From 049b905d86595bcf8a223e8277a546b1bc0e63a7 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Thu, 4 Aug 2016 14:41:40 -0700 Subject: [PATCH 01/63] Replace qof_object_foo_backend with c++ native containers. Since C++ provides find and for_each on native containers there's no need for a hand-rolled version in libqof. --- src/backend/dbi/gnc-backend-dbi.cpp | 19 +- .../dbi/test/test-backend-dbi-basic.cpp | 11 +- src/backend/sql/gnc-account-sql.cpp | 2 +- src/backend/sql/gnc-backend-sql.cpp | 256 ++++++++++-------- src/backend/sql/gnc-backend-sql.h | 24 +- src/backend/sql/gnc-bill-term-sql.cpp | 3 +- src/backend/sql/gnc-book-sql.cpp | 2 +- src/backend/sql/gnc-budget-sql.cpp | 3 +- src/backend/sql/gnc-commodity-sql.cpp | 4 +- src/backend/sql/gnc-customer-sql.cpp | 2 +- src/backend/sql/gnc-employee-sql.cpp | 2 +- src/backend/sql/gnc-entry-sql.cpp | 2 +- src/backend/sql/gnc-invoice-sql.cpp | 3 +- src/backend/sql/gnc-job-sql.cpp | 2 +- src/backend/sql/gnc-lots-sql.cpp | 3 +- src/backend/sql/gnc-order-sql.cpp | 3 +- src/backend/sql/gnc-price-sql.cpp | 2 +- src/backend/sql/gnc-recurrence-sql.cpp | 2 +- src/backend/sql/gnc-schedxaction-sql.cpp | 3 +- src/backend/sql/gnc-slots-sql.cpp | 7 +- src/backend/sql/gnc-tax-table-sql.cpp | 3 +- src/backend/sql/gnc-transaction-sql.cpp | 6 +- src/backend/sql/gnc-vendor-sql.cpp | 2 +- src/backend/sql/test/test-column-types.cpp | 5 +- src/backend/xml/gnc-address-xml-v2.cpp | 4 +- src/backend/xml/gnc-backend-xml.cpp | 2 +- src/backend/xml/gnc-bill-term-xml-v2.cpp | 4 +- src/backend/xml/gnc-customer-xml-v2.cpp | 4 +- src/backend/xml/gnc-employee-xml-v2.cpp | 4 +- src/backend/xml/gnc-entry-xml-v2.cpp | 4 +- src/backend/xml/gnc-invoice-xml-v2.cpp | 4 +- src/backend/xml/gnc-job-xml-v2.cpp | 4 +- src/backend/xml/gnc-order-xml-v2.cpp | 4 +- src/backend/xml/gnc-owner-xml-v2.cpp | 4 +- src/backend/xml/gnc-tax-table-xml-v2.cpp | 4 +- src/backend/xml/gnc-vendor-xml-v2.cpp | 4 +- src/backend/xml/io-gncxml-v2.cpp | 124 ++++----- src/backend/xml/io-gncxml-v2.h | 28 +- src/backend/xml/sixtp.h | 15 - src/libqof/qof/qofobject.cpp | 93 ------- src/libqof/qof/qofobject.h | 13 - src/libqof/qof/test/test-qofobject.c | 71 ----- 42 files changed, 293 insertions(+), 468 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 3e90e96da2..ac0553d3de 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -289,17 +289,16 @@ gnc_dbi_verify_conn (GncDbiSqlConnection* dbi_conn) /* ================================================================= */ static void -create_tables_cb (const gchar* type, gpointer data_p, gpointer be_p) +create_tables(const OBEEntry& entry, GncDbiBackend* be) { - GncSqlObjectBackend* pData = static_cast (data_p); - GncDbiBackend* be = static_cast (be_p); + std::string type; + GncSqlObjectBackendPtr obe = nullptr; + std::tie(type, obe) = entry; + g_return_if_fail(obe->version == GNC_SQL_BACKEND_VERSION); - g_return_if_fail (type != NULL && data_p != NULL && be_p != NULL); - g_return_if_fail (pData->version == GNC_SQL_BACKEND_VERSION); - - if (pData->create_tables != NULL) + if (obe->create_tables != nullptr) { - (pData->create_tables) (&be->sql_be); + (obe->create_tables)(&be->sql_be); } } @@ -1627,7 +1626,9 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) gnc_sql_init_version_info (&be->sql_be); // Call all object backends to create any required tables - qof_object_foreach_backend (GNC_SQL_BACKEND, create_tables_cb, be); + auto registry = gnc_sql_get_backend_registry(); + for (auto entry : registry) + create_tables(entry, be); } gnc_sql_load (&be->sql_be, book, loadType); diff --git a/src/backend/dbi/test/test-backend-dbi-basic.cpp b/src/backend/dbi/test/test-backend-dbi-basic.cpp index b0112d77c4..03e1bd7869 100644 --- a/src/backend/dbi/test/test-backend-dbi-basic.cpp +++ b/src/backend/dbi/test/test-backend-dbi-basic.cpp @@ -35,9 +35,7 @@ extern "C" #include #include -#include -#include - /* For cleaning up the database */ +/* For cleaning up the database */ #include #include /* For setup_business */ @@ -53,9 +51,14 @@ extern "C" #include } /* For test_conn_index_functions */ +#include "../gnc-backend-dbi-priv.h" +extern "C" +{ +#include +#include +} #include "test-dbi-stuff.h" #include "test-dbi-business-stuff.h" -#include "../gnc-backend-dbi-priv.h" #if LIBDBI_VERSION >= 900 #define HAVE_LIBDBI_R 1 diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index 4c5fe83f6e..164767be0f 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -464,7 +464,7 @@ gnc_sql_init_account_handler (void) NULL /* write */ }; - (void)qof_object_register_backend (GNC_ID_ACCOUNT, GNC_SQL_BACKEND, &be_data); + gnc_sql_register_backend(&be_data); gnc_sql_register_col_type_handler (CT_ACCOUNTREF, &account_guid_handler); } diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index a1ccfa9ed2..70798ba366 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -55,6 +55,9 @@ extern "C" #include "splint-defs.h" #endif } + +#include + #include "gnc-backend-sql.h" #include "gnc-account-sql.h" @@ -125,9 +128,26 @@ static QofLogModule log_module = G_LOG_DOMAIN; #define SQLITE_PROVIDER_NAME "SQLite" /* ================================================================= */ +static OBEVec backend_registry; +void +gnc_sql_register_backend(OBEEntry&& entry) +{ + backend_registry.emplace_back(entry); +} void -gnc_sql_init (GncSqlBackend* be) +gnc_sql_register_backend(GncSqlObjectBackendPtr obe) +{ + backend_registry.emplace_back(make_tuple(std::string{obe->type_name}, obe)); +} + +const OBEVec& +gnc_sql_get_backend_registry() +{ + return backend_registry; +} +void +gnc_sql_init(GncSqlBackend* be) { static gboolean initialized = FALSE; @@ -142,65 +162,54 @@ gnc_sql_init (GncSqlBackend* be) /* ================================================================= */ static void -create_tables_cb (const gchar* type, gpointer data_p, gpointer be_p) +create_tables(const OBEEntry& entry, GncSqlBackend* be) { - GncSqlObjectBackend* pData = static_cast (data_p); - GncSqlBackend* be = static_cast (be_p); + std::string type; + GncSqlObjectBackendPtr obe = nullptr; + std::tie(type, obe) = entry; + g_return_if_fail (obe->version == GNC_SQL_BACKEND_VERSION); - g_return_if_fail (type != NULL && data_p != NULL && be_p != NULL); - g_return_if_fail (pData->version == GNC_SQL_BACKEND_VERSION); - - if (pData->create_tables != NULL) + if (obe->create_tables != nullptr) { - update_progress (be); - (pData->create_tables) (be); + update_progress(be); + (obe->create_tables)(be); } } /* ================================================================= */ /* Main object load order */ -static const gchar* fixed_load_order[] = -{ GNC_ID_BOOK, GNC_ID_COMMODITY, GNC_ID_ACCOUNT, GNC_ID_LOT, NULL }; +static const LoadOrder fixed_load_order +{ GNC_ID_BOOK, GNC_ID_COMMODITY, GNC_ID_ACCOUNT, GNC_ID_LOT }; + /* Load order for objects from other modules */ -static const gchar** other_load_order = NULL; +static LoadOrder other_load_order; void -gnc_sql_set_load_order (const gchar** load_order) +gnc_sql_set_load_order(const LoadOrder& load_order) { other_load_order = load_order; } static void -initial_load_cb (const gchar* type, gpointer data_p, gpointer be_p) +initial_load(const OBEEntry& entry, GncSqlBackend* be) { - GncSqlObjectBackend* pData = static_cast (data_p); - GncSqlBackend* be = static_cast (be_p); - gint i; + std::string type; + GncSqlObjectBackendPtr obe = nullptr; + std::tie(type, obe) = entry; + g_return_if_fail(obe->version == GNC_SQL_BACKEND_VERSION); - g_return_if_fail (type != NULL && data_p != NULL && be_p != NULL); - g_return_if_fail (pData->version == GNC_SQL_BACKEND_VERSION); + /* Don't need to load anything if it has already been loaded with + * the fixed order. + */ + if (std::find(fixed_load_order.begin(), fixed_load_order.end(), + type) != fixed_load_order.end()) return; + if (std::find(other_load_order.begin(), other_load_order.end(), + type) != other_load_order.end()) return; - // Don't need to load anything if it has already been loaded with the fixed order - for (i = 0; fixed_load_order[i] != NULL; i++) - { - update_progress (be); - if (g_ascii_strcasecmp (type, fixed_load_order[i]) == 0) return; - } - if (other_load_order != NULL) - { - for (i = 0; other_load_order[i] != NULL; i++) - { - update_progress (be); - if (g_ascii_strcasecmp (type, other_load_order[i]) == 0) return; - } - } - - if (pData->initial_load != NULL) - { - (pData->initial_load) (be); - } + if (obe->initial_load != nullptr) + (obe->initial_load)(be); } void @@ -220,8 +229,6 @@ commit_commodity (gpointer data) void gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) { - GncSqlObjectBackend* pData; - gint i; Account* root; g_return_if_fail (be != NULL); @@ -237,39 +244,46 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) be->book = book; /* Load any initial stuff. Some of this needs to happen in a certain order */ - for (i = 0; fixed_load_order[i] != NULL; i++) + for (auto type : fixed_load_order) { - pData = static_cast (qof_object_lookup_backend ( - fixed_load_order[i], - GNC_SQL_BACKEND)); - if (pData->initial_load != NULL) + auto entry = std::find_if(backend_registry.begin(), + backend_registry.end(), + [type](const OBEEntry& entry){ + return type == std::get<0>(entry); + }); + auto obe = std::get<1>(*entry); + if (entry != backend_registry.end() && + obe->initial_load != nullptr) { - update_progress (be); - (pData->initial_load) (be); + update_progress(be); + (obe->initial_load)(be); } } - if (other_load_order != NULL) + for (auto type : other_load_order) { - for (i = 0; other_load_order[i] != NULL; i++) + auto entry = std::find_if(backend_registry.begin(), + backend_registry.end(), + [type](const OBEEntry& entry){ + return type == std::get<0>(entry); + }); + auto obe = std::get<1>(*entry); + if (entry != backend_registry.end() && + obe->initial_load != nullptr) { - pData = - static_cast (qof_object_lookup_backend ( - other_load_order[i], - GNC_SQL_BACKEND)); - if (pData->initial_load != NULL) - { - update_progress (be); - (pData->initial_load) (be); - } + update_progress(be); + (obe->initial_load)(be); } } - root = gnc_book_get_root_account (book); - gnc_account_foreach_descendant (root, (AccountCb)xaccAccountBeginEdit, NULL); + root = gnc_book_get_root_account( book ); + gnc_account_foreach_descendant(root, (AccountCb)xaccAccountBeginEdit, + nullptr); - qof_object_foreach_backend (GNC_SQL_BACKEND, initial_load_cb, be); + for (auto entry : backend_registry) + initial_load(entry, be); - gnc_account_foreach_descendant (root, (AccountCb)xaccAccountCommitEdit, NULL); + gnc_account_foreach_descendant(root, (AccountCb)xaccAccountCommitEdit, + nullptr); } else if (loadType == LOAD_TYPE_LOAD_ALL) { @@ -414,18 +428,17 @@ write_schedXactions (GncSqlBackend* be) } static void -write_cb (const gchar* type, gpointer data_p, gpointer be_p) +write(const OBEEntry& entry, GncSqlBackend* be) { - GncSqlObjectBackend* pData = static_cast (data_p); - GncSqlBackend* be = static_cast (be_p); + std::string type; + GncSqlObjectBackendPtr obe = nullptr; + std::tie(type, obe) = entry; + g_return_if_fail (obe->version == GNC_SQL_BACKEND_VERSION); - g_return_if_fail (type != NULL && data_p != NULL && be_p != NULL); - g_return_if_fail (pData->version == GNC_SQL_BACKEND_VERSION); - - if (pData->write != NULL) + if (obe->write != nullptr) { - (void) (pData->write) (be); - update_progress (be); + (void)(obe->write)(be); + update_progress(be); } } @@ -457,7 +470,8 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) /* Create new tables */ be->is_pristine_db = TRUE; - qof_object_foreach_backend (GNC_SQL_BACKEND, create_tables_cb, be); + for(auto entry : backend_registry) + create_tables(entry, be); /* Save all contents */ be->book = book; @@ -493,7 +507,8 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) } if (is_ok) { - qof_object_foreach_backend (GNC_SQL_BACKEND, write_cb, be); + for (auto entry : backend_registry) + write(entry, be); } if (is_ok) { @@ -542,21 +557,22 @@ gnc_sql_rollback_edit (GncSqlBackend* be, QofInstance* inst) } static void -commit_cb (const gchar* type, gpointer data_p, gpointer be_data_p) +commit(const OBEEntry& entry, sql_backend* be_data) { - GncSqlObjectBackend* pData = static_cast (data_p); - sql_backend* be_data = static_cast (be_data_p); + std::string type; + GncSqlObjectBackendPtr obe= nullptr; + std::tie(type, obe) = entry; + g_return_if_fail (obe->version == GNC_SQL_BACKEND_VERSION); - g_return_if_fail (type != NULL && pData != NULL && be_data != NULL); - g_return_if_fail (pData->version == GNC_SQL_BACKEND_VERSION); - - /* If this has already been handled, or is not the correct handler, return */ - if (strcmp (pData->type_name, be_data->inst->e_type) != 0) return; + /* If this has already been handled, or is not the correct + * handler, return + */ + if (type != std::string{be_data->inst->e_type}) return; if (be_data->is_known) return; - if (pData->commit != NULL) + if (obe->commit != nullptr) { - be_data->is_ok = (pData->commit) (be_data->be, be_data->inst); + be_data->is_ok = (obe->commit)(be_data->be, be_data->inst); be_data->is_known = TRUE; } } @@ -625,7 +641,8 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) be_data.inst = inst; be_data.is_ok = TRUE; - qof_object_foreach_backend (GNC_SQL_BACKEND, commit_cb, &be_data); + for (auto entry : backend_registry) + commit(entry, &be_data); if (!be_data.is_known) { @@ -809,23 +826,22 @@ handle_and_term (QofQueryTerm* pTerm, GString* sql) } static void -compile_query_cb (const gchar* type, gpointer data_p, gpointer be_data_p) +compile_query(const OBEEntry& entry, sql_backend* be_data) { - GncSqlObjectBackend* pData = static_cast (data_p); - sql_backend* be_data = static_cast (be_data_p); - - g_return_if_fail (type != NULL && pData != NULL && be_data != NULL); - g_return_if_fail (pData->version == GNC_SQL_BACKEND_VERSION); + std::string type; + GncSqlObjectBackendPtr obe = nullptr; + std::tie(type, obe) = entry; + g_return_if_fail (obe->version == GNC_SQL_BACKEND_VERSION); // Is this the right item? - if (strcmp (type, be_data->pQueryInfo->searchObj) != 0) return; + if (type != std::string{be_data->pQueryInfo->searchObj}) return; if (be_data->is_ok) return; - if (pData->compile_query != NULL) + if (obe->compile_query != nullptr) { - be_data->pQueryInfo->pCompiledQuery = (pData->compile_query) ( - be_data->be, - be_data->pQuery); + be_data->pQueryInfo->pCompiledQuery = (obe->compile_query)( + be_data->be, + be_data->pQuery); be_data->is_ok = TRUE; } } @@ -860,7 +876,8 @@ gnc_sql_compile_query (QofBackend* pBEnd, QofQuery* pQuery) be_data.pQuery = pQuery; be_data.pQueryInfo = pQueryInfo; - qof_object_foreach_backend (GNC_SQL_BACKEND, compile_query_cb, &be_data); + for (auto entry : backend_registry) + compile_query(entry, &be_data); if (be_data.is_ok) { LEAVE (""); @@ -925,19 +942,18 @@ gnc_sql_compile_query_to_sql (GncSqlBackend* be, QofQuery* query) } static void -free_query_cb (const gchar* type, gpointer data_p, gpointer be_data_p) +free_query(const OBEEntry& entry, sql_backend* be_data) { - GncSqlObjectBackend* pData = static_cast (data_p); - sql_backend* be_data = static_cast (be_data_p); - - g_return_if_fail (type != NULL && pData != NULL && be_data != NULL); - g_return_if_fail (pData->version == GNC_SQL_BACKEND_VERSION); + std::string type; + GncSqlObjectBackendPtr obe= nullptr; + std::tie(type, obe) = entry; + g_return_if_fail (obe->version == GNC_SQL_BACKEND_VERSION); if (be_data->is_ok) return; - if (strcmp (type, be_data->pQueryInfo->searchObj) != 0) return; + if (type != std::string{be_data->pQueryInfo->searchObj}) return; - if (pData->free_query != NULL) + if (obe->free_query != nullptr) { - (pData->free_query) (be_data->be, be_data->pCompiledQuery); + (obe->free_query)(be_data->be, be_data->pCompiledQuery); be_data->is_ok = TRUE; } } @@ -960,7 +976,8 @@ gnc_sql_free_query (QofBackend* pBEnd, gpointer pQuery) be_data.pCompiledQuery = pQuery; be_data.pQueryInfo = pQueryInfo; - qof_object_foreach_backend (GNC_SQL_BACKEND, free_query_cb, &be_data); + for (auto entry : backend_registry) + free_query(entry, &be_data); if (be_data.is_ok) { LEAVE (""); @@ -978,21 +995,20 @@ gnc_sql_free_query (QofBackend* pBEnd, gpointer pQuery) } static void -run_query_cb (const gchar* type, gpointer data_p, gpointer be_data_p) +run_query(const OBEEntry& entry, sql_backend* be_data) { - GncSqlObjectBackend* pData = static_cast (data_p); - sql_backend* be_data = static_cast (be_data_p); - - g_return_if_fail (type != NULL && pData != NULL && be_data != NULL); - g_return_if_fail (pData->version == GNC_SQL_BACKEND_VERSION); + std::string type; + GncSqlObjectBackendPtr obe = nullptr; + std::tie(type, obe) = entry; + g_return_if_fail (obe->version == GNC_SQL_BACKEND_VERSION); if (be_data->is_ok) return; // Is this the right item? - if (strcmp (type, be_data->pQueryInfo->searchObj) != 0) return; + if (type != std::string{be_data->pQueryInfo->searchObj}) return; - if (pData->run_query != NULL) + if (obe->run_query != nullptr) { - (pData->run_query) (be_data->be, be_data->pCompiledQuery); + (obe->run_query)(be_data->be, be_data->pCompiledQuery); be_data->is_ok = TRUE; } } @@ -1020,8 +1036,8 @@ gnc_sql_run_query (QofBackend* pBEnd, gpointer pQuery) be_data.be = be; be_data.pCompiledQuery = pQueryInfo->pCompiledQuery; be_data.pQueryInfo = pQueryInfo; - - qof_object_foreach_backend (GNC_SQL_BACKEND, run_query_cb, &be_data); + for (auto entry : backend_registry) + run_query(entry, &be_data); be->loading = FALSE; be->in_query = FALSE; qof_event_resume (); @@ -1040,8 +1056,8 @@ gnc_sql_run_query (QofBackend* pBEnd, gpointer pQuery) /* ================================================================= */ /* Order in which business objects need to be loaded */ -static const gchar* business_fixed_load_order[] = -{ GNC_ID_BILLTERM, GNC_ID_TAXTABLE, GNC_ID_INVOICE, NULL }; +static const LoadOrder business_fixed_load_order = +{ GNC_ID_BILLTERM, GNC_ID_TAXTABLE, GNC_ID_INVOICE }; static void business_core_sql_init (void) diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index e4a2be835f..ef851203cc 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -1,3 +1,4 @@ + /******************************************************************** * gnc-backend-sql.h: load and save data to SQL * * * @@ -44,6 +45,13 @@ extern "C" #include "qofbackend-p.h" #include } + +#include +#include +#include +#include + +using LoadOrder = std::vector; typedef struct GncSqlConnection GncSqlConnection; /** @@ -247,7 +255,7 @@ struct GncSqlResult * @struct GncSqlObjectBackend * * Struct used to handle a specific engine object type for an SQL backend. - * This handler should be registered with qof_object_register_backend(). + * This handler should be registered with gnc_sql_register_backend(). * * commit() - commit an object to the db * initial_load() - load stuff when new db opened @@ -259,8 +267,8 @@ struct GncSqlResult */ typedef struct { - int version; /**< Backend version number */ - const gchar* type_name; /**< Engine object type name */ + int version; /**< Backend version number */ + const std::string type_name; /**< Engine object type name */ /** Commit an instance of this object to the database * @return TRUE if successful, FALSE if error */ @@ -281,7 +289,13 @@ typedef struct gboolean (*write) (GncSqlBackend* be); } GncSqlObjectBackend; #define GNC_SQL_BACKEND "gnc:sql:1" -#define GNC_SQL_BACKEND_VERSION 1 +#define GNC_SQL_BACKEND_VERSION 1 +using GncSqlObjectBackendPtr = GncSqlObjectBackend*; +using OBEEntry = std::tuple; +using OBEVec = std::vector; +void gnc_sql_register_backend(OBEEntry&&); +void gnc_sql_register_backend(GncSqlObjectBackendPtr); +const OBEVec& gnc_sql_get_backend_registry(); /** * Basic column type @@ -762,7 +776,7 @@ gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, * * @param load_order NULL-terminated array of object type ID strings */ -void gnc_sql_set_load_order (const gchar** load_order); +void gnc_sql_set_load_order(LoadOrder&& load_order); void _retrieve_guid_ (gpointer pObject, gpointer pValue); diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index ce7462bad3..6e7c7f2317 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -411,8 +411,7 @@ gnc_billterm_sql_initialize (void) write_billterms /* write */ }; - qof_object_register_backend (GNC_ID_BILLTERM, GNC_SQL_BACKEND, &be_data); - + gnc_sql_register_backend(&be_data); gnc_sql_register_col_type_handler (CT_BILLTERMREF, &billterm_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-book-sql.cpp b/src/backend/sql/gnc-book-sql.cpp index 9c47987bc6..d3beba9bb3 100644 --- a/src/backend/sql/gnc-book-sql.cpp +++ b/src/backend/sql/gnc-book-sql.cpp @@ -245,6 +245,6 @@ gnc_sql_init_book_handler (void) NULL /* write */ }; - (void)qof_object_register_backend (GNC_ID_BOOK, GNC_SQL_BACKEND, &be_data); + gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index da50067241..40a994a6a6 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -545,8 +545,7 @@ gnc_sql_init_budget_handler (void) write_budgets /* write */ }; - (void)qof_object_register_backend (GNC_ID_BUDGET, GNC_SQL_BACKEND, &be_data); - + gnc_sql_register_backend(&be_data); gnc_sql_register_col_type_handler (CT_BUDGETREF, &budget_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index cb757fb659..2ea452a1ae 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -336,9 +336,7 @@ gnc_sql_init_commodity_handler (void) NULL /* write */ }; - (void)qof_object_register_backend (GNC_ID_COMMODITY, GNC_SQL_BACKEND, - &be_data); - + gnc_sql_register_backend(&be_data); gnc_sql_register_col_type_handler (CT_COMMODITYREF, &commodity_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index 05ff4bfbb7..ee9b27c935 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -248,6 +248,6 @@ gnc_customer_sql_initialize (void) write_customers /* write */ }; - qof_object_register_backend (GNC_ID_CUSTOMER, GNC_SQL_BACKEND, &be_data); + gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index ce282398dd..1bc95481a7 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -275,6 +275,6 @@ gnc_employee_sql_initialize (void) write_employees /* write */ }; - qof_object_register_backend (GNC_ID_EMPLOYEE, GNC_SQL_BACKEND, &be_data); + gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index 88a43d8e31..d947694255 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -295,6 +295,6 @@ gnc_entry_sql_initialize (void) write_entries /* write */ }; - qof_object_register_backend (GNC_ID_ENTRY, GNC_SQL_BACKEND, &be_data); + gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index cbcab3e596..884faba1b0 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -345,8 +345,7 @@ gnc_invoice_sql_initialize (void) write_invoices /* write */ }; - qof_object_register_backend (GNC_ID_INVOICE, GNC_SQL_BACKEND, &be_data); - + gnc_sql_register_backend(&be_data); gnc_sql_register_col_type_handler (CT_INVOICEREF, &invoice_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index 1a42eb5bfe..79ec2fcccc 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -217,6 +217,6 @@ gnc_job_sql_initialize (void) write_jobs /* write */ }; - qof_object_register_backend (GNC_ID_JOB, GNC_SQL_BACKEND, &be_data); + gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index e8005ba7a4..5714c5ba99 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -276,8 +276,7 @@ gnc_sql_init_lot_handler (void) write_lots /* save all */ }; - (void)qof_object_register_backend (GNC_ID_LOT, GNC_SQL_BACKEND, &be_data); - + gnc_sql_register_backend(&be_data); gnc_sql_register_col_type_handler (CT_LOTREF, &lot_guid_handler); } diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index 77a1cb1afb..f0f0a9c995 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -260,8 +260,7 @@ gnc_order_sql_initialize (void) write_orders /* write */ }; - qof_object_register_backend (GNC_ID_ORDER, GNC_SQL_BACKEND, &be_data); - + gnc_sql_register_backend(&be_data); gnc_sql_register_col_type_handler (CT_ORDERREF, &order_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-price-sql.cpp b/src/backend/sql/gnc-price-sql.cpp index c0611200a1..0bd549a220 100644 --- a/src/backend/sql/gnc-price-sql.cpp +++ b/src/backend/sql/gnc-price-sql.cpp @@ -242,7 +242,7 @@ gnc_sql_init_price_handler (void) write_prices /* write */ }; - (void)qof_object_register_backend (GNC_ID_PRICE, GNC_SQL_BACKEND, &be_data); + gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index 17e60be7aa..ca6dbf6ea6 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -459,6 +459,6 @@ gnc_sql_init_recurrence_handler (void) NULL /* write */ }; - (void)qof_object_register_backend (TABLE_NAME, GNC_SQL_BACKEND, &be_data); + gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index 9cce493707..c2cec7b58c 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -233,7 +233,6 @@ gnc_sql_init_schedxaction_handler (void) NULL /* write */ }; - (void)qof_object_register_backend (GNC_ID_SCHEDXACTION, GNC_SQL_BACKEND, - &be_data); + gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index 5feafe231c..d9bc89fb68 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -1100,6 +1100,10 @@ gnc_sql_init_slots_handler (void) static GncSqlObjectBackend be_data = { GNC_SQL_BACKEND_VERSION, +// This was GNC_ID_ACCOUNT. If somethine blows up, change it back, +// make the registry store a std::tuple, and check the first string against types +// in the functions that are called on each backend. GNC_ID_ACCOUNT, NULL, /* commit - cannot occur */ NULL, /* initial_load - cannot occur */ @@ -1110,6 +1114,7 @@ gnc_sql_init_slots_handler (void) NULL /* write */ }; - (void)qof_object_register_backend (TABLE_NAME, GNC_SQL_BACKEND, &be_data); + gnc_sql_register_backend(std::make_tuple(std::string{TABLE_NAME}, + &be_data)); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index 8154edcab7..c82ec119f6 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -569,8 +569,7 @@ gnc_taxtable_sql_initialize (void) write_taxtables /* write */ }; - qof_object_register_backend (GNC_ID_TAXTABLE, GNC_SQL_BACKEND, &be_data); - + gnc_sql_register_backend(&be_data); gnc_sql_register_col_type_handler (CT_TAXTABLEREF, &taxtable_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index 5d6f6d78e8..218fca694b 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -1540,10 +1540,8 @@ gnc_sql_init_transaction_handler (void) NULL /* write */ }; - (void)qof_object_register_backend (GNC_ID_TRANS, GNC_SQL_BACKEND, &be_data_tx); - (void)qof_object_register_backend (GNC_ID_SPLIT, GNC_SQL_BACKEND, - &be_data_split); - + gnc_sql_register_backend(&be_data_tx); + gnc_sql_register_backend(&be_data_split); gnc_sql_register_col_type_handler (CT_TXREF, &tx_guid_handler); } diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index 70935ed5b5..6ca010ddb7 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -268,6 +268,6 @@ gnc_vendor_sql_initialize (void) write_vendors /* write */ }; - qof_object_register_backend (GNC_ID_VENDOR, GNC_SQL_BACKEND, &be_data); + gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/test/test-column-types.cpp b/src/backend/sql/test/test-column-types.cpp index 0189001075..eb5ed96ce3 100644 --- a/src/backend/sql/test/test-column-types.cpp +++ b/src/backend/sql/test/test-column-types.cpp @@ -27,10 +27,13 @@ extern "C" { #include "config.h" #include "qof.h" +} +#include "gnc-backend-sql.h" +extern "C" +{ #include "cashobjects.h" #include "test-stuff.h" } -#include "gnc-backend-sql.h" int main (int argc, char** argv) { diff --git a/src/backend/xml/gnc-address-xml-v2.cpp b/src/backend/xml/gnc-address-xml-v2.cpp index 90dcf6902a..89dc77b190 100644 --- a/src/backend/xml/gnc-address-xml-v2.cpp +++ b/src/backend/xml/gnc-address-xml-v2.cpp @@ -238,7 +238,5 @@ gnc_address_xml_initialize (void) address_ns, }; - qof_object_register_backend ("gnc:Address", - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend (be_data); } diff --git a/src/backend/xml/gnc-backend-xml.cpp b/src/backend/xml/gnc-backend-xml.cpp index e9ebb815d2..3fc61e149d 100644 --- a/src/backend/xml/gnc-backend-xml.cpp +++ b/src/backend/xml/gnc-backend-xml.cpp @@ -77,7 +77,6 @@ extern "C" #include "gnc-engine.h" #include "gnc-uri-utils.h" -#include "io-gncxml-v2.h" #include "gnc-prefs.h" #ifndef HAVE_STRPTIME @@ -89,6 +88,7 @@ extern "C" #include "gnc-backend-xml.h" #include #include "gnc-xml-helper.h" +#include "io-gncxml-v2.h" #include "io-gncxml.h" #include "gnc-address-xml-v2.h" diff --git a/src/backend/xml/gnc-bill-term-xml-v2.cpp b/src/backend/xml/gnc-bill-term-xml-v2.cpp index 5bee3cd3b6..bdb6339852 100644 --- a/src/backend/xml/gnc-bill-term-xml-v2.cpp +++ b/src/backend/xml/gnc-bill-term-xml-v2.cpp @@ -774,9 +774,7 @@ gnc_billterm_xml_initialize (void) billterm_ns, }; - qof_object_register_backend (_GNC_MOD_NAME, - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend(be_data); } GncBillTerm* diff --git a/src/backend/xml/gnc-customer-xml-v2.cpp b/src/backend/xml/gnc-customer-xml-v2.cpp index 74cc13e099..80bed74eab 100644 --- a/src/backend/xml/gnc-customer-xml-v2.cpp +++ b/src/backend/xml/gnc-customer-xml-v2.cpp @@ -538,7 +538,5 @@ gnc_customer_xml_initialize (void) customer_ns, }; - qof_object_register_backend (_GNC_MOD_NAME, - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend (be_data); } diff --git a/src/backend/xml/gnc-employee-xml-v2.cpp b/src/backend/xml/gnc-employee-xml-v2.cpp index d8f8be22f3..a365a204e4 100644 --- a/src/backend/xml/gnc-employee-xml-v2.cpp +++ b/src/backend/xml/gnc-employee-xml-v2.cpp @@ -460,7 +460,5 @@ gnc_employee_xml_initialize (void) employee_ns, }; - qof_object_register_backend (_GNC_MOD_NAME, - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend (be_data); } diff --git a/src/backend/xml/gnc-entry-xml-v2.cpp b/src/backend/xml/gnc-entry-xml-v2.cpp index 44662014f0..750de6c4f0 100644 --- a/src/backend/xml/gnc-entry-xml-v2.cpp +++ b/src/backend/xml/gnc-entry-xml-v2.cpp @@ -863,7 +863,5 @@ gnc_entry_xml_initialize (void) entry_ns, }; - qof_object_register_backend (_GNC_MOD_NAME, - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend (be_data); } diff --git a/src/backend/xml/gnc-invoice-xml-v2.cpp b/src/backend/xml/gnc-invoice-xml-v2.cpp index 4cf3fbd93d..5aecaf56bc 100644 --- a/src/backend/xml/gnc-invoice-xml-v2.cpp +++ b/src/backend/xml/gnc-invoice-xml-v2.cpp @@ -571,7 +571,5 @@ gnc_invoice_xml_initialize (void) invoice_ns, }; - qof_object_register_backend (_GNC_MOD_NAME, - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend(be_data); } diff --git a/src/backend/xml/gnc-job-xml-v2.cpp b/src/backend/xml/gnc-job-xml-v2.cpp index 923937652f..95243aad55 100644 --- a/src/backend/xml/gnc-job-xml-v2.cpp +++ b/src/backend/xml/gnc-job-xml-v2.cpp @@ -359,7 +359,5 @@ gnc_job_xml_initialize (void) job_ns, }; - qof_object_register_backend (_GNC_MOD_NAME, - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend(be_data); } diff --git a/src/backend/xml/gnc-order-xml-v2.cpp b/src/backend/xml/gnc-order-xml-v2.cpp index 12512c78cc..c56349ca71 100644 --- a/src/backend/xml/gnc-order-xml-v2.cpp +++ b/src/backend/xml/gnc-order-xml-v2.cpp @@ -401,7 +401,5 @@ gnc_order_xml_initialize (void) order_ns, }; - qof_object_register_backend (_GNC_MOD_NAME, - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend(be_data); } diff --git a/src/backend/xml/gnc-owner-xml-v2.cpp b/src/backend/xml/gnc-owner-xml-v2.cpp index b17923a196..46a48e45bf 100644 --- a/src/backend/xml/gnc-owner-xml-v2.cpp +++ b/src/backend/xml/gnc-owner-xml-v2.cpp @@ -239,7 +239,5 @@ gnc_owner_xml_initialize (void) owner_ns, }; - qof_object_register_backend ("gnc:Owner", - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend (be_data); } diff --git a/src/backend/xml/gnc-tax-table-xml-v2.cpp b/src/backend/xml/gnc-tax-table-xml-v2.cpp index 183fe3aee9..b6a7f7fd46 100644 --- a/src/backend/xml/gnc-tax-table-xml-v2.cpp +++ b/src/backend/xml/gnc-tax-table-xml-v2.cpp @@ -719,7 +719,5 @@ gnc_taxtable_xml_initialize (void) taxtable_ns, }; - qof_object_register_backend (_GNC_MOD_NAME, - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend(be_data); } diff --git a/src/backend/xml/gnc-vendor-xml-v2.cpp b/src/backend/xml/gnc-vendor-xml-v2.cpp index f8975025cb..fd96c0234f 100644 --- a/src/backend/xml/gnc-vendor-xml-v2.cpp +++ b/src/backend/xml/gnc-vendor-xml-v2.cpp @@ -480,7 +480,5 @@ gnc_vendor_xml_initialize (void) vendor_ns, }; - qof_object_register_backend (_GNC_MOD_NAME, - GNC_FILE_BACKEND, - &be_data); + gnc_xml_register_backend(be_data); } diff --git a/src/backend/xml/io-gncxml-v2.cpp b/src/backend/xml/io-gncxml-v2.cpp index 994b24ada1..614c4fd5c9 100644 --- a/src/backend/xml/io-gncxml-v2.cpp +++ b/src/backend/xml/io-gncxml-v2.cpp @@ -66,7 +66,6 @@ extern "C" #endif } -#include "sixtp.h" #include "sixtp-parsers.h" #include "sixtp-utils.h" #include "gnc-xml.h" @@ -109,6 +108,13 @@ struct file_backend QofBook* book; }; +static std::vector backend_registry; +void +gnc_xml_register_backend(GncXmlDataType_t& xmlbe) +{ + backend_registry.push_back(xmlbe); +} + #define GNC_V2_STRING "gnc-v2" /* non-static because they are used in sixtp.c */ const gchar* gnc_v2_xml_version_string = GNC_V2_STRING; @@ -356,18 +362,14 @@ add_pricedb_local (sixtp_gdv2* data, GNCPriceDB* db) } static void -do_counter_cb (const char* type, gpointer data_p, gpointer be_data_p) +counter (const GncXmlDataType_t& data, file_backend* be_data) { - GncXmlDataType_t* data = static_cast (data_p); - struct file_backend* be_data = static_cast (be_data_p); - - g_return_if_fail (type && data && be_data); - g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS); + g_return_if_fail (data.version == GNC_FILE_BACKEND_VERS); if (be_data->ok == TRUE) return; - if (!g_strcmp0 (be_data->tag, data->type_name)) + if (!g_strcmp0 (be_data->tag, data.type_name)) be_data->ok = TRUE; /* XXX: should we do anything with this counter? */ @@ -443,8 +445,8 @@ gnc_counter_end_handler (gpointer data_for_children, be_data.ok = FALSE; be_data.tag = type; - - qof_object_foreach_backend (GNC_FILE_BACKEND, do_counter_cb, &be_data); + for(auto data : backend_registry) + counter(data, &be_data); if (be_data.ok == FALSE) { @@ -544,21 +546,17 @@ static const char* TEMPLATE_TRANSACTION_TAG = "gnc:template-transactions"; static const char* BUDGET_TAG = "gnc:budget"; static void -add_item_cb (const char* type, gpointer data_p, gpointer be_data_p) +add_item (const GncXmlDataType_t& data, struct file_backend* be_data) { - GncXmlDataType_t* data = static_cast (data_p); - struct file_backend* be_data = static_cast (be_data_p); - - g_return_if_fail (type && data && be_data); - g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS); + g_return_if_fail (data.version == GNC_FILE_BACKEND_VERS); if (be_data->ok) return; - if (!g_strcmp0 (be_data->tag, data->type_name)) + if (!g_strcmp0 (be_data->tag, data.type_name)) { - if (data->add_item) - (data->add_item) (be_data->gd, be_data->data); + if (data.add_item) + (data.add_item)(be_data->gd, be_data->data); be_data->ok = TRUE; } @@ -606,7 +604,8 @@ book_callback (const char* tag, gpointer globaldata, gpointer data) be_data.gd = gd; be_data.data = data; - qof_object_foreach_backend (GNC_FILE_BACKEND, add_item_cb, &be_data); + for (auto data : backend_registry) + add_item(data, &be_data); if (be_data.ok == FALSE) { @@ -635,36 +634,28 @@ generic_callback (const char* tag, gpointer globaldata, gpointer data) } static void -add_parser_cb (const char* type, gpointer data_p, gpointer be_data_p) +add_parser(const GncXmlDataType_t& data, struct file_backend* be_data) { - GncXmlDataType_t* data = static_cast (data_p); - struct file_backend* be_data = static_cast (be_data_p); - - g_return_if_fail (type && data && be_data); - g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS); + g_return_if_fail (data.version == GNC_FILE_BACKEND_VERS); if (be_data->ok == FALSE) return; - if (data->create_parser) - if (!sixtp_add_some_sub_parsers ( - be_data->parser, TRUE, - data->type_name, (data->create_parser) (), - NULL, NULL)) + if (data.create_parser) + if (!sixtp_add_some_sub_parsers( + be_data->parser, TRUE, + data.type_name, (data.create_parser)(), + NULL, NULL)) be_data->ok = FALSE; } static void -scrub_cb (const char* type, gpointer data_p, gpointer be_data_p) +scrub (const GncXmlDataType_t& data, struct file_backend* be_data) { - GncXmlDataType_t* data = static_cast (data_p); - struct file_backend* be_data = static_cast (be_data_p); + g_return_if_fail (data.version == GNC_FILE_BACKEND_VERS); - g_return_if_fail (type && data && be_data); - g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS); - - if (data->scrub) - (data->scrub) (be_data->book); + if (data.scrub) + (data.scrub)(be_data->book); } static sixtp_gdv2* @@ -773,7 +764,8 @@ qof_session_load_from_xml_file_v2_full ( be_data.ok = TRUE; be_data.parser = book_parser; - qof_object_foreach_backend (GNC_FILE_BACKEND, add_parser_cb, &be_data); + for (auto data : backend_registry) + add_parser(data, &be_data); if (be_data.ok == FALSE) goto bail; @@ -841,7 +833,8 @@ qof_session_load_from_xml_file_v2_full ( /* Call individual scrub functions */ memset (&be_data, 0, sizeof (be_data)); be_data.book = book; - qof_object_foreach_backend (GNC_FILE_BACKEND, scrub_cb, &be_data); + for (auto data : backend_registry) + scrub(data, &be_data); /* fix price quote sources */ root = gnc_book_get_root_account (book); @@ -963,31 +956,23 @@ static gboolean write_schedXactions (FILE* out, QofBook* book, sixtp_gdv2* gd); static void write_budget (QofInstance* ent, gpointer data); static void -write_counts_cb (const char* type, gpointer data_p, gpointer be_data_p) +write_counts(const GncXmlDataType_t& data, struct file_backend* be_data) { - GncXmlDataType_t* data = static_cast (data_p); - struct file_backend* be_data = static_cast (be_data_p); + g_return_if_fail (data.version == GNC_FILE_BACKEND_VERS); - g_return_if_fail (type && data && be_data); - g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS); - - if (data->get_count) - write_counts (be_data->out, data->type_name, - (data->get_count) (be_data->book), + if (data.get_count) + write_counts (be_data->out, data.type_name, + (data.get_count) (be_data->book), NULL); } static void -write_data_cb (const char* type, gpointer data_p, gpointer be_data_p) +write_data(const GncXmlDataType_t& data, struct file_backend* be_data) { - GncXmlDataType_t* data = static_cast (data_p); - struct file_backend* be_data = static_cast (be_data_p); + g_return_if_fail (data.version == GNC_FILE_BACKEND_VERS); - g_return_if_fail (type && data && be_data); - g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS); - - if (data->write && !ferror (be_data->out)) - (data->write) (be_data->out, be_data->book); + if (data.write && !ferror(be_data->out)) + (data.write)(be_data->out, be_data->book); } static gboolean @@ -1048,7 +1033,8 @@ write_book (FILE* out, QofBook* book, sixtp_gdv2* gd) NULL)) return FALSE; - qof_object_foreach_backend (GNC_FILE_BACKEND, write_counts_cb, &be_data); + for (auto data : backend_registry) + write_counts(data, &be_data); if (ferror (out) || !write_commodities (out, book, gd) @@ -1065,8 +1051,9 @@ write_book (FILE* out, QofBook* book, sixtp_gdv2* gd) if (ferror (out)) return FALSE; - qof_object_foreach_backend (GNC_FILE_BACKEND, write_data_cb, &be_data); - if (ferror (out)) + for (auto data : backend_registry) + write_data(data, &be_data); + if (ferror(out)) return FALSE; if (fprintf (out, "\n", BOOK_TAG) < 0) @@ -1296,16 +1283,12 @@ gnc_xml2_write_namespace_decl (FILE* out, const char* name_space) } static void -do_write_namespace_cb (const char* type, gpointer data_p, gpointer file_p) +write_namespace (const GncXmlDataType_t& data, FILE* out) { - GncXmlDataType_t* data = static_cast (data_p); - FILE* out = static_cast (file_p); + g_return_if_fail (data.version == GNC_FILE_BACKEND_VERS); - g_return_if_fail (type && data && out); - g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS); - - if (data->ns && !ferror (out)) - (data->ns) (out); + if (data.ns && !ferror(out)) + (data.ns)(out); } static gboolean @@ -1333,7 +1316,8 @@ write_v2_header (FILE* out) return FALSE; /* now cope with the plugins */ - qof_object_foreach_backend (GNC_FILE_BACKEND, do_write_namespace_cb, out); + for (auto data : backend_registry) + write_namespace(data, out); if (ferror (out) || fprintf (out, ">\n") < 0) return FALSE; diff --git a/src/backend/xml/io-gncxml-v2.h b/src/backend/xml/io-gncxml-v2.h index 363e4c59aa..0457c8c857 100644 --- a/src/backend/xml/io-gncxml-v2.h +++ b/src/backend/xml/io-gncxml-v2.h @@ -37,8 +37,11 @@ extern "C" #include #include "gnc-engine.h" +#ifdef __cplusplus +} #include "gnc-backend-xml.h" - +#include "sixtp.h" +#include /** @@ -106,6 +109,13 @@ QofBookFileType gnc_is_xml_data_file_v2 (const gchar* name, */ gboolean gnc_xml2_write_namespace_decl (FILE* out, const char* name_space); +extern "C" +{ +#endif /* __cplusplus. The next two functions are used (only) by + * src/gnome-utils/assistant-xml-encoding.c and so need C linkage; + * they're also the only part of this file that the C compiler needs to + * see. + */ typedef struct { @@ -147,5 +157,19 @@ gboolean gnc_xml2_parse_with_subst ( FileBackend* fbe, QofBook* book, GHashTable* subst); #ifdef __cplusplus } -#endif +typedef struct +{ + int version; /* backend version number */ + const char * type_name; /* The XML tag for this type */ + + sixtp * (*create_parser) (void); + gboolean (*add_item)(sixtp_gdv2 *, gpointer obj); + int (*get_count) (QofBook *); + gboolean (*write) (FILE*, QofBook*); + void (*scrub) (QofBook *); + gboolean (*ns) (FILE*); +} GncXmlDataType_t; + +void gnc_xml_register_backend(GncXmlDataType_t&); +#endif /* __cplusplus */ #endif /* __IO_GNCXML_V2_H__ */ diff --git a/src/backend/xml/sixtp.h b/src/backend/xml/sixtp.h index aca886bd10..5aa7992357 100644 --- a/src/backend/xml/sixtp.h +++ b/src/backend/xml/sixtp.h @@ -199,21 +199,6 @@ typedef struct sixtp_sax_data sixtp* bad_xml_parser; } sixtp_sax_data; -typedef struct -{ - int version; /* backend version number */ - const char* type_name; /* The XML tag for this type */ - - sixtp* (*create_parser) (void); - gboolean (*add_item) (sixtp_gdv2*, gpointer obj); - int (*get_count) (QofBook*); - gboolean (*write) (FILE*, QofBook*); - void (*scrub) (QofBook*); - gboolean (*ns) (FILE*); -} GncXmlDataType_t; - - - gboolean is_child_result_from_node_named (sixtp_child_result* cr, const char* tag); void sixtp_child_free_data (sixtp_child_result* result); diff --git a/src/libqof/qof/qofobject.cpp b/src/libqof/qof/qofobject.cpp index e7062145ae..505a8b6734 100644 --- a/src/libqof/qof/qofobject.cpp +++ b/src/libqof/qof/qofobject.cpp @@ -37,7 +37,6 @@ static QofLogModule log_module = QOF_MOD_OBJECT; static gboolean object_is_initialized = FALSE; static GList *object_modules = NULL; static GList *book_list = NULL; -static GHashTable *backend_data = NULL; /* * These getters are used in tests to reach static vars from outside @@ -52,7 +51,6 @@ extern "C" gboolean get_object_is_initialized( void ); GList* get_object_modules( void ); GList* get_book_list( void ); -GHashTable* get_backend_data( void ); #ifdef __cplusplus } @@ -76,12 +74,6 @@ get_book_list( void ) return book_list; } -GHashTable* -get_backend_data( void ) -{ - return backend_data; -} - /*********/ gpointer @@ -306,7 +298,6 @@ static gboolean clear_table (gpointer key, gpointer value, gpointer user_data) void qof_object_initialize (void) { if (object_is_initialized) return; - backend_data = g_hash_table_new (g_str_hash, g_str_equal); object_is_initialized = TRUE; } @@ -314,10 +305,6 @@ void qof_object_shutdown (void) { g_return_if_fail (object_is_initialized == TRUE); - g_hash_table_foreach_remove (backend_data, clear_table, NULL); - g_hash_table_destroy (backend_data); - backend_data = NULL; - g_list_free (object_modules); object_modules = NULL; g_list_free (book_list); @@ -371,84 +358,4 @@ const QofObject * qof_object_lookup (QofIdTypeConst name) return NULL; } -gboolean qof_object_register_backend (QofIdTypeConst type_name, - const char *backend_name, - gpointer be_data) -{ - GHashTable *ht; - g_return_val_if_fail (object_is_initialized, FALSE); - - if (!type_name || *type_name == '\0' || - !backend_name || *backend_name == '\0' || - !be_data) - return FALSE; - - ht = static_cast(g_hash_table_lookup (backend_data, backend_name)); - - /* If it doesn't already exist, create a new table for this backend */ - if (!ht) - { - ht = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (backend_data, (char *)backend_name, ht); - } - - /* Now insert the data */ - g_hash_table_insert (ht, (char *)type_name, be_data); - - return TRUE; -} - -gpointer qof_object_lookup_backend (QofIdTypeConst type_name, - const char *backend_name) -{ - GHashTable *ht; - - if (!type_name || *type_name == '\0' || - !backend_name || *backend_name == '\0') - return NULL; - - ht = static_cast(g_hash_table_lookup (backend_data, (char *)backend_name)); - if (!ht) - return NULL; - - return g_hash_table_lookup (ht, (char *)type_name); -} - -struct foreach_data -{ - QofForeachBackendTypeCB cb; - gpointer user_data; -}; - -static void foreach_backend (gpointer key, gpointer be_item, gpointer arg) -{ - char *data_type = static_cast(key); - struct foreach_data *cb_data = static_cast(arg); - - g_return_if_fail (key && be_item && arg); - - /* Call the callback for this data type */ - (cb_data->cb) (data_type, be_item, cb_data->user_data); -} - -void qof_object_foreach_backend (const char *backend_name, - QofForeachBackendTypeCB cb, - gpointer user_data) -{ - GHashTable *ht; - struct foreach_data cb_data; - - if (!backend_name || *backend_name == '\0' || !cb) - return; - - ht = static_cast(g_hash_table_lookup (backend_data, (char *)backend_name)); - if (!ht) - return; - - cb_data.cb = cb; - cb_data.user_data = user_data; - - g_hash_table_foreach_sorted (ht, foreach_backend, &cb_data, (GCompareFunc)strcmp); -} - /* ========================= END OF FILE =================== */ diff --git a/src/libqof/qof/qofobject.h b/src/libqof/qof/qofobject.h index 60a3f5ce45..eb87213e14 100644 --- a/src/libqof/qof/qofobject.h +++ b/src/libqof/qof/qofobject.h @@ -171,19 +171,6 @@ void qof_object_foreach (QofIdTypeConst type_name, QofBook *book, void qof_object_foreach_sorted (QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data); -/** Register and lookup backend-specific data for this particular object */ -gboolean qof_object_register_backend (QofIdTypeConst type_name, - const char *backend_name, - gpointer be_data); - -/*@ dependent @*/ -gpointer qof_object_lookup_backend (QofIdTypeConst type_name, - const char *backend_name); - -void qof_object_foreach_backend (const char *backend_name, - QofForeachBackendTypeCB cb, - gpointer user_data); - #ifdef __cplusplus } #endif diff --git a/src/libqof/qof/test/test-qofobject.c b/src/libqof/qof/test/test-qofobject.c index 86c395ae03..1aabc136a2 100644 --- a/src/libqof/qof/test/test-qofobject.c +++ b/src/libqof/qof/test/test-qofobject.c @@ -93,7 +93,6 @@ extern "C" extern gboolean get_object_is_initialized( void ); extern GList* get_object_modules( void ); extern GList* get_book_list( void ); -extern GHashTable* get_backend_data( void ); #ifdef __cplusplus } @@ -229,36 +228,6 @@ test_qof_object_lookup( Fixture *fixture, gconstpointer pData ) g_assert( qof_object_lookup( "anytype" ) == NULL ); } -static struct -{ - gpointer data1; - gpointer data2; -} be_data; - -static void -test_qof_object_backend_register_lookup( Fixture *fixture, gconstpointer pData ) -{ - g_test_message( "Test register and lookup null checks" ); - g_assert( qof_object_register_backend( NULL, "test", &be_data ) == FALSE ); - g_assert( qof_object_register_backend( "", "test", &be_data ) == FALSE ); - g_assert( qof_object_register_backend( "test", NULL, &be_data ) == FALSE ); - g_assert( qof_object_register_backend( "test", "", &be_data ) == FALSE ); - g_assert( qof_object_register_backend( "test", "test", NULL ) == FALSE ); - g_assert( qof_object_lookup_backend( NULL, "test" ) == NULL ); - g_assert( qof_object_lookup_backend( "", "test" ) == NULL ); - g_assert( qof_object_lookup_backend( "test", NULL ) == NULL ); - g_assert( qof_object_lookup_backend( "test", "" ) == NULL ); - - g_test_message( "Test new backend and type insert" ); - g_assert( qof_object_lookup_backend( "type", "backend" ) == NULL ); - g_assert( qof_object_register_backend( "type", "backend", &be_data.data1 ) == TRUE ); - g_assert( qof_object_lookup_backend( "type", "backend" ) == &be_data.data1 ); - - g_test_message( "Test type insert into existing backend" ); - g_assert( qof_object_register_backend( "type2", "backend", &be_data.data2 ) == TRUE ); - g_assert( qof_object_lookup_backend( "type", "backend" ) == &be_data.data1 ); - g_assert( qof_object_lookup_backend( "type2", "backend" ) == &be_data.data2 ); -} static void test_qof_object_get_type_label( Fixture *fixture, gconstpointer pData ) @@ -732,50 +701,11 @@ test_qof_object_foreach_sorted( Fixture *fixture, gconstpointer pData ) g_list_free( foreach_for_sorted_struct.instances ); } -static struct -{ - QofIdTypeConst type; - gpointer backend_data; - gpointer user_data; - guint call_count; -} foreach_backend_struct; - -static void -mock_foreach_backend( QofIdTypeConst type, gpointer backend_data, gpointer user_data) -{ - g_assert( type ); - g_assert( backend_data ); - g_assert( user_data ); - g_assert_cmpstr( type, == , foreach_backend_struct.type ); - g_assert( backend_data == foreach_backend_struct.backend_data ); - g_assert( user_data == foreach_backend_struct.user_data ); - foreach_backend_struct.call_count++; -} - -static void -test_qof_object_foreach_backend( Fixture *fixture, gconstpointer pData ) -{ - gint backend_data; - gint user_data; - - g_assert_cmpint( g_hash_table_size( get_backend_data() ), == , 0 ); - qof_object_register_backend( "type1", "backend", (gpointer) &backend_data ); /* register backend */ - g_assert_cmpint( g_hash_table_size( get_backend_data() ), == , 1 ); - - foreach_backend_struct.call_count = 0; - foreach_backend_struct.backend_data = (gpointer) &backend_data; - foreach_backend_struct.user_data = (gpointer) &user_data; - foreach_backend_struct.type = "type1"; - qof_object_foreach_backend ( "backend", mock_foreach_backend, (gpointer) &user_data); - g_assert_cmpint( foreach_backend_struct.call_count, == , 1 ); -} - void test_suite_qofobject (void) { GNC_TEST_ADD( suitename, "qof object register", Fixture, NULL, setup, test_qof_object_register, teardown ); GNC_TEST_ADD( suitename, "qof object lookup", Fixture, NULL, setup, test_qof_object_lookup, teardown ); - GNC_TEST_ADD( suitename, "qof object register and lookup backend", Fixture, NULL, setup, test_qof_object_backend_register_lookup, teardown ); GNC_TEST_ADD( suitename, "qof object get type label", Fixture, NULL, setup, test_qof_object_get_type_label, teardown ); GNC_TEST_ADD( suitename, "qof object printable", Fixture, NULL, setup, test_qof_object_printable, teardown ); GNC_TEST_ADD( suitename, "qof object book begin", Fixture, NULL, setup, test_qof_object_book_begin, teardown ); @@ -787,5 +717,4 @@ test_suite_qofobject (void) GNC_TEST_ADD( suitename, "qof object foreach type", Fixture, NULL, setup, test_qof_object_foreach_type, teardown ); GNC_TEST_ADD( suitename, "qof object foreach", Fixture, NULL, setup, test_qof_object_foreach, teardown ); GNC_TEST_ADD( suitename, "qof object foreach sorted", Fixture, NULL, setup, test_qof_object_foreach_sorted, teardown ); - GNC_TEST_ADD( suitename, "qof object foreach backend", Fixture, NULL, setup, test_qof_object_foreach_backend, teardown ); } From 611f210a072e84954e26bb8eaa94f880203e5714 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 28 Feb 2016 12:18:49 -0800 Subject: [PATCH 02/63] Provide constructors for GncSqlColumnInfo, change variable names to m_ prefix. --- src/backend/dbi/gnc-backend-dbi.cpp | 102 +++++++++--------- src/backend/sql/gnc-address-sql.cpp | 12 +-- src/backend/sql/gnc-backend-sql.cpp | 72 +++---------- src/backend/sql/gnc-backend-sql.h | 48 ++++++--- src/backend/sql/gnc-owner-sql.cpp | 24 ++--- .../sql/test/utest-gnc-backend-sql.cpp | 10 -- 6 files changed, 111 insertions(+), 157 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index ac0553d3de..19c8957332 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -2717,8 +2717,7 @@ add_columns_ddl (GncSqlConnection* conn, } g_string_append (ddl, "ADD COLUMN "); dbi_conn->provider->append_col_def (ddl, info); - g_free (info->name); - g_free (info); + delete info; } return g_string_free (ddl, FALSE); @@ -2729,42 +2728,42 @@ append_sqlite3_col_def (GString* ddl, GncSqlColumnInfo* info) { const char* type_name = nullptr; - if (info->type == BCT_INT) + if (info->m_type == BCT_INT) { type_name = "integer"; } - else if (info->type == BCT_INT64) + else if (info->m_type == BCT_INT64) { type_name = "bigint"; } - else if (info->type == BCT_DOUBLE) + else if (info->m_type == BCT_DOUBLE) { type_name = "float8"; } - else if (info->type == BCT_STRING || info->type == BCT_DATE - || info->type == BCT_DATETIME) + else if (info->m_type == BCT_STRING || info->m_type == BCT_DATE + || info->m_type == BCT_DATETIME) { type_name = "text"; } else { - PERR ("Unknown column type: %d\n", info->type); + PERR ("Unknown column type: %d\n", info->m_type); type_name = ""; } - g_string_append_printf (ddl, "%s %s", info->name, type_name); - if (info->size != 0) + g_string_append_printf (ddl, "%s %s", info->m_name.c_str(), type_name); + if (info->m_size != 0) { - (void)g_string_append_printf (ddl, "(%d)", info->size); + (void)g_string_append_printf (ddl, "(%d)", info->m_size); } - if (info->is_primary_key) + if (info->m_primary_key) { (void)g_string_append (ddl, " PRIMARY KEY"); } - if (info->is_autoinc) + if (info->m_autoinc) { (void)g_string_append (ddl, " AUTOINCREMENT"); } - if (!info->null_allowed) + if (!info->m_null_allowed) { (void)g_string_append (ddl, " NOT NULL"); } @@ -2795,8 +2794,7 @@ conn_create_table_ddl_sqlite3 (GncSqlConnection* conn, (void)g_string_append (ddl, ", "); } append_sqlite3_col_def (ddl, info); - g_free (info->name); - g_free (info); + delete info; } (void)g_string_append (ddl, ")"); @@ -2808,55 +2806,56 @@ append_mysql_col_def (GString* ddl, GncSqlColumnInfo* info) { const char* type_name = nullptr; - if (info->type == BCT_INT) + if (info->m_type == BCT_INT) { type_name = "integer"; } - else if (info->type == BCT_INT64) + else if (info->m_type == BCT_INT64) { type_name = "bigint"; } - else if (info->type == BCT_DOUBLE) + else if (info->m_type == BCT_DOUBLE) { type_name = "double"; } - else if (info->type == BCT_STRING) + else if (info->m_type == BCT_STRING) { type_name = "varchar"; } - else if (info->type == BCT_DATE) + else if (info->m_type == BCT_DATE) { - info->size = 0; + info->m_size = 0; type_name = "date"; } - else if (info->type == BCT_DATETIME) + else if (info->m_type == BCT_DATETIME) { - info->size = 0; + info->m_size = 0; type_name = "TIMESTAMP NULL DEFAULT 0"; } else { - PERR ("Unknown column type: %d\n", info->type); + PERR ("Unknown column type: %d\n", info->m_type); type_name = ""; } - g_string_append_printf (ddl, "%s %s", info->name, type_name); - if (info->size != 0) + g_string_append_printf (ddl, "%s %s", info->m_name.c_str(), type_name); + if (info->m_size != 0) { - g_string_append_printf (ddl, "(%d)", info->size); + g_string_append_printf (ddl, "(%d)", info->m_size); } - if (info->is_unicode) + if (info->m_unicode) { (void)g_string_append (ddl, " CHARACTER SET utf8"); } - if (info->is_primary_key) + if (info->m_primary_key) { (void)g_string_append (ddl, " PRIMARY KEY"); } - if (info->is_autoinc) + if (info->m_autoinc) { (void)g_string_append (ddl, " AUTO_INCREMENT"); } - if (!info->null_allowed) + if (!info->m_null_allowed) + { (void)g_string_append (ddl, " NOT NULL"); } @@ -2886,8 +2885,7 @@ conn_create_table_ddl_mysql (GncSqlConnection* conn, const gchar* table_name, (void)g_string_append (ddl, ", "); } append_mysql_col_def (ddl, info); - g_free (info->name); - g_free (info); + delete info; } (void)g_string_append (ddl, ")"); @@ -2899,9 +2897,9 @@ append_pgsql_col_def (GString* ddl, GncSqlColumnInfo* info) { const char* type_name = nullptr; - if (info->type == BCT_INT) + if (info->m_type == BCT_INT) { - if (info->is_autoinc) + if (info->m_autoinc) { type_name = "serial"; } @@ -2910,43 +2908,44 @@ append_pgsql_col_def (GString* ddl, GncSqlColumnInfo* info) type_name = "integer"; } } - else if (info->type == BCT_INT64) + else if (info->m_type == BCT_INT64) { type_name = "int8"; } - else if (info->type == BCT_DOUBLE) + else if (info->m_type == BCT_DOUBLE) + { type_name = "double precision"; } - else if (info->type == BCT_STRING) + else if (info->m_type == BCT_STRING) { type_name = "varchar"; } - else if (info->type == BCT_DATE) + else if (info->m_type == BCT_DATE) { - info->size = 0; + info->m_size = 0; type_name = "date"; } - else if (info->type == BCT_DATETIME) + else if (info->m_type == BCT_DATETIME) { - info->size = 0; + info->m_size = 0; type_name = "timestamp without time zone"; } else { - PERR ("Unknown column type: %d\n", info->type); + PERR ("Unknown column type: %d\n", info->m_type); type_name = ""; } - g_string_append_printf (ddl, "%s %s", info->name, type_name); - if (info->size != 0) + g_string_append_printf (ddl, "%s %s", info->m_name.c_str(), type_name); + if (info->m_size != 0) { - g_string_append_printf (ddl, "(%d)", info->size); + g_string_append_printf (ddl, "(%d)", info->m_size); } - if (info->is_primary_key) + if (info->m_primary_key) { (void)g_string_append (ddl, " PRIMARY KEY"); } - if (!info->null_allowed) + if (!info->m_null_allowed) { (void)g_string_append (ddl, " NOT NULL"); } @@ -2977,9 +2976,8 @@ conn_create_table_ddl_pgsql (GncSqlConnection* conn, const gchar* table_name, (void)g_string_append (ddl, ", "); } append_pgsql_col_def (ddl, info); - is_unicode = is_unicode || info->is_unicode; - g_free (info->name); - g_free (info); + is_unicode = is_unicode || info->m_unicode; + delete info; } (void)g_string_append (ddl, ")"); if (is_unicode) diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index 43d50063ec..088f8849d3 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -143,13 +143,11 @@ add_address_col_info_to_list (const GncSqlBackend* be, for (subtable_row = col_table; subtable_row->col_name != NULL; subtable_row++) { buf = g_strdup_printf ("%s_%s", table_row->col_name, subtable_row->col_name); - info = g_new0 (GncSqlColumnInfo, 1); - info->name = buf; - info->type = BCT_STRING; - info->size = subtable_row->size; - info->is_primary_key = (table_row->flags & COL_PKEY) ? TRUE : FALSE; - info->null_allowed = (table_row->flags & COL_NNUL) ? FALSE : TRUE; - info->is_unicode = TRUE; + auto info = new GncSqlColumnInfo(buf, BCT_STRING, subtable_row->size, + true, false, + table_row->flags & COL_PKEY, + table_row->flags ^ COL_NNUL); + *pList = g_list_append (*pList, info); } } diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 70798ba366..a1b9a436db 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -1202,27 +1202,6 @@ gnc_sql_add_subtable_colnames_to_list (const GncSqlColumnTableEntry* table_row, (*pList) = g_list_append ((*pList), buf); } } - -static GncSqlColumnInfo* -create_column_info (const GncSqlColumnTableEntry* table_row, - GncSqlBasicColumnType type, - gint size, gboolean is_unicode) -{ - GncSqlColumnInfo* info; - - info = g_new0 (GncSqlColumnInfo, 1); - g_assert (info != NULL); - info->name = g_strdup (table_row->col_name); - info->type = type; - info->size = size; - info->is_primary_key = ((table_row->flags & COL_PKEY) != 0) ? TRUE : FALSE; - info->null_allowed = ((table_row->flags & COL_NNUL) != 0) ? FALSE : TRUE; - info->is_unicode = is_unicode; - info->is_autoinc = ((table_row->flags & COL_AUTOINC) != 0) ? TRUE : FALSE; - - return info; -} - /* ----------------------------------------------------------------- */ static void load_string (const GncSqlBackend* be, GncSqlRow* row, @@ -1261,13 +1240,12 @@ add_string_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, GList** pList) { - GncSqlColumnInfo* info; - g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); - info = create_column_info (table_row, BCT_STRING, table_row->size, TRUE); + auto info = new GncSqlColumnInfo{table_row, BCT_STRING, + table_row->size, TRUE}; *pList = g_list_append (*pList, info); } @@ -1372,13 +1350,11 @@ add_int_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, GList** pList) { - GncSqlColumnInfo* info; - g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); - info = create_column_info (table_row, BCT_INT, 0, FALSE); + auto info = new GncSqlColumnInfo{table_row, BCT_INT, 0, FALSE}; *pList = g_list_append (*pList, info); } @@ -1477,15 +1453,12 @@ add_boolean_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, GList** pList) { - GncSqlColumnInfo* info; - g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); - info = create_column_info (table_row, BCT_INT, 0, FALSE); - - *pList = g_list_append (*pList, info); + auto info = new GncSqlColumnInfo{table_row, BCT_INT, 0, FALSE}; + *pList = g_list_append (*pList, static_cast(info)); } static void @@ -1574,13 +1547,10 @@ add_int64_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, GList** pList) { - GncSqlColumnInfo* info; - g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); - - info = create_column_info (table_row, BCT_INT64, 0, FALSE); + auto info = new GncSqlColumnInfo{table_row, BCT_INT64, 0, FALSE}; *pList = g_list_append (*pList, info); } @@ -1688,13 +1658,11 @@ add_double_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, GList** pList) { - GncSqlColumnInfo* info; - g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); - info = create_column_info (table_row, BCT_DOUBLE, 0, FALSE); + auto info = new GncSqlColumnInfo{table_row, BCT_DOUBLE, 0, FALSE}; *pList = g_list_append (*pList, info); } @@ -1794,13 +1762,12 @@ add_guid_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, GList** pList) { - GncSqlColumnInfo* info; - g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); - info = create_column_info (table_row, BCT_STRING, GUID_ENCODING_LENGTH, FALSE); + auto info = new GncSqlColumnInfo{table_row, BCT_STRING, + GUID_ENCODING_LENGTH, FALSE}; *pList = g_list_append (*pList, info); } @@ -2013,13 +1980,12 @@ add_timespec_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, GList** pList) { - GncSqlColumnInfo* info; - g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); - info = create_column_info (table_row, BCT_DATETIME, TIMESPEC_COL_SIZE, FALSE); + auto info = new GncSqlColumnInfo{table_row, BCT_DATETIME, + TIMESPEC_COL_SIZE, FALSE}; *pList = g_list_append (*pList, info); } @@ -2172,13 +2138,11 @@ add_date_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, GList** pList) { - GncSqlColumnInfo* info; - g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); - info = create_column_info (table_row, BCT_DATE, DATE_COL_SIZE, FALSE); + auto info = new GncSqlColumnInfo{table_row, BCT_DATE, DATE_COL_SIZE, FALSE}; *pList = g_list_append (*pList, info); } @@ -2307,7 +2271,6 @@ add_numeric_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, GList** pList) { - GncSqlColumnInfo* info; gchar* buf; const GncSqlColumnTableEntry* subtable_row; @@ -2319,13 +2282,10 @@ add_numeric_col_info_to_list (const GncSqlBackend* be, subtable_row++) { buf = g_strdup_printf ("%s_%s", table_row->col_name, subtable_row->col_name); - info = g_new0 (GncSqlColumnInfo, 1); - g_assert (info != NULL); - info->name = buf; - info->type = BCT_INT64; - info->is_primary_key = ((table_row->flags & COL_PKEY) != 0) ? TRUE : FALSE; - info->null_allowed = ((table_row->flags & COL_NNUL) != 0) ? FALSE : TRUE; - info->is_unicode = FALSE; + auto info = new GncSqlColumnInfo(buf, BCT_INT64, 0, false, false, + table_row->flags & COL_PKEY, + table_row->flags ^ COL_NNUL); + *pList = g_list_append (*pList, info); } } diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index ef851203cc..f1871b4e90 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -51,6 +51,9 @@ extern "C" #include #include +struct GncSqlColumnInfo; + +using ColVec = std::vector; using LoadOrder = std::vector; typedef struct GncSqlConnection GncSqlConnection; @@ -310,22 +313,6 @@ typedef enum BCT_DATETIME } GncSqlBasicColumnType; -/** - * @struct GncSqlColumnInfo - * - * The GncSqlColumnInfo structure contains information required to create - * a column in a table. - */ -typedef struct -{ - gchar* name; /**< Column name */ - GncSqlBasicColumnType type; /**< Column basic type */ - gint size; /**< Column size (string types) */ - gboolean is_unicode; /**< Column is unicode (string types) */ - gboolean is_autoinc; /**< Column is autoinc (int type) */ - gboolean is_primary_key; /**< Column is the primary key */ - gboolean null_allowed; /**< Column allows NULL values */ -} GncSqlColumnInfo; // Type for conversion of db row to object. #define CT_STRING "ct_string" @@ -365,7 +352,7 @@ struct GncSqlColumnTableEntry { const gchar* col_name; /**< Column name */ const gchar* col_type; /**< Column type */ - gint size; /**< Column size in bytes, for string columns */ + unsigned int size; /**< Column size in bytes, for string columns */ #define COL_PKEY 0x01 /**< The column is a primary key */ #define COL_NNUL 0x02 /**< The column may not contain a NULL value */ #define COL_UNIQUE 0x04 /**< The column must contain unique values */ @@ -377,6 +364,33 @@ struct GncSqlColumnTableEntry QofSetterFunc setter; /**< General setter function */ }; +/** + * information required to create a column in a table. + */ +struct GncSqlColumnInfo +{ + GncSqlColumnInfo (std::string&& name, GncSqlBasicColumnType type, + unsigned int size = 0, bool unicode = false, + bool autoinc = false, bool primary = false, + bool null_allowed = false) : + m_name{name}, m_type{type}, m_size{size}, m_unicode{unicode}, + m_autoinc{autoinc}, m_primary_key{primary}, m_null_allowed{null_allowed} + {} + GncSqlColumnInfo(const GncSqlColumnTableEntry* e, GncSqlBasicColumnType t, + unsigned int size = 0, bool unicode = true) : + m_name{e->col_name}, m_type{t}, m_size{size}, m_unicode{unicode}, + m_autoinc(e->flags & COL_AUTOINC), + m_primary_key(e->flags & COL_PKEY), + m_null_allowed(e->flags ^ COL_NNUL) {} + std::string m_name; /**< Column name */ + GncSqlBasicColumnType m_type; /**< Column basic type */ + unsigned int m_size; /**< Column size (string types) */ + bool m_unicode; /**< Column is unicode (string types) */ + bool m_autoinc; /**< Column is autoinc (int type) */ + bool m_primary_key; /**< Column is the primary key */ + bool m_null_allowed; /**< Column allows NULL values */ +}; + typedef enum { OP_DB_INSERT, diff --git a/src/backend/sql/gnc-owner-sql.cpp b/src/backend/sql/gnc-owner-sql.cpp index 9b8e24ad5f..9a2f923d2b 100644 --- a/src/backend/sql/gnc-owner-sql.cpp +++ b/src/backend/sql/gnc-owner-sql.cpp @@ -173,7 +173,6 @@ add_owner_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, GList** pList) { - GncSqlColumnInfo* info; gchar* buf; g_return_if_fail (be != NULL); @@ -181,23 +180,18 @@ add_owner_col_info_to_list (const GncSqlBackend* be, g_return_if_fail (pList != NULL); buf = g_strdup_printf ("%s_type", table_row->col_name); - info = g_new0 (GncSqlColumnInfo, 1); - info->name = buf; - info->type = BCT_INT; - info->is_primary_key = (table_row->flags & COL_PKEY) ? TRUE : FALSE; - info->null_allowed = (table_row->flags & COL_NNUL) ? FALSE : TRUE; - info->size = table_row->size; - info->is_unicode = FALSE; + auto info = new GncSqlColumnInfo(buf, BCT_INT, 0, false, false, + table_row->flags & COL_PKEY, + table_row->flags ^ COL_NNUL); + *pList = g_list_append (*pList, info); buf = g_strdup_printf ("%s_guid", table_row->col_name); - info = g_new0 (GncSqlColumnInfo, 1); - info->name = buf; - info->type = BCT_STRING; - info->size = GUID_ENCODING_LENGTH; - info->is_primary_key = (table_row->flags & COL_PKEY) ? TRUE : FALSE; - info->null_allowed = (table_row->flags & COL_NNUL) ? FALSE : TRUE; - info->is_unicode = FALSE; + info = new GncSqlColumnInfo(buf, BCT_STRING, GUID_ENCODING_LENGTH, + false, false, + table_row->flags & COL_PKEY, + table_row->flags ^ COL_NNUL); + *pList = g_list_append (*pList, info); } diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index 9e474b5de0..2a82f6fed4 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -408,15 +408,6 @@ GList** pList)// C: 1 */ test_gnc_sql_add_subtable_colnames_to_list (Fixture *fixture, gconstpointer pData) { }*/ -/* create_column_info -static GncSqlColumnInfo* -create_column_info (const GncSqlColumnTableEntry* table_row, GncSqlBasicColumnType type, -gint size, gboolean is_unicode)// 9 -*/ -/* static void -test_create_column_info (Fixture *fixture, gconstpointer pData) -{ -}*/ /* load_string static void load_string (const GncSqlBackend* be, GncSqlRow* row, @@ -987,7 +978,6 @@ test_suite_gnc_backend_sql (void) // GNC_TEST_ADD (suitename, "gnc sql get getter", Fixture, nullptr, test_gnc_sql_get_getter, teardown); // GNC_TEST_ADD (suitename, "gnc sql add colname to list", Fixture, nullptr, test_gnc_sql_add_colname_to_list, teardown); // GNC_TEST_ADD (suitename, "gnc sql add subtable colnames to list", Fixture, nullptr, test_gnc_sql_add_subtable_colnames_to_list, teardown); -// GNC_TEST_ADD (suitename, "create column info", Fixture, nullptr, test_create_column_info, teardown); // GNC_TEST_ADD (suitename, "load string", Fixture, nullptr, test_load_string, teardown); // GNC_TEST_ADD (suitename, "add string col info to list", Fixture, nullptr, test_add_string_col_info_to_list, teardown); // GNC_TEST_ADD (suitename, "add gvalue string to slist", Fixture, nullptr, test_add_gvalue_string_to_slist, teardown); From 72ac25d7552a790f02e8f03c481de2bf3bfe33b8 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 28 Feb 2016 12:28:18 -0800 Subject: [PATCH 03/63] Change GncSqlColumnInfo::m_null_allowed to m_not_null and invert logic. The COL_NNUL flag is "not null", the SQL table column qualifier is NOT NULL, and bitwise AND is clearer code than bitwise XOR. --- src/backend/dbi/gnc-backend-dbi.cpp | 7 +++---- src/backend/sql/gnc-address-sql.cpp | 2 +- src/backend/sql/gnc-backend-sql.cpp | 2 +- src/backend/sql/gnc-backend-sql.h | 8 ++++---- src/backend/sql/gnc-owner-sql.cpp | 4 ++-- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 19c8957332..d0f3fba211 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -2763,7 +2763,7 @@ append_sqlite3_col_def (GString* ddl, GncSqlColumnInfo* info) { (void)g_string_append (ddl, " AUTOINCREMENT"); } - if (!info->m_null_allowed) + if (info->m_not_null) { (void)g_string_append (ddl, " NOT NULL"); } @@ -2854,8 +2854,7 @@ append_mysql_col_def (GString* ddl, GncSqlColumnInfo* info) { (void)g_string_append (ddl, " AUTO_INCREMENT"); } - if (!info->m_null_allowed) - + if (info->m_not_null) { (void)g_string_append (ddl, " NOT NULL"); } @@ -2945,7 +2944,7 @@ append_pgsql_col_def (GString* ddl, GncSqlColumnInfo* info) { (void)g_string_append (ddl, " PRIMARY KEY"); } - if (!info->m_null_allowed) + if (info->m_not_null) { (void)g_string_append (ddl, " NOT NULL"); } diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index 088f8849d3..b6af258564 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -146,7 +146,7 @@ add_address_col_info_to_list (const GncSqlBackend* be, auto info = new GncSqlColumnInfo(buf, BCT_STRING, subtable_row->size, true, false, table_row->flags & COL_PKEY, - table_row->flags ^ COL_NNUL); + table_row->flags & COL_NNUL); *pList = g_list_append (*pList, info); } diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index a1b9a436db..4b98a09343 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -2284,7 +2284,7 @@ add_numeric_col_info_to_list (const GncSqlBackend* be, buf = g_strdup_printf ("%s_%s", table_row->col_name, subtable_row->col_name); auto info = new GncSqlColumnInfo(buf, BCT_INT64, 0, false, false, table_row->flags & COL_PKEY, - table_row->flags ^ COL_NNUL); + table_row->flags & COL_NNUL); *pList = g_list_append (*pList, info); } diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index f1871b4e90..8412b18051 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -372,23 +372,23 @@ struct GncSqlColumnInfo GncSqlColumnInfo (std::string&& name, GncSqlBasicColumnType type, unsigned int size = 0, bool unicode = false, bool autoinc = false, bool primary = false, - bool null_allowed = false) : + bool not_null = false) : m_name{name}, m_type{type}, m_size{size}, m_unicode{unicode}, - m_autoinc{autoinc}, m_primary_key{primary}, m_null_allowed{null_allowed} + m_autoinc{autoinc}, m_primary_key{primary}, m_not_null{not_null} {} GncSqlColumnInfo(const GncSqlColumnTableEntry* e, GncSqlBasicColumnType t, unsigned int size = 0, bool unicode = true) : m_name{e->col_name}, m_type{t}, m_size{size}, m_unicode{unicode}, m_autoinc(e->flags & COL_AUTOINC), m_primary_key(e->flags & COL_PKEY), - m_null_allowed(e->flags ^ COL_NNUL) {} + m_not_null(e->flags & COL_NNUL) {} std::string m_name; /**< Column name */ GncSqlBasicColumnType m_type; /**< Column basic type */ unsigned int m_size; /**< Column size (string types) */ bool m_unicode; /**< Column is unicode (string types) */ bool m_autoinc; /**< Column is autoinc (int type) */ bool m_primary_key; /**< Column is the primary key */ - bool m_null_allowed; /**< Column allows NULL values */ + bool m_not_null; /**< Column forbids NULL values */ }; typedef enum diff --git a/src/backend/sql/gnc-owner-sql.cpp b/src/backend/sql/gnc-owner-sql.cpp index 9a2f923d2b..ae234849e1 100644 --- a/src/backend/sql/gnc-owner-sql.cpp +++ b/src/backend/sql/gnc-owner-sql.cpp @@ -182,7 +182,7 @@ add_owner_col_info_to_list (const GncSqlBackend* be, buf = g_strdup_printf ("%s_type", table_row->col_name); auto info = new GncSqlColumnInfo(buf, BCT_INT, 0, false, false, table_row->flags & COL_PKEY, - table_row->flags ^ COL_NNUL); + table_row->flags & COL_NNUL); *pList = g_list_append (*pList, info); @@ -190,7 +190,7 @@ add_owner_col_info_to_list (const GncSqlBackend* be, info = new GncSqlColumnInfo(buf, BCT_STRING, GUID_ENCODING_LENGTH, false, false, table_row->flags & COL_PKEY, - table_row->flags ^ COL_NNUL); + table_row->flags & COL_NNUL); *pList = g_list_append (*pList, info); } From be1a5f56d69450302d4c67703b513d2bf2d00fbd Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 28 Feb 2016 14:38:29 -0800 Subject: [PATCH 04/63] Replace heap-allocate GncSqlColumnInfo GList with on-stack std::vector. Faster, more concise, can't leak. --- src/backend/dbi/gnc-backend-dbi-priv.h | 15 +- src/backend/dbi/gnc-backend-dbi.cpp | 252 ++++++++++--------------- src/backend/sql/gnc-address-sql.cpp | 16 +- src/backend/sql/gnc-backend-sql.cpp | 134 ++++++------- src/backend/sql/gnc-backend-sql.h | 50 ++--- src/backend/sql/gnc-owner-sql.cpp | 17 +- 6 files changed, 207 insertions(+), 277 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi-priv.h b/src/backend/dbi/gnc-backend-dbi-priv.h index acf8cc9b4c..09d2f73666 100644 --- a/src/backend/dbi/gnc-backend-dbi-priv.h +++ b/src/backend/dbi/gnc-backend-dbi-priv.h @@ -62,13 +62,14 @@ typedef enum GNC_DBI_FAIL_TEST } GncDbiTestResult; -typedef gchar* (*CREATE_TABLE_DDL_FN) (GncSqlConnection* conn, - const gchar* table_name, - const GList* col_info_list); -typedef GSList* (*GET_TABLE_LIST_FN) (dbi_conn conn, const gchar* dbname); -typedef void (*APPEND_COLUMN_DEF_FN) (GString* ddl, GncSqlColumnInfo* info); -typedef GSList* (*GET_INDEX_LIST_FN) (dbi_conn conn); -typedef void (*DROP_INDEX_FN) (dbi_conn conn, const gchar* index); +typedef gchar* (*CREATE_TABLE_DDL_FN) (GncSqlConnection* conn, + const gchar* table_name, + const ColVec& info_vec); +typedef GSList* (*GET_TABLE_LIST_FN) (dbi_conn conn, const gchar* dbname); +typedef void (*APPEND_COLUMN_DEF_FN) (GString* ddl, + const GncSqlColumnInfo& info); +typedef GSList* (*GET_INDEX_LIST_FN) (dbi_conn conn); +typedef void (*DROP_INDEX_FN) (dbi_conn conn, const gchar* index); typedef struct { CREATE_TABLE_DDL_FN create_table_ddl; diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index d0f3fba211..7e4198160c 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -156,15 +156,14 @@ static gchar lock_table[] = "gnclock"; #define SQLITE3_URI_PREFIX (SQLITE3_URI_TYPE "://") #define PGSQL_DEFAULT_PORT 5432 -static gchar* conn_create_table_ddl_sqlite3 (GncSqlConnection* conn, - const gchar* table_name, - const GList* col_info_list); +static gchar* conn_create_table_ddl_sqlite3 (GncSqlConnection* conn, + const gchar* table_name, + const ColVec& info_vec); static GSList* conn_get_table_list (dbi_conn conn, const gchar* dbname); -static GSList* conn_get_table_list_sqlite3 (dbi_conn conn, - const gchar* dbname); -static void append_sqlite3_col_def (GString* ddl, GncSqlColumnInfo* info); -static GSList* conn_get_index_list_sqlite3 (dbi_conn conn); -static void conn_drop_index_sqlite3 (dbi_conn conn, const gchar* index); +static GSList* conn_get_table_list_sqlite3 (dbi_conn conn, const gchar* dbname); +static void append_sqlite3_col_def (GString* ddl, const GncSqlColumnInfo& info); +static GSList *conn_get_index_list_sqlite3 (dbi_conn conn); +static void conn_drop_index_sqlite3 (dbi_conn conn, const gchar *index); static provider_functions_t provider_sqlite3 = { conn_create_table_ddl_sqlite3, @@ -175,12 +174,12 @@ static provider_functions_t provider_sqlite3 = }; #define SQLITE3_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" -static gchar* conn_create_table_ddl_mysql (GncSqlConnection* conn, - const gchar* table_name, - const GList* col_info_list); -static void append_mysql_col_def (GString* ddl, GncSqlColumnInfo* info); -static GSList* conn_get_index_list_mysql (dbi_conn conn); -static void conn_drop_index_mysql (dbi_conn conn, const gchar* index); +static gchar* conn_create_table_ddl_mysql (GncSqlConnection* conn, + const gchar* table_name, + const ColVec& info_vec); +static void append_mysql_col_def (GString* ddl, const GncSqlColumnInfo& info); +static GSList *conn_get_index_list_mysql (dbi_conn conn); +static void conn_drop_index_mysql (dbi_conn conn, const gchar *index); static provider_functions_t provider_mysql = { conn_create_table_ddl_mysql, @@ -191,13 +190,13 @@ static provider_functions_t provider_mysql = }; #define MYSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" -static gchar* conn_create_table_ddl_pgsql (GncSqlConnection* conn, - const gchar* table_name, - const GList* col_info_list); +static gchar* conn_create_table_ddl_pgsql (GncSqlConnection* conn, + const gchar* table_name, + const ColVec& info_vec ); static GSList* conn_get_table_list_pgsql (dbi_conn conn, const gchar* dbname); -static void append_pgsql_col_def (GString* ddl, GncSqlColumnInfo* info); -static GSList* conn_get_index_list_pgsql (dbi_conn conn); -static void conn_drop_index_pgsql (dbi_conn conn, const gchar* index); +static void append_pgsql_col_def (GString* ddl, const GncSqlColumnInfo& info); +static GSList *conn_get_index_list_pgsql (dbi_conn conn); +static void conn_drop_index_pgsql (dbi_conn conn, const gchar *index); static provider_functions_t provider_pgsql = { @@ -209,19 +208,19 @@ static provider_functions_t provider_pgsql = }; #define PGSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d %02d%02d%02d" -static gboolean gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock); -static void gnc_dbi_unlock (QofBackend* qbe); +static gboolean gnc_dbi_lock_database (QofBackend *qbe, gboolean ignore_lock); +static void gnc_dbi_unlock (QofBackend *qbe); static gboolean save_may_clobber_data (QofBackend* qbe); -static gchar* create_index_ddl (GncSqlConnection* conn, - const gchar* index_name, - const gchar* table_name, - const GncSqlColumnTableEntry* col_table); -static gchar* add_columns_ddl (GncSqlConnection* conn, +static gchar* create_index_ddl (GncSqlConnection* conn, + const gchar* index_name, const gchar* table_name, - GList* col_info_list); + const GncSqlColumnTableEntry* col_table); +static gchar* add_columns_ddl (GncSqlConnection* conn, + const gchar* table_name, + const ColVec& info_vec); static GncSqlConnection* create_dbi_connection (provider_functions_t* provider, - QofBackend* qbe, dbi_conn conn); + QofBackend* qbe, dbi_conn conn); static GncDbiTestResult conn_test_dbi_library (dbi_conn conn); #define GNC_DBI_PROVIDER_SQLITE (&provider_sqlite3) #define GNC_DBI_PROVIDER_MYSQL (&provider_mysql) @@ -2690,80 +2689,73 @@ create_index_ddl (GncSqlConnection* conn, return g_string_free (ddl, FALSE); } -static gchar* -add_columns_ddl (GncSqlConnection* conn, - const gchar* table_name, - GList* col_info_list) +static gchar* +add_columns_ddl(GncSqlConnection* conn, + const gchar* table_name, + const ColVec& info_vec) { GString* ddl; - const GList* list_node; - guint col_num; GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; g_return_val_if_fail (conn != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); - g_return_val_if_fail (col_info_list != NULL, NULL); ddl = g_string_new (""); g_string_printf (ddl, "ALTER TABLE %s ", table_name); - for (list_node = col_info_list, col_num = 0; list_node != NULL; - list_node = list_node->next, col_num++) + for (auto const& info : info_vec) { - GncSqlColumnInfo* info = (GncSqlColumnInfo*) (list_node->data); - - if (col_num != 0) + if (info != *info_vec.begin()) { (void)g_string_append (ddl, ", "); } g_string_append (ddl, "ADD COLUMN "); dbi_conn->provider->append_col_def (ddl, info); - delete info; } return g_string_free (ddl, FALSE); } static void -append_sqlite3_col_def (GString* ddl, GncSqlColumnInfo* info) +append_sqlite3_col_def(GString* ddl, const GncSqlColumnInfo& info) { const char* type_name = nullptr; - if (info->m_type == BCT_INT) + if (info.m_type == BCT_INT) { type_name = "integer"; } - else if (info->m_type == BCT_INT64) + else if (info.m_type == BCT_INT64) { type_name = "bigint"; } - else if (info->m_type == BCT_DOUBLE) + else if (info.m_type == BCT_DOUBLE) { type_name = "float8"; } - else if (info->m_type == BCT_STRING || info->m_type == BCT_DATE - || info->m_type == BCT_DATETIME) + else if (info.m_type == BCT_STRING || info.m_type == BCT_DATE + || info.m_type == BCT_DATETIME) { type_name = "text"; } else { - PERR ("Unknown column type: %d\n", info->m_type); + PERR ("Unknown column type: %d\n", info.m_type); type_name = ""; } - g_string_append_printf (ddl, "%s %s", info->m_name.c_str(), type_name); - if (info->m_size != 0) + g_string_append_printf (ddl, "%s %s", info.m_name.c_str(), type_name); + if (info.m_size != 0) { - (void)g_string_append_printf (ddl, "(%d)", info->m_size); + (void)g_string_append_printf (ddl, "(%d)", info.m_size); } - if (info->m_primary_key) + if (info.m_primary_key) { (void)g_string_append (ddl, " PRIMARY KEY"); } - if (info->m_autoinc) + if (info.m_autoinc) { (void)g_string_append (ddl, " AUTOINCREMENT"); } - if (info->m_not_null) + if (info.m_not_null) { (void)g_string_append (ddl, " NOT NULL"); } @@ -2772,29 +2764,23 @@ append_sqlite3_col_def (GString* ddl, GncSqlColumnInfo* info) static gchar* conn_create_table_ddl_sqlite3 (GncSqlConnection* conn, const gchar* table_name, - const GList* col_info_list) + const ColVec& info_vec) { GString* ddl; - const GList* list_node; - guint col_num; + unsigned int col_num = 0; g_return_val_if_fail (conn != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); - g_return_val_if_fail (col_info_list != NULL, NULL); ddl = g_string_new (""); g_string_printf (ddl, "CREATE TABLE %s (", table_name); - for (list_node = col_info_list, col_num = 0; list_node != NULL; - list_node = list_node->next, col_num++) + for (auto const& info : info_vec) { - GncSqlColumnInfo* info = (GncSqlColumnInfo*) (list_node->data); - - if (col_num != 0) + if (col_num++ != 0) { (void)g_string_append (ddl, ", "); } append_sqlite3_col_def (ddl, info); - delete info; } (void)g_string_append (ddl, ")"); @@ -2802,59 +2788,57 @@ conn_create_table_ddl_sqlite3 (GncSqlConnection* conn, } static void -append_mysql_col_def (GString* ddl, GncSqlColumnInfo* info) +append_mysql_col_def (GString* ddl, const GncSqlColumnInfo& info) { const char* type_name = nullptr; - if (info->m_type == BCT_INT) + if (info.m_type == BCT_INT) { type_name = "integer"; } - else if (info->m_type == BCT_INT64) + else if (info.m_type == BCT_INT64) { type_name = "bigint"; } - else if (info->m_type == BCT_DOUBLE) + else if (info.m_type == BCT_DOUBLE) { type_name = "double"; } - else if (info->m_type == BCT_STRING) + else if (info.m_type == BCT_STRING) { type_name = "varchar"; } - else if (info->m_type == BCT_DATE) + else if (info.m_type == BCT_DATE) { - info->m_size = 0; type_name = "date"; } - else if (info->m_type == BCT_DATETIME) + else if (info.m_type == BCT_DATETIME) { - info->m_size = 0; type_name = "TIMESTAMP NULL DEFAULT 0"; } else { - PERR ("Unknown column type: %d\n", info->m_type); + PERR ("Unknown column type: %d\n", info.m_type); type_name = ""; } - g_string_append_printf (ddl, "%s %s", info->m_name.c_str(), type_name); - if (info->m_size != 0) + g_string_append_printf (ddl, "%s %s", info.m_name.c_str(), type_name); + if (info.m_size != 0 && info.m_type == BCT_STRING) { - g_string_append_printf (ddl, "(%d)", info->m_size); + g_string_append_printf (ddl, "(%d)", info.m_size); } - if (info->m_unicode) + if (info.m_unicode) { (void)g_string_append (ddl, " CHARACTER SET utf8"); } - if (info->m_primary_key) + if (info.m_primary_key) { (void)g_string_append (ddl, " PRIMARY KEY"); } - if (info->m_autoinc) + if (info.m_autoinc) { (void)g_string_append (ddl, " AUTO_INCREMENT"); } - if (info->m_not_null) + if (info.m_not_null) { (void)g_string_append (ddl, " NOT NULL"); } @@ -2862,29 +2846,23 @@ append_mysql_col_def (GString* ddl, GncSqlColumnInfo* info) static gchar* conn_create_table_ddl_mysql (GncSqlConnection* conn, const gchar* table_name, - const GList* col_info_list) + const ColVec& info_vec) { GString* ddl; - const GList* list_node; - guint col_num; + unsigned int col_num = 0; g_return_val_if_fail (conn != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); - g_return_val_if_fail (col_info_list != NULL, NULL); ddl = g_string_new (""); g_string_printf (ddl, "CREATE TABLE %s (", table_name); - for (list_node = col_info_list, col_num = 0; list_node != NULL; - list_node = list_node->next, col_num++) + for (auto const& info : info_vec) { - GncSqlColumnInfo* info = (GncSqlColumnInfo*) (list_node->data); - - if (col_num != 0) + if (col_num++ != 0) { (void)g_string_append (ddl, ", "); } append_mysql_col_def (ddl, info); - delete info; } (void)g_string_append (ddl, ")"); @@ -2892,13 +2870,13 @@ conn_create_table_ddl_mysql (GncSqlConnection* conn, const gchar* table_name, } static void -append_pgsql_col_def (GString* ddl, GncSqlColumnInfo* info) +append_pgsql_col_def (GString* ddl, const GncSqlColumnInfo& info) { const char* type_name = nullptr; - if (info->m_type == BCT_INT) + if (info.m_type == BCT_INT) { - if (info->m_autoinc) + if (info.m_autoinc) { type_name = "serial"; } @@ -2907,44 +2885,42 @@ append_pgsql_col_def (GString* ddl, GncSqlColumnInfo* info) type_name = "integer"; } } - else if (info->m_type == BCT_INT64) + else if (info.m_type == BCT_INT64) { type_name = "int8"; } - else if (info->m_type == BCT_DOUBLE) + else if (info.m_type == BCT_DOUBLE) { type_name = "double precision"; } - else if (info->m_type == BCT_STRING) + else if (info.m_type == BCT_STRING) { type_name = "varchar"; } - else if (info->m_type == BCT_DATE) + else if (info.m_type == BCT_DATE) { - info->m_size = 0; type_name = "date"; } - else if (info->m_type == BCT_DATETIME) + else if (info.m_type == BCT_DATETIME) { - info->m_size = 0; type_name = "timestamp without time zone"; } else { - PERR ("Unknown column type: %d\n", info->m_type); + PERR ("Unknown column type: %d\n", info.m_type); type_name = ""; } - g_string_append_printf (ddl, "%s %s", info->m_name.c_str(), type_name); - if (info->m_size != 0) + g_string_append_printf (ddl, "%s %s", info.m_name.c_str(), type_name); + if (info.m_size != 0 && info.m_type == BCT_STRING) { - g_string_append_printf (ddl, "(%d)", info->m_size); + g_string_append_printf (ddl, "(%d)", info.m_size); } - if (info->m_primary_key) + if (info.m_primary_key) { (void)g_string_append (ddl, " PRIMARY KEY"); } - if (info->m_not_null) + if (info.m_not_null) { (void)g_string_append (ddl, " NOT NULL"); } @@ -2952,43 +2928,32 @@ append_pgsql_col_def (GString* ddl, GncSqlColumnInfo* info) static gchar* conn_create_table_ddl_pgsql (GncSqlConnection* conn, const gchar* table_name, - const GList* col_info_list) + const ColVec& info_vec) { GString* ddl; - const GList* list_node; - guint col_num; - gboolean is_unicode = FALSE; + unsigned int col_num = 0; g_return_val_if_fail (conn != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); - g_return_val_if_fail (col_info_list != NULL, NULL); ddl = g_string_new (""); g_string_printf (ddl, "CREATE TABLE %s (", table_name); - for (list_node = col_info_list, col_num = 0; list_node != NULL; - list_node = list_node->next, col_num++) + for (auto const& info : info_vec) { - GncSqlColumnInfo* info = (GncSqlColumnInfo*) (list_node->data); - - if (col_num != 0) + if (col_num++ != 0) { (void)g_string_append (ddl, ", "); } append_pgsql_col_def (ddl, info); - is_unicode = is_unicode || info->m_unicode; - delete info; } (void)g_string_append (ddl, ")"); - if (is_unicode) - { - } return g_string_free (ddl, FALSE); } static gboolean conn_create_table (GncSqlConnection* conn, const gchar* table_name, - GList* col_info_list) + const ColVec& info_vec) { GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; gchar* ddl; @@ -2996,12 +2961,8 @@ conn_create_table (GncSqlConnection* conn, const gchar* table_name, g_return_val_if_fail (conn != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - g_return_val_if_fail (col_info_list != NULL, FALSE); - - ddl = dbi_conn->provider->create_table_ddl (conn, table_name, - col_info_list); - g_list_free (col_info_list); + ddl = dbi_conn->provider->create_table_ddl(conn, table_name, info_vec); if (ddl != NULL) { gint status; @@ -3061,8 +3022,8 @@ conn_create_index (GncSqlConnection* conn, const gchar* index_name, } static gboolean -conn_add_columns_to_table (GncSqlConnection* conn, const gchar* table_name, - GList* col_info_list) +conn_add_columns_to_table(GncSqlConnection* conn, const char* table_name, + const ColVec& info_vec) { GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; gchar* ddl; @@ -3070,26 +3031,19 @@ conn_add_columns_to_table (GncSqlConnection* conn, const gchar* table_name, g_return_val_if_fail (conn != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - g_return_val_if_fail (col_info_list != NULL, FALSE); - ddl = add_columns_ddl (conn, table_name, col_info_list); - if (ddl != NULL) - { - gint status; - - DEBUG ("SQL: %s\n", ddl); - result = dbi_conn_query (dbi_conn->conn, ddl); - g_free (ddl); - status = dbi_result_free (result); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); - } - } - else - { + ddl = add_columns_ddl(conn, table_name, info_vec); + if (ddl == NULL) return FALSE; + + DEBUG ("SQL: %s\n", ddl); + result = dbi_conn_query (dbi_conn->conn, ddl); + g_free (ddl); + int status = dbi_result_free (result); + if (status < 0) + { + PERR( "Error in dbi_result_free() result\n" ); + qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR ); } return TRUE; diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index b6af258564..94f715316c 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -128,9 +128,9 @@ load_address (const GncSqlBackend* be, GncSqlRow* row, } static void -add_address_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +add_address_col_info_to_list(const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& vec) { GncSqlColumnInfo* info; gchar* buf; @@ -138,17 +138,15 @@ add_address_col_info_to_list (const GncSqlBackend* be, g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); for (subtable_row = col_table; subtable_row->col_name != NULL; subtable_row++) { buf = g_strdup_printf ("%s_%s", table_row->col_name, subtable_row->col_name); - auto info = new GncSqlColumnInfo(buf, BCT_STRING, subtable_row->size, - true, false, - table_row->flags & COL_PKEY, - table_row->flags & COL_NNUL); - *pList = g_list_append (*pList, info); + GncSqlColumnInfo info(buf, BCT_STRING, subtable_row->size, true, false, + table_row->flags & COL_PKEY, + table_row->flags & COL_NNUL); + vec.emplace_back(std::move(info)); } } diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 4b98a09343..23c0b95ea1 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -1236,18 +1236,15 @@ load_string (const GncSqlBackend* be, GncSqlRow* row, } static void -add_string_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +add_string_col_info_to_list(const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& vec) { g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); - auto info = new GncSqlColumnInfo{table_row, BCT_STRING, - table_row->size, TRUE}; - - *pList = g_list_append (*pList, info); + GncSqlColumnInfo info{table_row, BCT_STRING, table_row->size, TRUE}; + vec.emplace_back(std::move(info)); } static void @@ -1346,17 +1343,15 @@ load_int (const GncSqlBackend* be, GncSqlRow* row, } static void -add_int_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +add_int_col_info_to_list(const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& vec) { g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); - auto info = new GncSqlColumnInfo{table_row, BCT_INT, 0, FALSE}; - - *pList = g_list_append (*pList, info); + GncSqlColumnInfo info{table_row, BCT_INT, 0, FALSE}; + vec.emplace_back(std::move(info)); } static void @@ -1449,16 +1444,15 @@ load_boolean (const GncSqlBackend* be, GncSqlRow* row, } static void -add_boolean_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +add_boolean_col_info_to_list(const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& vec) { g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); - auto info = new GncSqlColumnInfo{table_row, BCT_INT, 0, FALSE}; - *pList = g_list_append (*pList, static_cast(info)); + GncSqlColumnInfo info{table_row, BCT_INT, 0, FALSE}; + vec.emplace_back(std::move(info)); } static void @@ -1543,16 +1537,15 @@ load_int64 (const GncSqlBackend* be, GncSqlRow* row, } static void -add_int64_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +add_int64_col_info_to_list(const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& vec) { g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); - auto info = new GncSqlColumnInfo{table_row, BCT_INT64, 0, FALSE}; - *pList = g_list_append (*pList, info); + GncSqlColumnInfo info{table_row, BCT_INT64, 0, FALSE}; + vec.emplace_back(std::move(info)); } static void @@ -1654,17 +1647,15 @@ load_double (const GncSqlBackend* be, GncSqlRow* row, } static void -add_double_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +add_double_col_info_to_list(const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& vec) { g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); - auto info = new GncSqlColumnInfo{table_row, BCT_DOUBLE, 0, FALSE}; - - *pList = g_list_append (*pList, info); + GncSqlColumnInfo info{table_row, BCT_DOUBLE, 0, FALSE}; + vec.emplace_back(std::move(info)); } static void @@ -1758,18 +1749,15 @@ load_guid (const GncSqlBackend* be, GncSqlRow* row, } static void -add_guid_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +add_guid_col_info_to_list(const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& vec) { g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); - auto info = new GncSqlColumnInfo{table_row, BCT_STRING, - GUID_ENCODING_LENGTH, FALSE}; - - *pList = g_list_append (*pList, info); + GncSqlColumnInfo info{table_row, BCT_STRING, GUID_ENCODING_LENGTH, FALSE}; + vec.emplace_back(std::move(info)); } static void @@ -1868,11 +1856,11 @@ gnc_sql_add_gvalue_objectref_guid_to_slist (const GncSqlBackend* be, } void -gnc_sql_add_objectref_guid_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +gnc_sql_add_objectref_guid_col_info_to_list( const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& info_vec) { - add_guid_col_info_to_list (be, table_row, pList); + add_guid_col_info_to_list(be, table_row, info_vec); } /* ----------------------------------------------------------------- */ @@ -1976,18 +1964,15 @@ load_timespec (const GncSqlBackend* be, GncSqlRow* row, } static void -add_timespec_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +add_timespec_col_info_to_list(const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& vec) { g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); - auto info = new GncSqlColumnInfo{table_row, BCT_DATETIME, - TIMESPEC_COL_SIZE, FALSE}; - - *pList = g_list_append (*pList, info); + GncSqlColumnInfo info{table_row, BCT_DATETIME, TIMESPEC_COL_SIZE, FALSE}; + vec.emplace_back(std::move(info)); } static void @@ -2136,15 +2121,13 @@ load_date (const GncSqlBackend* be, GncSqlRow* row, static void add_date_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, - GList** pList) + ColVec& vec) { g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); - auto info = new GncSqlColumnInfo{table_row, BCT_DATE, DATE_COL_SIZE, FALSE}; - - *pList = g_list_append (*pList, info); + GncSqlColumnInfo info{table_row, BCT_DATE, DATE_COL_SIZE, FALSE}; + vec.emplace_back(std::move(info)); } static void @@ -2267,26 +2250,24 @@ load_numeric (const GncSqlBackend* be, GncSqlRow* row, } static void -add_numeric_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +add_numeric_col_info_to_list(const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& vec) { gchar* buf; const GncSqlColumnTableEntry* subtable_row; g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); for (subtable_row = numeric_col_table; subtable_row->col_name != NULL; subtable_row++) { - buf = g_strdup_printf ("%s_%s", table_row->col_name, subtable_row->col_name); - auto info = new GncSqlColumnInfo(buf, BCT_INT64, 0, false, false, - table_row->flags & COL_PKEY, - table_row->flags & COL_NNUL); - - *pList = g_list_append (*pList, info); + buf = g_strdup_printf("%s_%s", table_row->col_name, subtable_row->col_name); + GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false, + table_row->flags & COL_PKEY, + table_row->flags & COL_NNUL); + vec.emplace_back(std::move(info)); } } @@ -3098,7 +3079,7 @@ static gboolean do_create_table (const GncSqlBackend* be, const gchar* table_name, const GncSqlColumnTableEntry* col_table) { - GList* col_info_list = NULL; + ColVec info_vec; gboolean ok = FALSE; g_return_val_if_fail (be != NULL, FALSE); @@ -3111,10 +3092,9 @@ do_create_table (const GncSqlBackend* be, const gchar* table_name, pHandler = get_handler (col_table); g_assert (pHandler != NULL); - pHandler->add_col_info_to_list_fn (be, col_table, &col_info_list); + pHandler->add_col_info_to_list_fn (be, col_table, info_vec); } - g_assert (col_info_list != NULL); - ok = gnc_sql_connection_create_table (be->conn, table_name, col_info_list); + ok = gnc_sql_connection_create_table (be->conn, table_name, info_vec); return ok; } @@ -3219,7 +3199,7 @@ gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const gchar* table_name, const GncSqlColumnTableEntry* new_col_table) { - GList* col_info_list = NULL; + ColVec info_vec; gboolean ok = FALSE; g_return_val_if_fail (be != NULL, FALSE); @@ -3232,11 +3212,9 @@ gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, pHandler = get_handler (new_col_table); g_assert (pHandler != NULL); - pHandler->add_col_info_to_list_fn (be, new_col_table, &col_info_list); + pHandler->add_col_info_to_list_fn (be, new_col_table, info_vec); } - g_assert (col_info_list != NULL); - ok = gnc_sql_connection_add_columns_to_table (be->conn, table_name, - col_info_list); + ok = gnc_sql_connection_add_columns_to_table(be->conn, table_name, info_vec); return ok; } diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 8412b18051..df88bdfb9e 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -171,25 +171,16 @@ struct GncSqlStatement struct GncSqlConnection { void (*dispose) (GncSqlConnection*); - GncSqlResult* (*executeSelectStatement) (GncSqlConnection*, - GncSqlStatement*); /**< Returns NULL if error */ - gint (*executeNonSelectStatement) (GncSqlConnection*, - GncSqlStatement*); /**< Returns -1 if error */ + GncSqlResult* (*executeSelectStatement) (GncSqlConnection*, GncSqlStatement*); /**< Returns NULL if error */ + gint (*executeNonSelectStatement) (GncSqlConnection*, GncSqlStatement*); /**< Returns -1 if error */ GncSqlStatement* (*createStatementFromSql) (GncSqlConnection*, const gchar*); - gboolean (*doesTableExist) (GncSqlConnection*, - const gchar*); /**< Returns true if successful */ - gboolean (*beginTransaction) ( - GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*rollbackTransaction) ( - GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*commitTransaction) ( - GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*createTable) (GncSqlConnection*, const gchar*, - GList*); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*createIndex) (GncSqlConnection*, const gchar*, const gchar*, - const GncSqlColumnTableEntry*); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*addColumnsToTable) (GncSqlConnection*, const gchar* table, - GList*); /**< Returns TRUE if successful, FALSE if error */ + gboolean (*doesTableExist) (GncSqlConnection*, const gchar*); /**< Returns true if successful */ + gboolean (*beginTransaction) (GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ + gboolean (*rollbackTransaction) (GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ + gboolean (*commitTransaction) (GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ + gboolean (*createTable) (GncSqlConnection*, const gchar*, const ColVec&); /**< Returns TRUE if successful, FALSE if error */ + gboolean (*createIndex) (GncSqlConnection*, const gchar*, const gchar*, const GncSqlColumnTableEntry*); /**< Returns TRUE if successful, FALSE if error */ + gboolean (*addColumnsToTable) (GncSqlConnection*, const gchar* table, const ColVec&); /**< Returns TRUE if successful, FALSE if error */ gchar* (*quoteString) (const GncSqlConnection*, gchar*); }; #define gnc_sql_connection_dispose(CONN) (CONN)->dispose(CONN) @@ -391,6 +382,18 @@ struct GncSqlColumnInfo bool m_not_null; /**< Column forbids NULL values */ }; +inline bool operator==(const GncSqlColumnInfo& l, + const GncSqlColumnInfo& r) +{ + return l.m_name == r.m_name && l.m_type == r.m_type; +} + +inline bool operator!=(const GncSqlColumnInfo& l, + const GncSqlColumnInfo& r) +{ + return !(l == r); +} + typedef enum { OP_DB_INSERT, @@ -403,14 +406,13 @@ typedef void (*GNC_SQL_LOAD_FN) (const GncSqlBackend* be, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry* table); typedef void (*GNC_SQL_ADD_COL_INFO_TO_LIST_FN) (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList); -typedef void (*GNC_SQL_ADD_COLNAME_TO_LIST_FN) (const GncSqlColumnTableEntry* - table_row, GList** pList); + const GncSqlColumnTableEntry* table_row, + ColVec& vec); +typedef void (*GNC_SQL_ADD_COLNAME_TO_LIST_FN) (const GncSqlColumnTableEntry* table_row, GList** pList); typedef void (*GNC_SQL_ADD_GVALUE_TO_SLIST_FN) (const GncSqlBackend* be, QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry* table_row, GSList** pList); /** @@ -673,7 +675,7 @@ void gnc_sql_add_gvalue_objectref_guid_to_slist (const GncSqlBackend* be, */ void gnc_sql_add_objectref_guid_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, - GList** pList); + ColVec& vec); /** * Appends the ascii strings for a list of GUIDs to the end of an SQL string. diff --git a/src/backend/sql/gnc-owner-sql.cpp b/src/backend/sql/gnc-owner-sql.cpp index ae234849e1..73b5717637 100644 --- a/src/backend/sql/gnc-owner-sql.cpp +++ b/src/backend/sql/gnc-owner-sql.cpp @@ -169,30 +169,27 @@ load_owner (const GncSqlBackend* be, GncSqlRow* row, } static void -add_owner_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, - GList** pList) +add_owner_col_info_to_list(const GncSqlBackend* be, + const GncSqlColumnTableEntry* table_row, + ColVec& vec) { gchar* buf; g_return_if_fail (be != NULL); g_return_if_fail (table_row != NULL); - g_return_if_fail (pList != NULL); buf = g_strdup_printf ("%s_type", table_row->col_name); - auto info = new GncSqlColumnInfo(buf, BCT_INT, 0, false, false, + GncSqlColumnInfo info(buf, BCT_INT, 0, false, false, table_row->flags & COL_PKEY, table_row->flags & COL_NNUL); - - *pList = g_list_append (*pList, info); + vec.emplace_back(std::move(info)); buf = g_strdup_printf ("%s_guid", table_row->col_name); - info = new GncSqlColumnInfo(buf, BCT_STRING, GUID_ENCODING_LENGTH, + GncSqlColumnInfo info2(buf, BCT_STRING, GUID_ENCODING_LENGTH, false, false, table_row->flags & COL_PKEY, table_row->flags & COL_NNUL); - - *pList = g_list_append (*pList, info); + vec.emplace_back(std::move(info2)); } static void From 96a8a7b99f19aa600840f3b3b391f33c7a39c198 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 12 Mar 2016 11:13:05 -0800 Subject: [PATCH 05/63] Make GncSqlColumnTableEntry arrays into std::vectors. Allows use of range for. --- src/backend/dbi/gnc-backend-dbi.cpp | 30 +- src/backend/sql/gnc-account-sql.cpp | 19 +- src/backend/sql/gnc-address-sql.cpp | 68 ++- src/backend/sql/gnc-backend-sql.cpp | 412 ++++++++---------- src/backend/sql/gnc-backend-sql.h | 132 +++--- src/backend/sql/gnc-bill-term-sql.cpp | 15 +- src/backend/sql/gnc-book-sql.cpp | 3 +- src/backend/sql/gnc-budget-sql.cpp | 15 +- src/backend/sql/gnc-commodity-sql.cpp | 12 +- src/backend/sql/gnc-customer-sql.cpp | 7 +- src/backend/sql/gnc-employee-sql.cpp | 7 +- src/backend/sql/gnc-entry-sql.cpp | 7 +- src/backend/sql/gnc-invoice-sql.cpp | 16 +- src/backend/sql/gnc-job-sql.cpp | 7 +- src/backend/sql/gnc-lots-sql.cpp | 18 +- src/backend/sql/gnc-order-sql.cpp | 16 +- src/backend/sql/gnc-owner-sql.cpp | 40 +- src/backend/sql/gnc-price-sql.cpp | 9 +- src/backend/sql/gnc-recurrence-sql.cpp | 27 +- src/backend/sql/gnc-schedxaction-sql.cpp | 7 +- src/backend/sql/gnc-slots-sql.cpp | 12 +- src/backend/sql/gnc-tax-table-sql.cpp | 37 +- src/backend/sql/gnc-transaction-sql.cpp | 27 +- src/backend/sql/gnc-vendor-sql.cpp | 7 +- .../sql/test/utest-gnc-backend-sql.cpp | 32 +- 25 files changed, 458 insertions(+), 524 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 7e4198160c..85dcdf6612 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -215,7 +215,7 @@ static gboolean save_may_clobber_data (QofBackend* qbe); static gchar* create_index_ddl (GncSqlConnection* conn, const gchar* index_name, const gchar* table_name, - const GncSqlColumnTableEntry* col_table); + const EntryVec& col_table); static gchar* add_columns_ddl (GncSqlConnection* conn, const gchar* table_name, const ColVec& info_vec); @@ -2430,15 +2430,16 @@ stmt_to_sql (GncSqlStatement* stmt) } static void -stmt_add_where_cond (GncSqlStatement* stmt, QofIdTypeConst type_name, - gpointer obj, const GncSqlColumnTableEntry* table_row, GValue* value) +stmt_add_where_cond(GncSqlStatement* stmt, QofIdTypeConst type_name, + gpointer obj, const GncSqlColumnTableEntry& table_row, + GValue* value ) { GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt; gchar* buf; gchar* value_str; value_str = gnc_sql_get_sql_value (dbi_stmt->conn, value); - buf = g_strdup_printf (" WHERE %s = %s", table_row->col_name, + buf = g_strdup_printf (" WHERE %s = %s", table_row.col_name, value_str); g_free (value_str); (void)g_string_append (dbi_stmt->sql, buf); @@ -2660,29 +2661,25 @@ conn_commit_transaction (GncSqlConnection* conn) return success; } -static gchar* -create_index_ddl (GncSqlConnection* conn, - const gchar* index_name, - const gchar* table_name, - const GncSqlColumnTableEntry* col_table) +static gchar* +create_index_ddl (GncSqlConnection* conn, const char* index_name, + const char* table_name, const EntryVec& col_table) { GString* ddl; - const GncSqlColumnTableEntry* table_row; g_return_val_if_fail (conn != NULL, NULL); g_return_val_if_fail (index_name != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); - g_return_val_if_fail (col_table != NULL, NULL); ddl = g_string_new (""); g_string_printf (ddl, "CREATE INDEX %s ON %s (", index_name, table_name); - for (table_row = col_table; table_row->col_name != NULL; ++table_row) + for (auto const& table_row : col_table) { - if (table_row != col_table) + if (table_row != *col_table.begin()) { (void)g_string_append (ddl, ", "); } - g_string_append_printf (ddl, "%s", table_row->col_name); + g_string_append_printf (ddl, "%s", table_row.col_name); } (void)g_string_append (ddl, ")"); @@ -2986,8 +2983,8 @@ conn_create_table (GncSqlConnection* conn, const gchar* table_name, } static gboolean -conn_create_index (GncSqlConnection* conn, const gchar* index_name, - const gchar* table_name, const GncSqlColumnTableEntry* col_table) +conn_create_index(GncSqlConnection* conn, const char* index_name, + const char* table_name, const EntryVec& col_table) { GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; gchar* ddl; @@ -2996,7 +2993,6 @@ conn_create_index (GncSqlConnection* conn, const gchar* index_name, g_return_val_if_fail (conn != NULL, FALSE); g_return_val_if_fail (index_name != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - g_return_val_if_fail (col_table != NULL, FALSE); ddl = create_index_ddl (conn, index_name, table_name, col_table); if (ddl != NULL) diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index 164767be0f..de0fa28f71 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -62,7 +62,7 @@ static void set_parent_guid (gpointer pObject, gpointer pValue); #define ACCOUNT_MAX_CODE_LEN 2048 #define ACCOUNT_MAX_DESCRIPTION_LEN 2048 -static const GncSqlColumnTableEntry col_table[] = +static const EntryVec col_table { { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "name", CT_STRING, ACCOUNT_MAX_NAME_LEN, COL_NNUL, "name" }, @@ -78,13 +78,11 @@ static const GncSqlColumnTableEntry col_table[] = { "description", CT_STRING, ACCOUNT_MAX_DESCRIPTION_LEN, 0, "description" }, { "hidden", CT_BOOLEAN, 0, 0, "hidden" }, { "placeholder", CT_BOOLEAN, 0, 0, "placeholder" }, - { NULL } }; -static GncSqlColumnTableEntry parent_col_table[] = -{ +static EntryVec parent_col_table +({ { "parent_guid", CT_GUID, 0, 0, NULL, NULL, NULL, set_parent_guid }, - { NULL } -}; +}); typedef struct { @@ -403,7 +401,7 @@ gnc_sql_save_account (GncSqlBackend* be, QofInstance* inst) static void load_account_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; GncGUID guid; @@ -412,9 +410,8 @@ load_account_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val != NULL && G_VALUE_HOLDS_STRING (val) && g_value_get_string (val) != NULL) { @@ -422,10 +419,10 @@ load_account_guid (const GncSqlBackend* be, GncSqlRow* row, account = xaccAccountLookup (&guid, be->book); if (account != NULL) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, account, NULL); + g_object_set (pObject, table_row.gobj_param_name, account, NULL); qof_instance_decrease_editlevel (pObject); } else diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index 94f715316c..cd793007ec 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -50,8 +50,8 @@ G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN; #define ADDRESS_MAX_FAX_LEN 128 #define ADDRESS_MAX_EMAIL_LEN 256 -static GncSqlColumnTableEntry col_table[] = -{ +static EntryVec col_table +({ { "name", CT_STRING, ADDRESS_MAX_NAME_LEN, COL_NNUL, "name" }, { "addr1", CT_STRING, ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr1" }, { "addr2", CT_STRING, ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr2" }, @@ -60,8 +60,7 @@ static GncSqlColumnTableEntry col_table[] = { "phone", CT_STRING, ADDRESS_MAX_PHONE_LEN, COL_NNUL, "phone" }, { "fax", CT_STRING, ADDRESS_MAX_FAX_LEN, COL_NNUL, "fax" }, { "email", CT_STRING, ADDRESS_MAX_EMAIL_LEN, COL_NNUL, "email" }, - { NULL } -}; +}); typedef void (*AddressSetterFunc) (gpointer, GncAddress*); typedef GncAddress* (*AddressGetterFunc) (const gpointer); @@ -69,24 +68,24 @@ typedef GncAddress* (*AddressGetterFunc) (const gpointer); static void load_address (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; gchar* buf; GncAddress* addr; AddressSetterFunc a_setter = (AddressSetterFunc)setter; - const GncSqlColumnTableEntry* subtable; const gchar* s; + g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); addr = gncAddressCreate (be->book, QOF_INSTANCE(pObject)); - for (subtable = col_table; subtable->col_name != NULL; subtable++) + for (auto const& subtable_row : col_table) { - buf = g_strdup_printf ("%s_%s", table_row->col_name, subtable->col_name); + buf = g_strdup_printf ("%s_%s", table_row.col_name, + subtable_row.col_name); val = gnc_sql_row_get_value_at_col_name (row, buf); g_free (buf); if (val == NULL) @@ -97,28 +96,28 @@ load_address (const GncSqlBackend* be, GncSqlRow* row, { s = g_value_get_string (val); } - if (subtable->gobj_param_name != NULL) + if (subtable_row.gobj_param_name != NULL) { - g_object_set (addr, subtable->gobj_param_name, s, NULL); + g_object_set (addr, subtable_row.gobj_param_name, s, NULL); } else { - if (subtable->qof_param_name != NULL) + if (subtable_row.qof_param_name != NULL) { setter = qof_class_get_parameter_setter (GNC_ID_ADDRESS, - subtable->qof_param_name); + subtable_row.qof_param_name); } else { - setter = subtable->setter; + setter = subtable_row.setter; } (*setter) (addr, (const gpointer)s); } } - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, addr, NULL); + g_object_set (pObject, table_row.gobj_param_name, addr, NULL); qof_instance_decrease_editlevel (pObject); } else @@ -129,29 +128,27 @@ load_address (const GncSqlBackend* be, GncSqlRow* row, static void add_address_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { GncSqlColumnInfo* info; gchar* buf; - const GncSqlColumnTableEntry* subtable_row; g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); - for (subtable_row = col_table; subtable_row->col_name != NULL; subtable_row++) + for (auto const& subtable_row : col_table) { - buf = g_strdup_printf ("%s_%s", table_row->col_name, subtable_row->col_name); + buf = g_strdup_printf ("%s_%s", table_row.col_name, subtable_row.col_name); - GncSqlColumnInfo info(buf, BCT_STRING, subtable_row->size, true, false, - table_row->flags & COL_PKEY, - table_row->flags & COL_NNUL); + GncSqlColumnInfo info(buf, BCT_STRING, subtable_row.size, true, false, + table_row.flags & COL_PKEY, + table_row.flags & COL_NNUL); vec.emplace_back(std::move(info)); } } static void -add_address_colname_to_list (const GncSqlColumnTableEntry* table_row, +add_address_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pList) { gnc_sql_add_subtable_colnames_to_list (table_row, col_table, pList); @@ -160,7 +157,7 @@ add_address_colname_to_list (const GncSqlColumnTableEntry* table_row, static void get_gvalue_address (const GncSqlBackend* be, QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry* table_row, GValue* value) + const GncSqlColumnTableEntry& table_row, GValue* value) { AddressGetterFunc getter; GncAddress* addr; @@ -168,13 +165,11 @@ get_gvalue_address (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - g_return_if_fail (value != NULL); memset (value, 0, sizeof (GValue)); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { - g_object_get (pObject, table_row->gobj_param_name, &addr, NULL); + g_object_get (pObject, table_row.gobj_param_name, &addr, NULL); } else { @@ -187,7 +182,8 @@ get_gvalue_address (const GncSqlBackend* be, QofIdTypeConst obj_name, static void add_gvalue_address_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { GValue value; @@ -195,25 +191,23 @@ add_gvalue_address_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, GncAddress* addr; gchar* s; QofAccessFunc getter; - const GncSqlColumnTableEntry* subtable_row; g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); memset (&value, 0, sizeof (GValue)); get_gvalue_address (be, obj_name, pObject, table_row, &value); if (G_VALUE_TYPE (&value) != 0) { - addr = static_cast (g_value_get_object (&value)); - for (subtable_row = col_table; subtable_row->col_name != NULL; subtable_row++) + addr = static_cast(g_value_get_object(&value)); + for (auto const& subtable_row : col_table) { subfield_value = g_new0 (GValue, 1); - if (subtable_row->gobj_param_name != NULL) + if (subtable_row.gobj_param_name != NULL) { - g_object_get (addr, subtable_row->gobj_param_name, &s, NULL); + g_object_get (addr, subtable_row.gobj_param_name, &s, NULL); } else { diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 23c0b95ea1..228cb0fe4e 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -91,15 +91,15 @@ static gboolean reset_version_info (GncSqlBackend* be); static GncSqlStatement* build_insert_statement (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table); + const EntryVec& table); static GncSqlStatement* build_update_statement (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table); + const EntryVec& table); static GncSqlStatement* build_delete_statement (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table); + const EntryVec& table); static GList* post_load_commodities = NULL; @@ -1155,25 +1155,24 @@ set_autoinc_id (void* object, void* item) QofAccessFunc gnc_sql_get_getter (QofIdTypeConst obj_name, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { QofAccessFunc getter; g_return_val_if_fail (obj_name != NULL, NULL); - g_return_val_if_fail (table_row != NULL, NULL); - if ((table_row->flags & COL_AUTOINC) != 0) + if (table_row.flags & COL_AUTOINC) { getter = get_autoinc_id; } - else if (table_row->qof_param_name != NULL) + else if (table_row.qof_param_name != NULL) { getter = qof_class_get_parameter_getter (obj_name, - table_row->qof_param_name); + table_row.qof_param_name); } else { - getter = table_row->getter; + getter = table_row.getter; } return getter; @@ -1181,32 +1180,30 @@ gnc_sql_get_getter (QofIdTypeConst obj_name, /* ----------------------------------------------------------------- */ void -gnc_sql_add_colname_to_list (const GncSqlColumnTableEntry* table_row, +gnc_sql_add_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pList) { - (*pList) = g_list_append ((*pList), g_strdup (table_row->col_name)); + (*pList) = g_list_append ((*pList), g_strdup (table_row.col_name)); } /* ----------------------------------------------------------------- */ void -gnc_sql_add_subtable_colnames_to_list (const GncSqlColumnTableEntry* table_row, - const GncSqlColumnTableEntry* subtable, - GList** pList) +gnc_sql_add_subtable_colnames_to_list (const GncSqlColumnTableEntry& table_row, + const EntryVec& subtable, + GList** pList ) { - const GncSqlColumnTableEntry* subtable_row; - gchar* buf; - - for (subtable_row = subtable; subtable_row->col_name != NULL; subtable_row++) + for (auto const& subtable_row : subtable) { - buf = g_strdup_printf ("%s_%s", table_row->col_name, subtable_row->col_name); - (*pList) = g_list_append ((*pList), buf); + char* buf = g_strdup_printf ("%s_%s", + table_row.col_name, subtable_row.col_name); + *pList = g_list_append (*pList, buf); } } /* ----------------------------------------------------------------- */ static void load_string (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; const gchar* s; @@ -1214,19 +1211,19 @@ load_string (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - g_return_if_fail (table_row->gobj_param_name != NULL || setter != NULL); + g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); g_return_if_fail (val != NULL); s = g_value_get_string (val); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row->gobj_param_name, s, NULL); + g_object_set (pObject, table_row.gobj_param_name, s, NULL); if (QOF_IS_INSTANCE (pObject)) qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); + } else { @@ -1237,19 +1234,19 @@ load_string (const GncSqlBackend* be, GncSqlRow* row, static void add_string_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); - GncSqlColumnInfo info{table_row, BCT_STRING, table_row->size, TRUE}; + GncSqlColumnInfo info{table_row, BCT_STRING, table_row.size, TRUE}; vec.emplace_back(std::move(info)); } static void add_gvalue_string_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { QofAccessFunc getter; @@ -1259,15 +1256,14 @@ add_gvalue_string_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); value = g_new0 (GValue, 1); g_assert (value != NULL); memset (value, 0, sizeof (GValue)); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { - g_object_get (pObject, table_row->gobj_param_name, &s, NULL); + g_object_get (pObject, table_row.gobj_param_name, &s, NULL); } else { @@ -1305,7 +1301,7 @@ typedef void (*IntSetterFunc) (const gpointer, gint); static void load_int (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; gint int_value; @@ -1314,10 +1310,9 @@ load_int (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - g_return_if_fail (table_row->gobj_param_name != NULL || setter != NULL); + g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val == NULL) { int_value = 0; @@ -1326,11 +1321,11 @@ load_int (const GncSqlBackend* be, GncSqlRow* row, { int_value = (gint)gnc_sql_get_integer_value (val); } - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row->gobj_param_name, int_value, NULL); + g_object_set (pObject, table_row.gobj_param_name, int_value, NULL); if (QOF_IS_INSTANCE (pObject)) qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } @@ -1344,11 +1339,10 @@ load_int (const GncSqlBackend* be, GncSqlRow* row, static void add_int_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); GncSqlColumnInfo info{table_row, BCT_INT, 0, FALSE}; vec.emplace_back(std::move(info)); @@ -1356,7 +1350,8 @@ add_int_col_info_to_list(const GncSqlBackend* be, static void add_gvalue_int_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { gint int_value = 0; @@ -1366,16 +1361,15 @@ add_gvalue_int_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); value = g_new0 (GValue, 1); g_assert (value != NULL); (void)g_value_init (value, G_TYPE_INT); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { - g_object_get_property (G_OBJECT (pObject), table_row->gobj_param_name, + g_object_get_property (G_OBJECT (pObject), table_row.gobj_param_name, value); } else @@ -1406,7 +1400,7 @@ typedef void (*BooleanSetterFunc) (const gpointer, gboolean); static void load_boolean (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; gint int_value; @@ -1415,10 +1409,9 @@ load_boolean (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - g_return_if_fail (table_row->gobj_param_name != NULL || setter != NULL); + g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val == NULL) { int_value = 0; @@ -1427,13 +1420,13 @@ load_boolean (const GncSqlBackend* be, GncSqlRow* row, { int_value = (gint)gnc_sql_get_integer_value (val); } - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != nullptr) { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row->gobj_param_name, int_value, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); + g_object_set (pObject, table_row.gobj_param_name, int_value, nullptr); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } else { @@ -1445,11 +1438,10 @@ load_boolean (const GncSqlBackend* be, GncSqlRow* row, static void add_boolean_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); GncSqlColumnInfo info{table_row, BCT_INT, 0, FALSE}; vec.emplace_back(std::move(info)); @@ -1457,7 +1449,8 @@ add_boolean_col_info_to_list(const GncSqlBackend* be, static void add_gvalue_boolean_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { gint int_value = 0; @@ -1467,15 +1460,14 @@ add_gvalue_boolean_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); value = g_new0 (GValue, 1); g_assert (value != NULL); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != nullptr) { - g_object_get (pObject, table_row->gobj_param_name, &int_value, NULL); + g_object_get (pObject, table_row.gobj_param_name, &int_value, NULL); } else { @@ -1506,7 +1498,7 @@ typedef void (*Int64SetterFunc) (const gpointer, gint64); static void load_int64 (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; gint64 i64_value = 0; @@ -1514,19 +1506,19 @@ load_int64 (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); - g_return_if_fail (table_row != NULL); - g_return_if_fail (table_row->gobj_param_name != NULL || setter != NULL); + g_return_if_fail (table_row.gobj_param_name != nullptr || + setter != nullptr); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val != NULL) { i64_value = gnc_sql_get_integer_value (val); } - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != nullptr) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row->gobj_param_name, i64_value, NULL); + g_object_set (pObject, table_row.gobj_param_name, i64_value, nullptr); if (QOF_IS_INSTANCE (pObject)) qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } @@ -1538,11 +1530,10 @@ load_int64 (const GncSqlBackend* be, GncSqlRow* row, static void add_int64_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); GncSqlColumnInfo info{table_row, BCT_INT64, 0, FALSE}; vec.emplace_back(std::move(info)); @@ -1550,7 +1541,8 @@ add_int64_col_info_to_list(const GncSqlBackend* be, static void add_gvalue_int64_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { gint64 i64_value = 0; @@ -1560,14 +1552,13 @@ add_gvalue_int64_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); value = g_new0 (GValue, 1); g_assert (value != NULL); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != nullptr) { - g_object_get (pObject, table_row->gobj_param_name, &i64_value, NULL); + g_object_get (pObject, table_row.gobj_param_name, &i64_value, NULL); } else { @@ -1596,7 +1587,7 @@ static GncSqlColumnTypeHandler int64_handler static void load_double (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; gdouble d_value; @@ -1604,10 +1595,10 @@ load_double (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - g_return_if_fail (table_row->gobj_param_name != NULL || setter != NULL); + g_return_if_fail (table_row.gobj_param_name != nullptr || + setter != nullptr); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val == NULL) { (*setter) (pObject, (gpointer)NULL); @@ -1631,11 +1622,11 @@ load_double (const GncSqlBackend* be, GncSqlRow* row, PWARN ("Unknown float value type: %s\n", g_type_name (G_VALUE_TYPE (val))); d_value = 0; } - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row->gobj_param_name, d_value, NULL); + g_object_set (pObject, table_row.gobj_param_name, d_value, NULL); if (QOF_IS_INSTANCE (pObject)) qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } @@ -1648,11 +1639,10 @@ load_double (const GncSqlBackend* be, GncSqlRow* row, static void add_double_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); GncSqlColumnInfo info{table_row, BCT_DOUBLE, 0, FALSE}; vec.emplace_back(std::move(info)); @@ -1660,7 +1650,8 @@ add_double_col_info_to_list(const GncSqlBackend* be, static void add_gvalue_double_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { QofAccessFunc getter; @@ -1671,7 +1662,6 @@ add_gvalue_double_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); value = g_new0 (GValue, 1); g_assert (value != NULL); @@ -1708,7 +1698,7 @@ static GncSqlColumnTypeHandler double_handler static void load_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; GncGUID guid; @@ -1717,10 +1707,10 @@ load_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - g_return_if_fail (table_row->gobj_param_name != NULL || setter != NULL); + g_return_if_fail (table_row.gobj_param_name != nullptr || + setter != nullptr); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val == NULL || g_value_get_string (val) == NULL) { pGuid = NULL; @@ -1732,11 +1722,11 @@ load_guid (const GncSqlBackend* be, GncSqlRow* row, } if (pGuid != NULL) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row->gobj_param_name, pGuid, NULL); + g_object_set (pObject, table_row.gobj_param_name, pGuid, NULL); if (QOF_IS_INSTANCE (pObject)) qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } @@ -1750,11 +1740,10 @@ load_guid (const GncSqlBackend* be, GncSqlRow* row, static void add_guid_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); GncSqlColumnInfo info{table_row, BCT_STRING, GUID_ENCODING_LENGTH, FALSE}; vec.emplace_back(std::move(info)); @@ -1762,7 +1751,8 @@ add_guid_col_info_to_list(const GncSqlBackend* be, static void add_gvalue_guid_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { QofAccessFunc getter; @@ -1773,13 +1763,12 @@ add_gvalue_guid_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); value = g_new0 (GValue, 1); g_assert (value != NULL); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { - g_object_get (pObject, table_row->gobj_param_name, &guid, NULL); + g_object_get (pObject, table_row.gobj_param_name, &guid, NULL); } else { @@ -1813,7 +1802,8 @@ static GncSqlColumnTypeHandler guid_handler void gnc_sql_add_gvalue_objectref_guid_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { QofAccessFunc getter; @@ -1825,13 +1815,12 @@ gnc_sql_add_gvalue_objectref_guid_to_slist (const GncSqlBackend* be, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); value = g_new0 (GValue, 1); g_assert (value != NULL); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { - g_object_get (pObject, table_row->gobj_param_name, &inst, NULL); + g_object_get (pObject, table_row.gobj_param_name, &inst, NULL); } else { @@ -1857,7 +1846,7 @@ gnc_sql_add_gvalue_objectref_guid_to_slist (const GncSqlBackend* be, void gnc_sql_add_objectref_guid_col_info_to_list( const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& info_vec) { add_guid_col_info_to_list(be, table_row, info_vec); @@ -1897,7 +1886,7 @@ gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, Timespec ts) static void load_timespec (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; Timespec ts = {0, 0}; @@ -1907,11 +1896,11 @@ load_timespec (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - g_return_if_fail (table_row->gobj_param_name != NULL || setter != NULL); + g_return_if_fail (table_row.gobj_param_name != nullptr || + setter != nullptr); ts_setter = (TimespecSetterFunc)setter; - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val == NULL) { isOK = TRUE; @@ -1948,11 +1937,11 @@ load_timespec (const GncSqlBackend* be, GncSqlRow* row, } if (isOK) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row->gobj_param_name, &ts, NULL); + g_object_set (pObject, table_row.gobj_param_name, &ts, NULL); if (QOF_IS_INSTANCE (pObject)) qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } @@ -1965,11 +1954,10 @@ load_timespec (const GncSqlBackend* be, GncSqlRow* row, static void add_timespec_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); GncSqlColumnInfo info{table_row, BCT_DATETIME, TIMESPEC_COL_SIZE, FALSE}; vec.emplace_back(std::move(info)); @@ -1977,7 +1965,8 @@ add_timespec_col_info_to_list(const GncSqlBackend* be, static void add_gvalue_timespec_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { TimespecAccessFunc ts_getter; @@ -1988,13 +1977,12 @@ add_gvalue_timespec_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); g_return_if_fail (pList != NULL); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { Timespec* pts; - g_object_get (pObject, table_row->gobj_param_name, &pts, NULL); + g_object_get (pObject, table_row.gobj_param_name, &pts, NULL); ts = *pts; } else @@ -2030,17 +2018,17 @@ static GncSqlColumnTypeHandler timespec_handler static void load_date (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - g_return_if_fail (table_row->gobj_param_name != NULL || setter != NULL); + g_return_if_fail (table_row.gobj_param_name != nullptr || + setter != nullptr); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val != NULL) { if (G_VALUE_HOLDS_INT64 (val)) @@ -2057,11 +2045,11 @@ load_date (const GncSqlBackend* be, GncSqlRow* row, static_cast(tm->tm_mon + 1), tm->tm_year + 1900); free(tm); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row->gobj_param_name, &date, NULL); + g_object_set (pObject, table_row.gobj_param_name, &date, NULL); if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); } @@ -2094,11 +2082,11 @@ load_date (const GncSqlBackend* be, GncSqlRow* row, if (year != 0 || month != 0 || day != (GDateDay)0) { date = g_date_new_dmy (day, month, year); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row->gobj_param_name, + g_object_set (pObject, table_row.gobj_param_name, date, NULL); if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); @@ -2120,11 +2108,10 @@ load_date (const GncSqlBackend* be, GncSqlRow* row, static void add_date_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); GncSqlColumnInfo info{table_row, BCT_DATE, DATE_COL_SIZE, FALSE}; vec.emplace_back(std::move(info)); @@ -2133,7 +2120,8 @@ add_date_col_info_to_list (const GncSqlBackend* be, static void add_gvalue_date_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry* table_row, GSList** pList) + const GncSqlColumnTableEntry& table_row, + GSList** pList) { GDate* date = NULL; QofAccessFunc getter; @@ -2143,14 +2131,13 @@ add_gvalue_date_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); value = g_new0 (GValue, 1); g_assert (value != NULL); (void)g_value_init (value, G_TYPE_STRING); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { - g_object_get (pObject, table_row->gobj_param_name, &date, NULL); + g_object_get (pObject, table_row.gobj_param_name, &date, NULL); } else { @@ -2182,17 +2169,16 @@ static GncSqlColumnTypeHandler date_handler typedef gnc_numeric (*NumericGetterFunc) (const gpointer); typedef void (*NumericSetterFunc) (gpointer, gnc_numeric); -static const GncSqlColumnTableEntry numeric_col_table[] = +static const EntryVec numeric_col_table = { { "num", CT_INT64, 0, COL_NNUL, "guid" }, { "denom", CT_INT64, 0, COL_NNUL, "guid" }, - { NULL } }; static void load_numeric (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; gchar* buf; @@ -2203,10 +2189,10 @@ load_numeric (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - g_return_if_fail (table_row->gobj_param_name != NULL || setter != NULL); + g_return_if_fail (table_row.gobj_param_name != nullptr || + setter != nullptr); - buf = g_strdup_printf ("%s_num", table_row->col_name); + buf = g_strdup_printf ("%s_num", table_row.col_name); val = gnc_sql_row_get_value_at_col_name (row, buf); g_free (buf); if (val == NULL) @@ -2218,7 +2204,7 @@ load_numeric (const GncSqlBackend* be, GncSqlRow* row, { num = gnc_sql_get_integer_value (val); } - buf = g_strdup_printf ("%s_denom", table_row->col_name); + buf = g_strdup_printf ("%s_denom", table_row.col_name); val = gnc_sql_row_get_value_at_col_name (row, buf); g_free (buf); if (val == NULL) @@ -2233,11 +2219,11 @@ load_numeric (const GncSqlBackend* be, GncSqlRow* row, n = gnc_numeric_create (num, denom); if (!isNull) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != nullptr) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row->gobj_param_name, &n, NULL); + g_object_set (pObject, table_row.gobj_param_name, &n, NULL); if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); } @@ -2251,28 +2237,24 @@ load_numeric (const GncSqlBackend* be, GncSqlRow* row, static void add_numeric_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { - gchar* buf; - const GncSqlColumnTableEntry* subtable_row; - g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); - for (subtable_row = numeric_col_table; subtable_row->col_name != NULL; - subtable_row++) + for (auto const& subtable_row : numeric_col_table) { - buf = g_strdup_printf("%s_%s", table_row->col_name, subtable_row->col_name); + gchar* buf = g_strdup_printf("%s_%s", table_row.col_name, + subtable_row.col_name); GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false, - table_row->flags & COL_PKEY, - table_row->flags & COL_NNUL); + table_row.flags & COL_PKEY, + table_row.flags & COL_NNUL); vec.emplace_back(std::move(info)); } } static void -add_numeric_colname_to_list (const GncSqlColumnTableEntry* table_row, +add_numeric_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pList) { gnc_sql_add_subtable_colnames_to_list (table_row, numeric_col_table, pList); @@ -2280,7 +2262,8 @@ add_numeric_colname_to_list (const GncSqlColumnTableEntry* table_row, static void add_gvalue_numeric_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { NumericGetterFunc getter; @@ -2291,12 +2274,11 @@ add_gvalue_numeric_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != nullptr) { gnc_numeric* s; - g_object_get (pObject, table_row->gobj_param_name, &s, NULL); + g_object_get (pObject, table_row.gobj_param_name, &s, NULL); n = *s; } else @@ -2353,17 +2335,16 @@ gnc_sql_register_col_type_handler (const gchar* colType, } static GncSqlColumnTypeHandler* -get_handler (const GncSqlColumnTableEntry* table_row) +get_handler (const GncSqlColumnTableEntry& table_row) { GncSqlColumnTypeHandler* pHandler; - g_return_val_if_fail (table_row != NULL, NULL); - g_return_val_if_fail (table_row->col_type != NULL, NULL); + g_return_val_if_fail (table_row.col_type != NULL, NULL); if (g_columnTypeHash != NULL) { - pHandler = static_cast ( - g_hash_table_lookup (g_columnTypeHash, table_row->col_type)); + pHandler = static_cast( + g_hash_table_lookup (g_columnTypeHash, table_row.col_type)); g_assert (pHandler != NULL); } else @@ -2402,10 +2383,9 @@ _retrieve_guid_ (gpointer pObject, gpointer pValue) // Table to retrieve just the guid -static GncSqlColumnTableEntry guid_table[] = +static EntryVec guid_table { { "guid", CT_GUID, 0, 0, NULL, NULL, NULL, _retrieve_guid_ }, - { NULL } }; const GncGUID* @@ -2422,11 +2402,10 @@ gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow* row) } // Table to retrieve just the guid -static GncSqlColumnTableEntry tx_guid_table[] = +static EntryVec tx_guid_table { - { "tx_guid", CT_GUID, 0, 0, NULL, NULL, NULL, _retrieve_guid_ }, - { NULL } -}; + { "tx_guid", CT_GUID, 0, 0, NULL, NULL, NULL, _retrieve_guid_ }, + }; const GncGUID* @@ -2445,32 +2424,30 @@ gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow* row) void gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow* row, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table) + const EntryVec& table) { QofSetterFunc setter; GncSqlColumnTypeHandler* pHandler; - const GncSqlColumnTableEntry* table_row; g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table != NULL); - for (table_row = table; table_row->col_name != NULL; table_row++) + for (auto const& table_row : table) { - if ((table_row->flags & COL_AUTOINC) != 0) + if (table_row.flags & COL_AUTOINC) { setter = set_autoinc_id; } - else if (table_row->qof_param_name != NULL) + else if (table_row.qof_param_name != nullptr) { g_assert (obj_name != NULL); setter = qof_class_get_parameter_setter (obj_name, - table_row->qof_param_name); + table_row.qof_param_name); } else { - setter = table_row->setter; + setter = table_row.setter; } pHandler = get_handler (table_row); g_assert (pHandler != NULL); @@ -2497,16 +2474,15 @@ gnc_sql_create_select_statement (GncSqlBackend* be, const gchar* table_name) static GncSqlStatement* create_single_col_select_statement (GncSqlBackend* be, const gchar* table_name, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { gchar* sql; GncSqlStatement* stmt; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); - g_return_val_if_fail (table_row != NULL, NULL); - sql = g_strdup_printf ("SELECT %s FROM %s", table_row->col_name, table_name); + sql = g_strdup_printf ("SELECT %s FROM %s", table_row.col_name, table_name); stmt = gnc_sql_create_statement_from_sql (be, sql); g_free (sql); return stmt; @@ -2646,7 +2622,7 @@ gnc_sql_append_guid_list_to_sql (GString* sql, GList* list, guint maxCount) gboolean gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table) + const EntryVec& table) { GncSqlStatement* sqlStmt; guint count; @@ -2657,18 +2633,17 @@ gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, g_return_val_if_fail (table_name != NULL, FALSE); g_return_val_if_fail (obj_name != NULL, FALSE); g_return_val_if_fail (pObject != NULL, FALSE); - g_return_val_if_fail (table != NULL, FALSE); /* SELECT * FROM */ - sqlStmt = create_single_col_select_statement (be, table_name, table); + sqlStmt = create_single_col_select_statement (be, table_name, table[0]); g_assert (sqlStmt != NULL); /* WHERE */ - pHandler = get_handler (table); + pHandler = get_handler (table[0]); g_assert (pHandler != NULL); - pHandler->add_gvalue_to_slist_fn (be, obj_name, pObject, table, &list); + pHandler->add_gvalue_to_slist_fn (be, obj_name, pObject, table[0], &list); g_assert (list != NULL); - gnc_sql_statement_add_where_cond (sqlStmt, obj_name, pObject, &table[0], + gnc_sql_statement_add_where_cond (sqlStmt, obj_name, pObject, table[0], (GValue*) (list->data)); count = execute_statement_get_count (be, sqlStmt); @@ -2688,7 +2663,7 @@ gnc_sql_do_db_operation (GncSqlBackend* be, E_DB_OPERATION op, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table) + const EntryVec& table) { GncSqlStatement* stmt = NULL; gboolean ok = FALSE; @@ -2697,7 +2672,6 @@ gnc_sql_do_db_operation (GncSqlBackend* be, g_return_val_if_fail (table_name != NULL, FALSE); g_return_val_if_fail (obj_name != NULL, FALSE); g_return_val_if_fail (pObject != NULL, FALSE); - g_return_val_if_fail (table != NULL, FALSE); if (op == OP_DB_INSERT) { @@ -2738,15 +2712,14 @@ gnc_sql_do_db_operation (GncSqlBackend* be, static GSList* create_gslist_from_values (GncSqlBackend* be, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table) + const EntryVec& table ) { GSList* list = NULL; GncSqlColumnTypeHandler* pHandler; - const GncSqlColumnTableEntry* table_row; - for (table_row = table; table_row->col_name != NULL; table_row++) + for (auto const& table_row : table) { - if ((table_row->flags & COL_AUTOINC) == 0) + if (!(table_row.flags & COL_AUTOINC)) { pHandler = get_handler (table_row); g_assert (pHandler != NULL); @@ -2847,7 +2820,7 @@ static GncSqlStatement* build_insert_statement (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table) + const EntryVec& table) { GncSqlStatement* stmt; GString* sql; @@ -2856,22 +2829,20 @@ build_insert_statement (GncSqlBackend* be, gchar* sqlbuf; GList* colnames = NULL; GList* colname; - const GncSqlColumnTableEntry* table_row; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); g_return_val_if_fail (obj_name != NULL, NULL); g_return_val_if_fail (pObject != NULL, NULL); - g_return_val_if_fail (table != NULL, NULL); sqlbuf = g_strdup_printf ("INSERT INTO %s(", table_name); sql = g_string_new (sqlbuf); g_free (sqlbuf); // Get all col names and all values - for (table_row = table; table_row->col_name != NULL; table_row++) + for (auto const& table_row : table) { - if ((table_row->flags & COL_AUTOINC) == 0) + if (!(table_row.flags & COL_AUTOINC)) { GncSqlColumnTypeHandler* pHandler; @@ -2922,7 +2893,7 @@ static GncSqlStatement* build_update_statement (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table) + const EntryVec& table) { GncSqlStatement* stmt; GString* sql; @@ -2931,19 +2902,17 @@ build_update_statement (GncSqlBackend* be, GSList* value; GList* colname; gboolean firstCol; - const GncSqlColumnTableEntry* table_row; gchar* sqlbuf; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); g_return_val_if_fail (obj_name != NULL, NULL); g_return_val_if_fail (pObject != NULL, NULL); - g_return_val_if_fail (table != NULL, NULL); // Get all col names and all values - for (table_row = table; table_row->col_name != NULL; table_row++) + for (auto const& table_row : table) { - if ((table_row->flags & COL_AUTOINC) == 0) + if (!(table_row.flags & COL_AUTOINC)) { GncSqlColumnTypeHandler* pHandler; @@ -2989,7 +2958,7 @@ build_update_statement (GncSqlBackend* be, } stmt = gnc_sql_connection_create_statement_from_sql (be->conn, sql->str); - gnc_sql_statement_add_where_cond (stmt, obj_name, pObject, &table[0], + gnc_sql_statement_add_where_cond (stmt, obj_name, pObject, table[0], (GValue*) (values->data)); free_gvalue_list (values); (void)g_string_free (sql, TRUE); @@ -3001,7 +2970,7 @@ static GncSqlStatement* build_delete_statement (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table) + const EntryVec& table) { GncSqlStatement* stmt; GncSqlColumnTypeHandler* pHandler; @@ -3012,18 +2981,17 @@ build_delete_statement (GncSqlBackend* be, g_return_val_if_fail (table_name != NULL, NULL); g_return_val_if_fail (obj_name != NULL, NULL); g_return_val_if_fail (pObject != NULL, NULL); - g_return_val_if_fail (table != NULL, NULL); sqlbuf = g_strdup_printf ("DELETE FROM %s ", table_name); stmt = gnc_sql_connection_create_statement_from_sql (be->conn, sqlbuf); g_free (sqlbuf); /* WHERE */ - pHandler = get_handler (table); + pHandler = get_handler (table[0]); g_assert (pHandler != NULL); - pHandler->add_gvalue_to_slist_fn (be, obj_name, pObject, table, &list); + pHandler->add_gvalue_to_slist_fn (be, obj_name, pObject, table[0], &list); g_assert (list != NULL); - gnc_sql_statement_add_where_cond (stmt, obj_name, pObject, &table[0], + gnc_sql_statement_add_where_cond (stmt, obj_name, pObject, table[0], (GValue*) (list->data)); free_gvalue_list (list); @@ -3033,8 +3001,8 @@ build_delete_statement (GncSqlBackend* be, /* ================================================================= */ gboolean gnc_sql_commit_standard_item (GncSqlBackend* be, QofInstance* inst, - const gchar* tableName, - QofIdTypeConst obj_name, const GncSqlColumnTableEntry* col_table) + const gchar* tableName, QofIdTypeConst obj_name, + const EntryVec& col_table) { const GncGUID* guid; gboolean is_infant; @@ -3077,36 +3045,32 @@ gnc_sql_commit_standard_item (GncSqlBackend* be, QofInstance* inst, static gboolean do_create_table (const GncSqlBackend* be, const gchar* table_name, - const GncSqlColumnTableEntry* col_table) + const EntryVec& col_table) { ColVec info_vec; gboolean ok = FALSE; g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - g_return_val_if_fail (col_table != NULL, FALSE); - for (; col_table->col_name != NULL; col_table++) + for (auto const& table_row : col_table) { - GncSqlColumnTypeHandler* pHandler; - - pHandler = get_handler (col_table); + GncSqlColumnTypeHandler* pHandler = get_handler (table_row); g_assert (pHandler != NULL); - pHandler->add_col_info_to_list_fn (be, col_table, info_vec); + pHandler->add_col_info_to_list_fn (be, table_row, info_vec); } ok = gnc_sql_connection_create_table (be->conn, table_name, info_vec); return ok; } gboolean -gnc_sql_create_table (GncSqlBackend* be, const gchar* table_name, - gint table_version, const GncSqlColumnTableEntry* col_table) +gnc_sql_create_table (GncSqlBackend* be, const char* table_name, + gint table_version, const EntryVec& col_table) { gboolean ok; g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - g_return_val_if_fail (col_table != NULL, FALSE); DEBUG ("Creating %s table\n", table_name); @@ -3120,11 +3084,10 @@ gnc_sql_create_table (GncSqlBackend* be, const gchar* table_name, gboolean gnc_sql_create_temp_table (const GncSqlBackend* be, const gchar* table_name, - const GncSqlColumnTableEntry* col_table) + const EntryVec& col_table) { g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - g_return_val_if_fail (col_table != NULL, FALSE); return do_create_table (be, table_name, col_table); } @@ -3132,14 +3095,13 @@ gnc_sql_create_temp_table (const GncSqlBackend* be, const gchar* table_name, gboolean gnc_sql_create_index (const GncSqlBackend* be, const gchar* index_name, const gchar* table_name, - const GncSqlColumnTableEntry* col_table) + const EntryVec& col_table) { gboolean ok; g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (index_name != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - g_return_val_if_fail (col_table != NULL, FALSE); ok = gnc_sql_connection_create_index (be->conn, index_name, table_name, col_table); @@ -3165,14 +3127,13 @@ gnc_sql_get_table_version (const GncSqlBackend* be, const gchar* table_name) old table, then rename the new one. */ void gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name, - const GncSqlColumnTableEntry* col_table) + const EntryVec& col_table) { gchar* sql; gchar* temp_table_name; g_return_if_fail (be != NULL); g_return_if_fail (table_name != NULL); - g_return_if_fail (col_table != NULL); DEBUG ("Upgrading %s table\n", table_name); @@ -3195,24 +3156,22 @@ gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name, } /* Adds one or more columns to an existing table. */ -gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, - const gchar* table_name, - const GncSqlColumnTableEntry* new_col_table) +gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const gchar* table_name, + const EntryVec& new_col_table) { ColVec info_vec; gboolean ok = FALSE; g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - g_return_val_if_fail (new_col_table != NULL, FALSE); - for (; new_col_table->col_name != NULL; new_col_table++) + for (auto const& table_row : new_col_table) { GncSqlColumnTypeHandler* pHandler; - pHandler = get_handler (new_col_table); + pHandler = get_handler (table_row); g_assert (pHandler != NULL); - pHandler->add_col_info_to_list_fn (be, new_col_table, info_vec); + pHandler->add_col_info_to_list_fn (be, table_row, info_vec); } ok = gnc_sql_connection_add_columns_to_table(be->conn, table_name, info_vec); return ok; @@ -3224,11 +3183,10 @@ gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, #define TABLE_COL_NAME "table_name" #define VERSION_COL_NAME "table_version" -static GncSqlColumnTableEntry version_table[] = +static EntryVec version_table { { TABLE_COL_NAME, CT_STRING, MAX_TABLE_NAME_LEN, COL_PKEY | COL_NNUL }, { VERSION_COL_NAME, CT_INT, 0, COL_NNUL }, - { NULL } }; /** diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index df88bdfb9e..e2d0b82764 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -52,7 +52,8 @@ extern "C" #include struct GncSqlColumnInfo; - +struct GncSqlColumnTableEntry; +using EntryVec = std::vector; using ColVec = std::vector; using LoadOrder = std::vector; typedef struct GncSqlConnection GncSqlConnection; @@ -137,7 +138,6 @@ void gnc_sql_commit_edit (GncSqlBackend* qbe, QofInstance* inst); /** */ -typedef struct GncSqlColumnTableEntry GncSqlColumnTableEntry; typedef struct GncSqlStatement GncSqlStatement; typedef struct GncSqlResult GncSqlResult; typedef struct GncSqlRow GncSqlRow; @@ -153,7 +153,7 @@ struct GncSqlStatement void (*dispose) (GncSqlStatement*); gchar* (*toSql) (GncSqlStatement*); void (*addWhereCond) (GncSqlStatement*, QofIdTypeConst, gpointer, - const GncSqlColumnTableEntry*, GValue*); + const GncSqlColumnTableEntry&, GValue*); }; #define gnc_sql_statement_dispose(STMT) \ (STMT)->dispose(STMT) @@ -179,7 +179,7 @@ struct GncSqlConnection gboolean (*rollbackTransaction) (GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ gboolean (*commitTransaction) (GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ gboolean (*createTable) (GncSqlConnection*, const gchar*, const ColVec&); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*createIndex) (GncSqlConnection*, const gchar*, const gchar*, const GncSqlColumnTableEntry*); /**< Returns TRUE if successful, FALSE if error */ + gboolean (*createIndex) (GncSqlConnection*, const gchar*, const gchar*, const EntryVec&); /**< Returns TRUE if successful, FALSE if error */ gboolean (*addColumnsToTable) (GncSqlConnection*, const gchar* table, const ColVec&); /**< Returns TRUE if successful, FALSE if error */ gchar* (*quoteString) (const GncSqlConnection*, gchar*); }; @@ -321,12 +321,18 @@ typedef enum #define CT_LOTREF "ct_lotref" #define CT_TXREF "ct_txref" +enum ColumnFlags : int +{ + COL_NO_FLAG = 0, + COL_PKEY = 0x01, /**< The column is a primary key */ + COL_NNUL = 0x02, /**< The column may not contain a NULL value */ + COL_UNIQUE = 0x04, /**< The column must contain unique values */ + COL_AUTOINC = 0x08 /**< The column is an auto-incrementing int */ + }; + /** - * @struct GncSqlColumnTableEntry - * - * The GncSqlColumnTableEntry struct contains all of the information - * required to copy information between an object and the database for a - * specific object property. + * Contains all of the information required to copy information between an + * object and the database for a specific object property. * * If an entry contains a gobj_param_name value, this string is used as the * property name for a call to g_object_get() or g_object_set(). If the @@ -341,20 +347,46 @@ typedef enum */ struct GncSqlColumnTableEntry { - const gchar* col_name; /**< Column name */ - const gchar* col_type; /**< Column type */ - unsigned int size; /**< Column size in bytes, for string columns */ -#define COL_PKEY 0x01 /**< The column is a primary key */ -#define COL_NNUL 0x02 /**< The column may not contain a NULL value */ -#define COL_UNIQUE 0x04 /**< The column must contain unique values */ -#define COL_AUTOINC 0x08 /**< The column is an auto-incrementing int */ - gint flags; /**< Column flags */ - const gchar* gobj_param_name; /**< If non-null, g_object param name */ - const gchar* qof_param_name; /**< If non-null, qof parameter name */ - QofAccessFunc getter; /**< General access function */ - QofSetterFunc setter; /**< General setter function */ + GncSqlColumnTableEntry (const char* name, const char*type, unsigned int s, + ColumnFlags f, const char* gobj_name = nullptr, + const char* qof_name = nullptr, + QofAccessFunc get = nullptr, + QofSetterFunc set = nullptr) : + col_name{name}, col_type{type}, size{s}, flags{f}, + gobj_param_name{gobj_name}, qof_param_name{qof_name}, getter{get}, + setter{set} {} + GncSqlColumnTableEntry (const char* name, const char*type, unsigned int s, + int f, const char* gobj_name = nullptr, + const char* qof_name = nullptr, + QofAccessFunc get = nullptr, + QofSetterFunc set = nullptr) : + col_name{name}, col_type{type}, size{s}, + flags{static_cast(f)}, + gobj_param_name{gobj_name}, qof_param_name{qof_name}, getter{get}, + setter{set} {} + const char* col_name; /**< Column name */ + const char* col_type; /**< Column type */ + unsigned int size; /**< Column size in bytes, for string columns */ + ColumnFlags flags; /**< Column flags */ + const char* gobj_param_name; /**< If non-null, g_object param name */ + const char* qof_param_name; /**< If non-null, qof parameter name */ + QofAccessFunc getter; /**< General access function */ + QofSetterFunc setter; /**< General setter function */ }; +inline bool operator==(const GncSqlColumnTableEntry& l, + const GncSqlColumnTableEntry& r) +{ + return strcmp(l.col_name, r.col_name) == 0 && + strcmp(l.col_type, r.col_type) == 0; +} + +inline bool operator!=(const GncSqlColumnTableEntry& l, + const GncSqlColumnTableEntry& r) +{ + return !(l == r); +} + /** * information required to create a column in a table. */ @@ -367,12 +399,12 @@ struct GncSqlColumnInfo m_name{name}, m_type{type}, m_size{size}, m_unicode{unicode}, m_autoinc{autoinc}, m_primary_key{primary}, m_not_null{not_null} {} - GncSqlColumnInfo(const GncSqlColumnTableEntry* e, GncSqlBasicColumnType t, + GncSqlColumnInfo(const GncSqlColumnTableEntry& e, GncSqlBasicColumnType t, unsigned int size = 0, bool unicode = true) : - m_name{e->col_name}, m_type{t}, m_size{size}, m_unicode{unicode}, - m_autoinc(e->flags & COL_AUTOINC), - m_primary_key(e->flags & COL_PKEY), - m_not_null(e->flags & COL_NNUL) {} + m_name{e.col_name}, m_type{t}, m_size{size}, m_unicode{unicode}, + m_autoinc(e.flags & COL_AUTOINC), + m_primary_key(e.flags & COL_PKEY), + m_not_null(e.flags & COL_NNUL) {} std::string m_name; /**< Column name */ GncSqlBasicColumnType m_type; /**< Column basic type */ unsigned int m_size; /**< Column size (string types) */ @@ -404,15 +436,15 @@ typedef enum typedef void (*GNC_SQL_LOAD_FN) (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table); + const GncSqlColumnTableEntry& table); typedef void (*GNC_SQL_ADD_COL_INFO_TO_LIST_FN) (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec); -typedef void (*GNC_SQL_ADD_COLNAME_TO_LIST_FN) (const GncSqlColumnTableEntry* table_row, GList** pList); +typedef void (*GNC_SQL_ADD_COLNAME_TO_LIST_FN) (const GncSqlColumnTableEntry& table_row, GList** pList); typedef void (*GNC_SQL_ADD_GVALUE_TO_SLIST_FN) (const GncSqlBackend* be, QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, GSList** pList); /** @@ -455,7 +487,7 @@ typedef struct * @return Access function */ QofAccessFunc gnc_sql_get_getter (QofIdTypeConst obj_name, - const GncSqlColumnTableEntry* table_row); + const GncSqlColumnTableEntry& table_row); /** * Adds a column name to a list. If the column type spans multiple columns, @@ -464,7 +496,7 @@ QofAccessFunc gnc_sql_get_getter (QofIdTypeConst obj_name, * @param table_row DB table column * @param pList List */ -void gnc_sql_add_colname_to_list (const GncSqlColumnTableEntry* table_row, +void gnc_sql_add_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pList); /** @@ -483,7 +515,7 @@ gboolean gnc_sql_do_db_operation (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table); + const EntryVec& table); /** * Executes an SQL SELECT statement and returns the result rows. If an error @@ -538,7 +570,7 @@ GncSqlStatement* gnc_sql_create_statement_from_sql (GncSqlBackend* be, */ void gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow* row, QofIdTypeConst obj_name, gpointer pObject, - const GncSqlColumnTableEntry* table); + const EntryVec& table); /** * Checks whether an object is in the database or not. @@ -552,8 +584,9 @@ void gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow* row, */ gboolean gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, - QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry* table); + QofIdTypeConst obj_name, + const gpointer pObject, + const EntryVec& table ); /** * Returns the version number for a DB table. @@ -581,7 +614,7 @@ gboolean gnc_sql_set_table_version (GncSqlBackend* be, gboolean gnc_sql_create_table (GncSqlBackend* be, const gchar* table_name, gint table_version, - const GncSqlColumnTableEntry* col_table); + const EntryVec& col_table); /** * Creates a temporary table in the database. A temporary table does not @@ -594,7 +627,7 @@ gboolean gnc_sql_create_table (GncSqlBackend* be, */ gboolean gnc_sql_create_temp_table (const GncSqlBackend* be, const gchar* table_name, - const GncSqlColumnTableEntry* col_table); + const EntryVec& col_table); /** * Creates an index in the database @@ -605,9 +638,8 @@ gboolean gnc_sql_create_temp_table (const GncSqlBackend* be, * @param col_table Columns that the index should index * @return TRUE if successful, FALSE if unsuccessful */ -gboolean gnc_sql_create_index (const GncSqlBackend* be, - const gchar* index_name, - const gchar* table_name, const GncSqlColumnTableEntry* col_table); +gboolean gnc_sql_create_index (const GncSqlBackend* be, const char* index_name, + const char* table_name, const EntryVec& col_table); /** * Loads the object guid from a database row. The table must have a column @@ -662,7 +694,7 @@ void gnc_sql_register_col_type_handler (const gchar* colType, void gnc_sql_add_gvalue_objectref_guid_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, GSList** pList); /** @@ -674,7 +706,7 @@ void gnc_sql_add_gvalue_objectref_guid_to_slist (const GncSqlBackend* be, * @param pList List */ void gnc_sql_add_objectref_guid_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec); /** @@ -695,9 +727,8 @@ guint gnc_sql_append_guid_list_to_sql (GString* str, GList* list, * @param subtable Sub-column description table * @param pList List */ -void gnc_sql_add_subtable_colnames_to_list (const GncSqlColumnTableEntry* - table_row, - const GncSqlColumnTableEntry* subtable, +void gnc_sql_add_subtable_colnames_to_list (const GncSqlColumnTableEntry& table_row, + const EntryVec& subtable, GList** pList); /** @@ -739,7 +770,7 @@ void gnc_sql_finalize_version_info (GncSqlBackend* be); gboolean gnc_sql_commit_standard_item (GncSqlBackend* be, QofInstance* inst, const gchar* tableName, QofIdTypeConst obj_name, - const GncSqlColumnTableEntry* col_table); + const EntryVec& col_table); /** * Gets an integer value (of any size) from a GValue. @@ -771,7 +802,7 @@ gchar* gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, * @param col_table Column table */ void gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name, - const GncSqlColumnTableEntry* col_table); + const EntryVec& col_table); /** * Adds one or more columns to an existing table. @@ -781,9 +812,8 @@ void gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name, * @param new_col_table Column table for new columns * @return TRUE if successful, FALSE if unsuccessful */ -gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, - const gchar* table_name, - const GncSqlColumnTableEntry* new_col_table); +gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const char* table_name, + const EntryVec& new_col_table); /** * Specifies the load order for a set of objects. When loading from a database, diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index 6e7c7f2317..ea609011de 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -61,7 +61,7 @@ static void bt_set_parent_guid (gpointer data, gpointer value); #define TABLE_NAME "billterms" #define TABLE_VERSION 2 -static GncSqlColumnTableEntry col_table[] = +static EntryVec col_table { { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" }, @@ -83,13 +83,11 @@ static GncSqlColumnTableEntry col_table[] = { "discountdays", CT_INT, 0, 0, 0, GNC_BILLTERM_DISCDAYS }, { "discount", CT_NUMERIC, 0, 0, 0, GNC_BILLTERM_DISCOUNT }, { "cutoff", CT_INT, 0, 0, 0, GNC_BILLTERM_CUTOFF }, - { NULL } }; -static GncSqlColumnTableEntry billterm_parent_col_table[] = +static EntryVec billterm_parent_col_table { { "parent", CT_GUID, 0, 0, NULL, NULL, NULL, (QofSetterFunc)bt_set_parent_guid }, - { NULL } }; typedef struct @@ -353,7 +351,7 @@ gnc_sql_save_billterm (GncSqlBackend* be, QofInstance* inst) static void load_billterm_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; GncGUID guid; @@ -362,9 +360,8 @@ load_billterm_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val != NULL && G_VALUE_HOLDS_STRING (val) && g_value_get_string (val) != NULL) { @@ -372,10 +369,10 @@ load_billterm_guid (const GncSqlBackend* be, GncSqlRow* row, term = gncBillTermLookup (be->book, &guid); if (term != NULL) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, term, NULL); + g_object_set (pObject, table_row.gobj_param_name, term, NULL); qof_instance_decrease_editlevel (pObject); } else diff --git a/src/backend/sql/gnc-book-sql.cpp b/src/backend/sql/gnc-book-sql.cpp index d3beba9bb3..500c2f94e4 100644 --- a/src/backend/sql/gnc-book-sql.cpp +++ b/src/backend/sql/gnc-book-sql.cpp @@ -56,7 +56,7 @@ static void set_root_account_guid (gpointer pObject, gpointer pValue); static gpointer get_root_template_guid (gpointer pObject); static void set_root_template_guid (gpointer pObject, gpointer pValue); -static const GncSqlColumnTableEntry col_table[] = +static const EntryVec col_table { { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { @@ -67,7 +67,6 @@ static const GncSqlColumnTableEntry col_table[] = "root_template_guid", CT_GUID, 0, COL_NNUL, NULL, NULL, (QofAccessFunc)get_root_template_guid, set_root_template_guid }, - { NULL } }; /* ================================================================= */ diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index 40a994a6a6..6be0140eaa 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -55,13 +55,12 @@ static QofLogModule log_module = G_LOG_DOMAIN; #define BUDGET_MAX_NAME_LEN 2048 #define BUDGET_MAX_DESCRIPTION_LEN 2048 -static const GncSqlColumnTableEntry col_table[] = +static const EntryVec col_table { { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "name", CT_STRING, BUDGET_MAX_NAME_LEN, COL_NNUL, "name" }, { "description", CT_STRING, BUDGET_MAX_DESCRIPTION_LEN, 0, "description" }, { "num_periods", CT_INT, 0, COL_NNUL, "num_periods" }, - { NULL } }; static QofInstance* get_budget (gpointer pObj); @@ -80,7 +79,7 @@ typedef struct guint period_num; } budget_amount_info_t; -static const GncSqlColumnTableEntry budget_amounts_col_table[] = +static const EntryVec budget_amounts_col_table { { "id", CT_INT, 0, COL_NNUL | COL_PKEY | COL_AUTOINC }, { @@ -99,7 +98,6 @@ static const GncSqlColumnTableEntry budget_amounts_col_table[] = "amount", CT_NUMERIC, 0, COL_NNUL, NULL, NULL, (QofAccessFunc)get_amount, (QofSetterFunc)set_amount }, - { NULL } }; /* ================================================================= */ @@ -484,7 +482,7 @@ write_budgets (GncSqlBackend* be) static void load_budget_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; GncGUID guid; @@ -493,9 +491,8 @@ load_budget_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val != NULL && G_VALUE_HOLDS_STRING (val) && g_value_get_string (val) != NULL) { @@ -503,10 +500,10 @@ load_budget_guid (const GncSqlBackend* be, GncSqlRow* row, budget = gnc_budget_lookup (&guid, be->book); if (budget != NULL) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, budget, NULL); + g_object_set (pObject, table_row.gobj_param_name, budget, NULL); qof_instance_decrease_editlevel (pObject); } else diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index 2ea452a1ae..d571d7e7b2 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -59,7 +59,7 @@ static void set_quote_source_name (gpointer pObject, gpointer pValue); #define COMMODITY_MAX_QUOTESOURCE_LEN 2048 #define COMMODITY_MAX_QUOTE_TZ_LEN 2048 -static const GncSqlColumnTableEntry col_table[] = +static const EntryVec col_table { { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { @@ -77,7 +77,6 @@ static const GncSqlColumnTableEntry col_table[] = (QofAccessFunc)get_quote_source_name, set_quote_source_name }, { "quote_tz", CT_STRING, COMMODITY_MAX_QUOTE_TZ_LEN, 0, "quote-tz" }, - { NULL } }; /* ================================================================= */ @@ -276,7 +275,7 @@ gnc_sql_commit_commodity (gnc_commodity* pCommodity) static void load_commodity_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; GncGUID guid; @@ -285,9 +284,8 @@ load_commodity_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val != NULL && G_VALUE_HOLDS_STRING (val) && g_value_get_string (val) != NULL) { @@ -295,10 +293,10 @@ load_commodity_guid (const GncSqlBackend* be, GncSqlRow* row, commodity = gnc_commodity_find_commodity_by_guid (&guid, be->book); if (commodity != NULL) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, commodity, NULL); + g_object_set (pObject, table_row.gobj_param_name, commodity, NULL); qof_instance_decrease_editlevel (pObject); } else if (setter != NULL) diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index ee9b27c935..a647cce88c 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -58,8 +58,8 @@ static QofLogModule log_module = G_LOG_DOMAIN; #define MAX_ID_LEN 2048 #define MAX_NOTES_LEN 2048 -static GncSqlColumnTableEntry col_table[] = -{ +static EntryVec col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" }, { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, NULL, CUSTOMER_ID }, @@ -83,8 +83,7 @@ static GncSqlColumnTableEntry col_table[] = "taxtable", CT_TAXTABLEREF, 0, 0, NULL, NULL, (QofAccessFunc)gncCustomerGetTaxTable, (QofSetterFunc)gncCustomerSetTaxTable }, - { NULL } -}; +}); static GncCustomer* load_single_customer (GncSqlBackend* be, GncSqlRow* row) diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index 1bc95481a7..f80accd66e 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -58,8 +58,8 @@ static QofLogModule log_module = G_LOG_DOMAIN; #define TABLE_NAME "employees" #define TABLE_VERSION 2 -static GncSqlColumnTableEntry col_table[] = -{ +static EntryVec col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "username", CT_STRING, MAX_USERNAME_LEN, COL_NNUL, "username" }, { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, "id" }, @@ -71,8 +71,7 @@ static GncSqlColumnTableEntry col_table[] = { "workday", CT_NUMERIC, 0, COL_NNUL, "workday" }, { "rate", CT_NUMERIC, 0, COL_NNUL, "rate" }, { "addr", CT_ADDRESS, 0, 0, "address" }, - { NULL } -}; +}); static GncEmployee* load_single_employee (GncSqlBackend* be, GncSqlRow* row) diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index d947694255..ac2d8dcb6f 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -64,8 +64,8 @@ static QofLogModule log_module = G_LOG_DOMAIN; static void entry_set_invoice (gpointer pObject, gpointer val); static void entry_set_bill (gpointer pObject, gpointer val); -static GncSqlColumnTableEntry col_table[] = -{ +static EntryVec col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "date", CT_TIMESPEC, 0, COL_NNUL, NULL, ENTRY_DATE }, { "date_entered", CT_TIMESPEC, 0, 0, NULL, ENTRY_DATE_ENTERED }, @@ -113,8 +113,7 @@ static GncSqlColumnTableEntry col_table[] = "order_guid", CT_ORDERREF, 0, 0, NULL, NULL, (QofAccessFunc)gncEntryGetOrder, (QofSetterFunc)gncEntrySetOrder }, - { NULL } -}; +}); static void entry_set_invoice (gpointer pObject, gpointer val) diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index 884faba1b0..c02d3d5aad 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -59,8 +59,8 @@ static QofLogModule log_module = G_LOG_DOMAIN; #define MAX_NOTES_LEN 2048 #define MAX_BILLING_ID_LEN 2048 -static GncSqlColumnTableEntry col_table[] = -{ +static EntryVec col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, NULL, INVOICE_ID }, { "date_opened", CT_TIMESPEC, 0, 0, NULL, INVOICE_OPENED }, @@ -91,8 +91,7 @@ static GncSqlColumnTableEntry col_table[] = "charge_amt", CT_NUMERIC, 0, 0, NULL, NULL, (QofAccessFunc)gncInvoiceGetToChargeAmount, (QofSetterFunc)gncInvoiceSetToChargeAmount }, - { NULL } -}; +}); static GncInvoice* load_single_invoice (GncSqlBackend* be, GncSqlRow* row) @@ -287,7 +286,7 @@ write_invoices (GncSqlBackend* be) static void load_invoice_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; GncGUID guid; @@ -296,9 +295,8 @@ load_invoice_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val != NULL && G_VALUE_HOLDS_STRING (val) && g_value_get_string (val) != NULL) { @@ -306,10 +304,10 @@ load_invoice_guid (const GncSqlBackend* be, GncSqlRow* row, invoice = gncInvoiceLookup (be->book, &guid); if (invoice != NULL) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, invoice, NULL); + g_object_set (pObject, table_row.gobj_param_name, invoice, NULL); qof_instance_decrease_editlevel (pObject); } else diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index 79ec2fcccc..f7f9ba7190 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -54,8 +54,8 @@ G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN; #define MAX_NAME_LEN 2048 #define MAX_REFERENCE_LEN 2048 -static GncSqlColumnTableEntry col_table[] = -{ +static EntryVec col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, NULL, JOB_ID }, { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" }, @@ -68,8 +68,7 @@ static GncSqlColumnTableEntry col_table[] = "owner", CT_OWNERREF, 0, 0, NULL, NULL, (QofAccessFunc)gncJobGetOwner, (QofSetterFunc)gncJobSetOwner }, - { NULL } -}; +}); static GncJob* load_single_job (GncSqlBackend* be, GncSqlRow* row) diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index 5714c5ba99..e541fbebfc 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -54,16 +54,15 @@ static QofLogModule log_module = G_LOG_DOMAIN; static gpointer get_lot_account (gpointer pObject); static void set_lot_account (gpointer pObject, gpointer pValue); -static const GncSqlColumnTableEntry col_table[] = -{ +static const EntryVec col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "account_guid", CT_ACCOUNTREF, 0, 0, NULL, NULL, (QofAccessFunc)get_lot_account, set_lot_account }, - { "is_closed", CT_BOOLEAN, 0, COL_NNUL, "is-closed" }, - { NULL } -}; + { "is_closed", CT_BOOLEAN, 0, COL_NNUL, "is-closed" } +}); /* ================================================================= */ static gpointer @@ -217,7 +216,7 @@ write_lots (GncSqlBackend* be) static void load_lot_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; GncGUID guid; @@ -226,9 +225,8 @@ load_lot_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val != NULL && G_VALUE_HOLDS_STRING (val) && g_value_get_string (val) != NULL) { @@ -236,10 +234,10 @@ load_lot_guid (const GncSqlBackend* be, GncSqlRow* row, lot = gnc_lot_lookup (&guid, be->book); if (lot != NULL) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, lot, NULL); + g_object_set (pObject, table_row.gobj_param_name, lot, NULL); qof_instance_decrease_editlevel (pObject); } else diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index f0f0a9c995..74a036ea49 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -54,8 +54,8 @@ static QofLogModule log_module = G_LOG_DOMAIN; #define MAX_NOTES_LEN 2048 #define MAX_REFERENCE_LEN 2048 -static GncSqlColumnTableEntry col_table[] = -{ +static EntryVec col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, "id" }, { "notes", CT_STRING, MAX_NOTES_LEN, COL_NNUL, "notes" }, @@ -64,8 +64,7 @@ static GncSqlColumnTableEntry col_table[] = { "date_opened", CT_TIMESPEC, 0, COL_NNUL, "date-opened" }, { "date_closed", CT_TIMESPEC, 0, COL_NNUL, "date-closed" }, { "owner", CT_OWNERREF, 0, COL_NNUL, NULL, ORDER_OWNER }, - { NULL }, -}; +}); static GncOrder* load_single_order (GncSqlBackend* be, GncSqlRow* row) @@ -202,7 +201,7 @@ write_orders (GncSqlBackend* be) static void load_order_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; GncGUID guid; @@ -211,9 +210,8 @@ load_order_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val != NULL && G_VALUE_HOLDS_STRING (val) && g_value_get_string (val) != NULL) { @@ -221,10 +219,10 @@ load_order_guid (const GncSqlBackend* be, GncSqlRow* row, order = gncOrderLookup (be->book, &guid); if (order != NULL) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, order, NULL); + g_object_set (pObject, table_row.gobj_param_name, order, NULL); qof_instance_decrease_editlevel (pObject); } else diff --git a/src/backend/sql/gnc-owner-sql.cpp b/src/backend/sql/gnc-owner-sql.cpp index 73b5717637..279853485e 100644 --- a/src/backend/sql/gnc-owner-sql.cpp +++ b/src/backend/sql/gnc-owner-sql.cpp @@ -51,7 +51,7 @@ typedef GncOwner* (*OwnerGetterFunc) (const gpointer); static void load_owner (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; gchar* buf; @@ -64,14 +64,13 @@ load_owner (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); book = be->book; - buf = g_strdup_printf ("%s_type", table_row->col_name); + buf = g_strdup_printf ("%s_type", table_row.col_name); val = gnc_sql_row_get_value_at_col_name (row, buf); type = (GncOwnerType)gnc_sql_get_integer_value (val); g_free (buf); - buf = g_strdup_printf ("%s_guid", table_row->col_name); + buf = g_strdup_printf ("%s_guid", table_row.col_name); val = gnc_sql_row_get_value_at_col_name (row, buf); g_free (buf); @@ -156,10 +155,10 @@ load_owner (const GncSqlBackend* be, GncSqlRow* row, PWARN ("Invalid owner type: %d\n", type); } - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, &owner, NULL); + g_object_set (pObject, table_row.gobj_param_name, &owner, NULL); qof_instance_decrease_editlevel (pObject); } else @@ -170,42 +169,42 @@ load_owner (const GncSqlBackend* be, GncSqlRow* row, static void add_owner_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry* table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec) { gchar* buf; g_return_if_fail (be != NULL); - g_return_if_fail (table_row != NULL); - buf = g_strdup_printf ("%s_type", table_row->col_name); + buf = g_strdup_printf ("%s_type", table_row.col_name); GncSqlColumnInfo info(buf, BCT_INT, 0, false, false, - table_row->flags & COL_PKEY, - table_row->flags & COL_NNUL); + table_row.flags & COL_PKEY, + table_row.flags & COL_NNUL); vec.emplace_back(std::move(info)); - buf = g_strdup_printf ("%s_guid", table_row->col_name); + buf = g_strdup_printf ("%s_guid", table_row.col_name); GncSqlColumnInfo info2(buf, BCT_STRING, GUID_ENCODING_LENGTH, false, false, - table_row->flags & COL_PKEY, - table_row->flags & COL_NNUL); + table_row.flags & COL_PKEY, + table_row.flags & COL_NNUL); vec.emplace_back(std::move(info2)); } static void -add_colname_to_list (const GncSqlColumnTableEntry* table_row, GList** pList) +add_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pList) { gchar* buf; - buf = g_strdup_printf ("%s_type", table_row->col_name); + buf = g_strdup_printf ("%s_type", table_row.col_name); (*pList) = g_list_append ((*pList), buf); - buf = g_strdup_printf ("%s_guid", table_row->col_name); + buf = g_strdup_printf ("%s_guid", table_row.col_name); (*pList) = g_list_append ((*pList), buf); } static void add_gvalue_owner_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, const GncSqlColumnTableEntry* table_row, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, GSList** pList) { GValue* subfield_value; @@ -220,14 +219,13 @@ add_gvalue_owner_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); getter = (OwnerGetterFunc)gnc_sql_get_getter (obj_name, table_row); owner = (*getter) (pObject); if (owner != NULL) { - buf = g_strdup_printf ("%s_type", table_row->col_name); + buf = g_strdup_printf ("%s_type", table_row.col_name); subfield_value = g_new0 (GValue, 1); g_value_init (subfield_value, G_TYPE_INT); type = gncOwnerGetType (owner); @@ -235,7 +233,7 @@ add_gvalue_owner_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, (*pList) = g_slist_append ((*pList), subfield_value); g_free (buf); - buf = g_strdup_printf ("%s_guid", table_row->col_name); + buf = g_strdup_printf ("%s_guid", table_row.col_name); subfield_value = g_new0 (GValue, 1); switch (type) { diff --git a/src/backend/sql/gnc-price-sql.cpp b/src/backend/sql/gnc-price-sql.cpp index 0bd549a220..2360b9af45 100644 --- a/src/backend/sql/gnc-price-sql.cpp +++ b/src/backend/sql/gnc-price-sql.cpp @@ -53,17 +53,16 @@ static QofLogModule log_module = G_LOG_DOMAIN; #define PRICE_MAX_SOURCE_LEN 2048 #define PRICE_MAX_TYPE_LEN 2048 -static const GncSqlColumnTableEntry col_table[] = -{ +static const EntryVec col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "commodity_guid", CT_COMMODITYREF, 0, COL_NNUL, "commodity" }, { "currency_guid", CT_COMMODITYREF, 0, COL_NNUL, "currency" }, { "date", CT_TIMESPEC, 0, COL_NNUL, "date" }, { "source", CT_STRING, PRICE_MAX_SOURCE_LEN, 0, "source" }, { "type", CT_STRING, PRICE_MAX_TYPE_LEN, 0, "type" }, - { "value", CT_NUMERIC, 0, COL_NNUL, "value" }, - { NULL } -}; + { "value", CT_NUMERIC, 0, COL_NNUL, "value" } +}); /* ================================================================= */ diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index ca6dbf6ea6..2d3925f5f5 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -69,8 +69,8 @@ static void set_recurrence_weekend_adjust (gpointer pObject, gpointer pValue); static gpointer get_recurrence_period_start (gpointer pObject); static void set_recurrence_period_start (gpointer pObject, gpointer pValue); -static const GncSqlColumnTableEntry col_table[] = -{ +static const EntryVec col_table +({ { "id", CT_INT, 0, COL_PKEY | COL_NNUL | COL_AUTOINC }, { "obj_guid", CT_GUID, 0, COL_NNUL, NULL, NULL, @@ -91,29 +91,26 @@ static const GncSqlColumnTableEntry col_table[] = { "recurrence_weekend_adjust", CT_STRING, BUDGET_MAX_RECURRENCE_WEEKEND_ADJUST_LEN, COL_NNUL, NULL, NULL, (QofAccessFunc)get_recurrence_weekend_adjust, set_recurrence_weekend_adjust - }, - { NULL } -}; + } +}); /* Special column table because we need to be able to access the table by a column other than the primary key */ -static const GncSqlColumnTableEntry guid_col_table[] = -{ +static const EntryVec guid_col_table +({ { "obj_guid", CT_GUID, 0, 0, NULL, NULL, (QofAccessFunc)get_obj_guid, (QofSetterFunc)set_obj_guid - }, - { NULL } -}; + } +}); /* Special column table used to upgrade table from version 1 to 2 */ -static const GncSqlColumnTableEntry weekend_adjust_col_table[] = -{ +static const EntryVec weekend_adjust_col_table +({ { "recurrence_weekend_adjust", CT_STRING, BUDGET_MAX_RECURRENCE_WEEKEND_ADJUST_LEN, 0, - }, - { NULL } -}; + } +}); /* ================================================================= */ diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index c2cec7b58c..91d7f0c05a 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -55,8 +55,8 @@ G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN; #define SX_MAX_NAME_LEN 2048 -static const GncSqlColumnTableEntry col_table[] = -{ +static const EntryVec col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "name", CT_STRING, SX_MAX_NAME_LEN, 0, "name" }, { "enabled", CT_BOOLEAN, 0, COL_NNUL, "enabled" }, @@ -71,8 +71,7 @@ static const GncSqlColumnTableEntry col_table[] = { "adv_notify", CT_INT, 0, COL_NNUL, "advance-reminder-days" }, { "instance_count", CT_INT, 0, COL_NNUL, "instance-count" }, { "template_act_guid", CT_ACCOUNTREF, 0, COL_NNUL, "template-account" }, - { NULL } -}; +}); /* ================================================================= */ static SchedXaction* diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index d9bc89fb68..25730ef78e 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -110,7 +110,7 @@ enum gdate_val_col }; -static const GncSqlColumnTableEntry col_table[] = +static const EntryVec col_table { /* col_name, col_type, size, flags, g0bj_param_name, qof_param_name, getter, setter */ { "id", CT_INT, 0, COL_PKEY | COL_NNUL | COL_AUTOINC }, @@ -154,21 +154,18 @@ static const GncSqlColumnTableEntry col_table[] = "gdate_val", CT_GDATE, 0, 0, NULL, NULL, (QofAccessFunc)get_gdate_val, (QofSetterFunc)set_gdate_val }, - { NULL } }; /* Special column table because we need to be able to access the table by a column other than the primary key */ -static const GncSqlColumnTableEntry obj_guid_col_table[] = +static const EntryVec obj_guid_col_table { { "obj_guid", CT_GUID, 0, 0, NULL, NULL, (QofAccessFunc)get_obj_guid, _retrieve_guid_ }, - { NULL } }; -static const GncSqlColumnTableEntry gdate_col_table[] = +static const EntryVec gdate_col_table { { "gdate_val", CT_GDATE, 0, 0, }, - { NULL } }; /* ================================================================= */ @@ -751,7 +748,8 @@ gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid) while (row != NULL) { - GncSqlColumnTableEntry table_row = col_table[guid_val_col]; + const GncSqlColumnTableEntry& table_row = + col_table[guid_val_col]; GncGUID child_guid; const GValue* val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index c82ec119f6..b0f4b689d7 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -65,8 +65,8 @@ static void tt_set_parent_guid (gpointer pObject, gpointer pValue); #define TT_TABLE_NAME "taxtables" #define TT_TABLE_VERSION 2 -static GncSqlColumnTableEntry tt_col_table[] = -{ +static EntryVec tt_col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" }, { "refcount", CT_INT64, 0, COL_NNUL, "ref-count" }, @@ -77,20 +77,18 @@ static GncSqlColumnTableEntry tt_col_table[] = "parent", CT_GUID, 0, 0, NULL, NULL, (QofAccessFunc)bt_get_parent, tt_set_parent }, - { NULL } -}; +}); -static GncSqlColumnTableEntry tt_parent_col_table[] = -{ +static EntryVec tt_parent_col_table +({ { "parent", CT_GUID, 0, 0, NULL, NULL, NULL, tt_set_parent_guid }, - { NULL } -}; +}); #define TTENTRIES_TABLE_NAME "taxtable_entries" #define TTENTRIES_TABLE_VERSION 3 -static GncSqlColumnTableEntry ttentries_col_table[] = -{ +static EntryVec ttentries_col_table +({ { "id", CT_INT, 0, COL_PKEY | COL_NNUL | COL_AUTOINC }, { "taxtable", CT_TAXTABLEREF, 0, COL_NNUL, NULL, NULL, @@ -108,16 +106,14 @@ static GncSqlColumnTableEntry ttentries_col_table[] = "type", CT_INT, 0, COL_NNUL, NULL, NULL, (QofAccessFunc)gncTaxTableEntryGetType, (QofSetterFunc)gncTaxTableEntrySetType }, - { NULL } -}; +}); /* Special column table because we need to be able to access the table by a column other than the primary key */ -static GncSqlColumnTableEntry guid_col_table[] = -{ +static EntryVec guid_col_table +({ { "taxtable", CT_GUID, 0, 0, NULL, NULL, get_obj_guid, set_obj_guid }, - { NULL } -}; +}); typedef struct { @@ -511,7 +507,7 @@ write_taxtables (GncSqlBackend* be) static void load_taxtable_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; GncGUID guid; @@ -520,9 +516,8 @@ load_taxtable_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); if (val != NULL && G_VALUE_HOLDS_STRING (val) && g_value_get_string (val) != NULL) { @@ -530,10 +525,10 @@ load_taxtable_guid (const GncSqlBackend* be, GncSqlRow* row, taxtable = gncTaxTableLookup (be->book, &guid); if (taxtable != NULL) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, taxtable, NULL); + g_object_set (pObject, table_row.gobj_param_name, taxtable, NULL); qof_instance_decrease_editlevel (pObject); } else diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index 218fca694b..41fd3d29bc 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -76,7 +76,7 @@ typedef struct #define TX_MAX_NUM_LEN 2048 #define TX_MAX_DESCRIPTION_LEN 2048 -static const GncSqlColumnTableEntry tx_col_table[] = +static const EntryVec tx_col_table { { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "currency_guid", CT_COMMODITYREF, 0, COL_NNUL, "currency" }, @@ -84,7 +84,6 @@ static const GncSqlColumnTableEntry tx_col_table[] = { "post_date", CT_TIMESPEC, 0, 0, "post-date" }, { "enter_date", CT_TIMESPEC, 0, 0, "enter-date" }, { "description", CT_STRING, TX_MAX_DESCRIPTION_LEN, 0, "description" }, - { NULL } }; static gpointer get_split_reconcile_state (gpointer pObject); @@ -94,7 +93,7 @@ static void set_split_lot (gpointer pObject, gpointer pLot); #define SPLIT_MAX_MEMO_LEN 2048 #define SPLIT_MAX_ACTION_LEN 2048 -static const GncSqlColumnTableEntry split_col_table[] = +static const EntryVec split_col_table { { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "tx_guid", CT_TXREF, 0, COL_NNUL, "transaction" }, @@ -112,25 +111,21 @@ static const GncSqlColumnTableEntry split_col_table[] = "lot_guid", CT_LOTREF, 0, 0, NULL, NULL, (QofAccessFunc)xaccSplitGetLot, set_split_lot }, - { NULL } }; -static const GncSqlColumnTableEntry post_date_col_table[] = +static const EntryVec post_date_col_table { { "post_date", CT_TIMESPEC, 0, 0, "post-date" }, - { NULL } }; -static const GncSqlColumnTableEntry account_guid_col_table[] = +static const EntryVec account_guid_col_table { { "account_guid", CT_ACCOUNTREF, 0, COL_NNUL, "account" }, - { NULL } }; -static const GncSqlColumnTableEntry tx_guid_col_table[] = +static const EntryVec tx_guid_col_table { { "tx_guid", CT_GUID, 0, 0, "guid" }, - { NULL } }; /* ================================================================= */ @@ -1322,12 +1317,11 @@ set_acct_bal_balance (gpointer pObject, gnc_numeric value) bal->balance = value; } -static const GncSqlColumnTableEntry acct_balances_col_table[] = +static const EntryVec acct_balances_col_table { { "account_guid", CT_GUID, 0, 0, NULL, NULL, NULL, (QofSetterFunc)set_acct_bal_account_from_guid }, { "reconcile_state", CT_STRING, 1, 0, NULL, NULL, NULL, (QofSetterFunc)set_acct_bal_reconcile_state }, { "quantity", CT_NUMERIC, 0, 0, NULL, NULL, NULL, (QofSetterFunc)set_acct_bal_balance }, - { NULL } }; G_GNUC_UNUSED static single_acct_balance_t* @@ -1444,7 +1438,7 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be) static void load_tx_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry* table_row) + const GncSqlColumnTableEntry& table_row) { const GValue* val; GncGUID guid; @@ -1454,9 +1448,8 @@ load_tx_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (be != NULL); g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row->col_name); + val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); g_assert (val != NULL); guid_str = g_value_get_string (val); if (guid_str != NULL) @@ -1480,10 +1473,10 @@ load_tx_guid (const GncSqlBackend* be, GncSqlRow* row, if (tx != NULL) { - if (table_row->gobj_param_name != NULL) + if (table_row.gobj_param_name != NULL) { qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row->gobj_param_name, tx, NULL); + g_object_set (pObject, table_row.gobj_param_name, tx, NULL); qof_instance_decrease_editlevel (pObject); } else diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index 6ca010ddb7..87daeab884 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -61,8 +61,8 @@ G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN; #define TABLE_NAME "vendors" #define TABLE_VERSION 1 -static GncSqlColumnTableEntry col_table[] = -{ +static EntryVec col_table +({ { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" }, { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, "id" }, @@ -74,8 +74,7 @@ static GncSqlColumnTableEntry col_table[] = { "terms", CT_BILLTERMREF, 0, 0, "terms" }, { "tax_inc", CT_STRING, MAX_TAX_INC_LEN, 0, "tax-included-string" }, { "tax_table", CT_TAXTABLEREF, 0, 0, "tax-table" }, - { NULL } -}; +}); static GncVendor* load_single_vendor (GncSqlBackend* be, GncSqlRow* row) diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index 2a82f6fed4..b8c6e0db48 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -386,7 +386,7 @@ test_set_autoinc_id (Fixture *fixture, gconstpointer pData) { }*/ /* gnc_sql_get_getter -gnc_sql_get_getter (QofIdTypeConst obj_name, const GncSqlColumnTableEntry* table_row)// C: 3 in 2 */ +gnc_sql_get_getter (QofIdTypeConst obj_name, const GncSqlColumnTableEntry& table_row)// C: 3 in 2 */ /* static void test_gnc_sql_get_getter (Fixture *fixture, gconstpointer pData) { @@ -394,7 +394,7 @@ test_gnc_sql_get_getter (Fixture *fixture, gconstpointer pData) // Make Static /* gnc_sql_add_colname_to_list void -gnc_sql_add_colname_to_list (const GncSqlColumnTableEntry* table_row, GList** pList)// 9 +gnc_sql_add_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pList)// 9 */ /* static void test_gnc_sql_add_colname_to_list (Fixture *fixture, gconstpointer pData) @@ -402,7 +402,7 @@ test_gnc_sql_add_colname_to_list (Fixture *fixture, gconstpointer pData) }*/ /* gnc_sql_add_subtable_colnames_to_list void -gnc_sql_add_subtable_colnames_to_list (const GncSqlColumnTableEntry* table_row, const GncSqlColumnTableEntry* subtable, +gnc_sql_add_subtable_colnames_to_list (const GncSqlColumnTableEntry& table_row, const EntryVec& subtable, GList** pList)// C: 1 */ /* static void test_gnc_sql_add_subtable_colnames_to_list (Fixture *fixture, gconstpointer pData) @@ -411,7 +411,7 @@ test_gnc_sql_add_subtable_colnames_to_list (Fixture *fixture, gconstpointer pDat /* load_string static void load_string (const GncSqlBackend* be, GncSqlRow* row, -const GncSqlColumnTableEntry* table_row)// 2 +const GncSqlColumnTableEntry& table_row)// 2 */ /* static void test_load_string (Fixture *fixture, gconstpointer pData) @@ -419,7 +419,7 @@ test_load_string (Fixture *fixture, gconstpointer pData) }*/ /* add_string_col_info_to_list static void -add_string_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row, +add_string_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row, GList** pList)// 2 */ /* static void @@ -429,7 +429,7 @@ test_add_string_col_info_to_list (Fixture *fixture, gconstpointer pData) /* add_gvalue_string_to_slist static void add_gvalue_string_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, -const gpointer pObject, const GncSqlColumnTableEntry* table_row, GSList** pList)// 2 +const gpointer pObject, const GncSqlColumnTableEntry& table_row, GSList** pList)// 2 */ /* static void test_add_gvalue_string_to_slist (Fixture *fixture, gconstpointer pData) @@ -445,7 +445,7 @@ test_load_int (Fixture *fixture, gconstpointer pData) }*/ /* add_int_col_info_to_list static void -add_int_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,// 2 +add_int_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row,// 2 */ /* static void test_add_int_col_info_to_list (Fixture *fixture, gconstpointer pData) @@ -469,7 +469,7 @@ test_load_boolean (Fixture *fixture, gconstpointer pData) }*/ /* add_boolean_col_info_to_list static void -add_boolean_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,// 2 +add_boolean_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row,// 2 */ /* static void test_add_boolean_col_info_to_list (Fixture *fixture, gconstpointer pData) @@ -493,7 +493,7 @@ test_load_int64 (Fixture *fixture, gconstpointer pData) }*/ /* add_int64_col_info_to_list static void -add_int64_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,// 2 +add_int64_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row,// 2 */ /* static void test_add_int64_col_info_to_list (Fixture *fixture, gconstpointer pData) @@ -517,7 +517,7 @@ test_load_double (Fixture *fixture, gconstpointer pData) }*/ /* add_double_col_info_to_list static void -add_double_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,// 2 +add_double_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row,// 2 */ /* static void test_add_double_col_info_to_list (Fixture *fixture, gconstpointer pData) @@ -541,7 +541,7 @@ test_load_guid (Fixture *fixture, gconstpointer pData) }*/ /* add_guid_col_info_to_list static void -add_guid_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,// 3 +add_guid_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row,// 3 */ /* static void test_add_guid_col_info_to_list (Fixture *fixture, gconstpointer pData) @@ -618,7 +618,7 @@ test_load_timespec (Fixture *fixture, gconstpointer pData) }*/ /* add_timespec_col_info_to_list static void -add_timespec_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,// 2 +add_timespec_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row,// 2 */ /* static void test_add_timespec_col_info_to_list (Fixture *fixture, gconstpointer pData) @@ -642,7 +642,7 @@ test_load_date (Fixture *fixture, gconstpointer pData) }*/ /* add_date_col_info_to_list static void -add_date_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,// 2 +add_date_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row,// 2 */ /* static void test_add_date_col_info_to_list (Fixture *fixture, gconstpointer pData) @@ -666,7 +666,7 @@ test_load_numeric (Fixture *fixture, gconstpointer pData) }*/ /* add_numeric_col_info_to_list static void -add_numeric_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,// 2 +add_numeric_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row,// 2 */ /* static void test_add_numeric_col_info_to_list (Fixture *fixture, gconstpointer pData) @@ -674,7 +674,7 @@ test_add_numeric_col_info_to_list (Fixture *fixture, gconstpointer pData) }*/ /* add_numeric_colname_to_list static void -add_numeric_colname_to_list (const GncSqlColumnTableEntry* table_row, GList** pList)// 2 +add_numeric_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pList)// 2 */ /* static void test_add_numeric_colname_to_list (Fixture *fixture, gconstpointer pData) @@ -689,7 +689,7 @@ test_add_gvalue_numeric_to_slist (Fixture *fixture, gconstpointer pData) { }*/ /* get_handler -get_handler (const GncSqlColumnTableEntry* table_row)// C: 1 */ +get_handler (const GncSqlColumnTableEntry& table_row)// C: 1 */ /* static void test_get_handler (Fixture *fixture, gconstpointer pData) { From 7d4ca43fd01e75364b44f9e027c87dc6f4367518 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 12 Mar 2016 11:32:27 -0800 Subject: [PATCH 06/63] Combine add_colname_to_list and add_gvalue_to_slist into single function add_value_to_vec. The two lists were always used together so replace them with a single vector of std::pair; this also gets rid of the intermediate GValue which was used to convert the returned value to a string. operator<<() can do that for us more transparently. Also template most of the add_value_to_vec functions. --- src/backend/dbi/gnc-backend-dbi.cpp | 56 +- src/backend/sql/gnc-account-sql.cpp | 3 +- src/backend/sql/gnc-address-sql.cpp | 92 +-- src/backend/sql/gnc-backend-sql.cpp | 756 ++++-------------- src/backend/sql/gnc-backend-sql.h | 174 ++-- src/backend/sql/gnc-bill-term-sql.cpp | 3 +- src/backend/sql/gnc-budget-sql.cpp | 3 +- src/backend/sql/gnc-commodity-sql.cpp | 3 +- src/backend/sql/gnc-invoice-sql.cpp | 3 +- src/backend/sql/gnc-lots-sql.cpp | 3 +- src/backend/sql/gnc-order-sql.cpp | 3 +- src/backend/sql/gnc-owner-sql.cpp | 95 +-- src/backend/sql/gnc-tax-table-sql.cpp | 3 +- src/backend/sql/gnc-transaction-sql.cpp | 3 +- .../sql/test/utest-gnc-backend-sql.cpp | 42 +- src/libqof/qof/gnc-datetime.hpp | 2 + 16 files changed, 406 insertions(+), 838 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 85dcdf6612..9b67cbb0ca 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -83,6 +83,7 @@ extern "C" #include #include +#include #include #include "gnc-backend-dbi.h" #include "gnc-backend-dbi-priv.h" @@ -2194,16 +2195,16 @@ row_get_value_at_col_name (GncSqlRow* row, const gchar* col_name) GncDbiSqlRow* dbi_row = (GncDbiSqlRow*)row; gushort type; guint attrs; - GValue* value; + GValue *value; type = dbi_result_get_field_type (dbi_row->result, col_name); attrs = dbi_result_get_field_attribs (dbi_row->result, col_name); - value = g_new0 (GValue, 1); - g_assert (value != NULL); switch (type) { case DBI_TYPE_INTEGER: + value = g_new0 (GValue, 1); + g_assert (value != NULL); (void)g_value_init (value, G_TYPE_INT64); g_value_set_int64 (value, dbi_result_get_longlong (dbi_row->result, col_name)); break; @@ -2211,11 +2212,15 @@ row_get_value_at_col_name (GncSqlRow* row, const gchar* col_name) gnc_push_locale (LC_NUMERIC, "C"); if ((attrs & DBI_DECIMAL_SIZEMASK) == DBI_DECIMAL_SIZE4) { + value = g_new0 (GValue, 1); + g_assert (value != NULL); (void)g_value_init (value, G_TYPE_FLOAT); g_value_set_float (value, dbi_result_get_float (dbi_row->result, col_name)); } else if ((attrs & DBI_DECIMAL_SIZEMASK) == DBI_DECIMAL_SIZE8) { + value = g_new0 (GValue, 1); + g_assert (value != NULL); (void)g_value_init (value, G_TYPE_DOUBLE); g_value_set_double (value, dbi_result_get_double (dbi_row->result, col_name)); } @@ -2226,6 +2231,8 @@ row_get_value_at_col_name (GncSqlRow* row, const gchar* col_name) gnc_pop_locale (LC_NUMERIC); break; case DBI_TYPE_STRING: + value = g_new0 (GValue, 1); + g_assert (value != NULL); (void)g_value_init (value, G_TYPE_STRING); g_value_take_string (value, dbi_result_get_string_copy (dbi_row->result, col_name)); @@ -2238,11 +2245,11 @@ row_get_value_at_col_name (GncSqlRow* row, const gchar* col_name) else { #if HAVE_LIBDBI_TO_LONGLONG - /* A less evil hack than the one equrie by libdbi-0.8, but - * still necessary to work around the same bug. - */ - time64 time = dbi_result_get_as_longlong(dbi_row->result, - col_name); + /* A less evil hack than the one equrie by libdbi-0.8, but + * still necessary to work around the same bug. + */ + time64 time = dbi_result_get_as_longlong(dbi_row->result, + col_name); #else /* A seriously evil hack to work around libdbi bug #15 * https://sourceforge.net/p/libdbi/bugs/15/. When libdbi @@ -2253,14 +2260,18 @@ row_get_value_at_col_name (GncSqlRow* row, const gchar* col_name) guint64 row = dbi_result_get_currow (result); guint idx = dbi_result_get_field_idx (result, col_name) - 1; time64 time = result->rows[row]->field_values[idx].d_datetime; + if (time < MINTIME || time > MAXTIME) + return nullptr; + value = g_new0 (GValue, 1); + g_assert (value != NULL); #endif //HAVE_LIBDBI_TO_LONGLONG + (void)g_value_init (value, G_TYPE_INT64); g_value_set_int64 (value, time); } break; default: PERR ("Field %s: unknown DBI_TYPE: %d\n", col_name, type); - g_free (value); return NULL; } @@ -2431,19 +2442,20 @@ stmt_to_sql (GncSqlStatement* stmt) static void stmt_add_where_cond(GncSqlStatement* stmt, QofIdTypeConst type_name, - gpointer obj, const GncSqlColumnTableEntry& table_row, - GValue* value ) + gpointer obj, const PairVec& col_values) { - GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt; - gchar* buf; - gchar* value_str; - - value_str = gnc_sql_get_sql_value (dbi_stmt->conn, value); - buf = g_strdup_printf (" WHERE %s = %s", table_row.col_name, - value_str); - g_free (value_str); - (void)g_string_append (dbi_stmt->sql, buf); - g_free (buf); + GncDbiSqlStatement* dbi_stmt = reinterpret_cast(stmt); + std::ostringstream sql; + sql << " WHERE "; + for (auto colpair : col_values) + { + if (colpair != *col_values.begin()) + sql << " AND "; + sql << colpair.first << " = " << + gnc_sql_connection_quote_string (dbi_stmt->conn, + colpair.second.c_str()); + } + (void)g_string_append (dbi_stmt->sql, sql.str().c_str()); } static GncSqlStatement* @@ -3046,7 +3058,7 @@ conn_add_columns_to_table(GncSqlConnection* conn, const char* table_name, } static gchar* -conn_quote_string (const GncSqlConnection* conn, gchar* unquoted_str) +conn_quote_string (const GncSqlConnection* conn, const char* unquoted_str) { GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; gchar* quoted_str; diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index de0fa28f71..e2fb2b7bed 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -441,8 +441,7 @@ load_account_guid (const GncSqlBackend* be, GncSqlRow* row, static GncSqlColumnTypeHandler account_guid_handler = { load_account_guid, gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_colname_to_list, - gnc_sql_add_gvalue_objectref_guid_to_slist + gnc_sql_add_objectref_guid_to_vec }; /* ================================================================= */ void diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index cd793007ec..9c6eb83b67 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -148,91 +148,33 @@ add_address_col_info_to_list(const GncSqlBackend* be, } static void -add_address_colname_to_list (const GncSqlColumnTableEntry& table_row, - GList** pList) +add_value_address_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec) { - gnc_sql_add_subtable_colnames_to_list (table_row, col_table, pList); -} + auto addr = get_row_value_from_object(obj_name, pObject, + table_row); -static void -get_gvalue_address (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, GValue* value) -{ - AddressGetterFunc getter; - GncAddress* addr; - g_return_if_fail (be != NULL); - g_return_if_fail (obj_name != NULL); - g_return_if_fail (pObject != NULL); - - memset (value, 0, sizeof (GValue)); - if (table_row.gobj_param_name != NULL) + if (addr == nullptr) + return; + for (auto const& subtable_row : col_table) { - g_object_get (pObject, table_row.gobj_param_name, &addr, NULL); - } - else - { - getter = (AddressGetterFunc)gnc_sql_get_getter (obj_name, table_row); - addr = (*getter) (pObject); - } - g_value_init (value, gnc_address_get_type ()); - g_value_set_object (value, addr); -} - -static void -add_gvalue_address_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) -{ - GValue value; - GValue* subfield_value; - GncAddress* addr; - gchar* s; - QofAccessFunc getter; - - g_return_if_fail (be != NULL); - g_return_if_fail (obj_name != NULL); - g_return_if_fail (pObject != NULL); - - memset (&value, 0, sizeof (GValue)); - get_gvalue_address (be, obj_name, pObject, table_row, &value); - - if (G_VALUE_TYPE (&value) != 0) - { - addr = static_cast(g_value_get_object(&value)); - for (auto const& subtable_row : col_table) - { - subfield_value = g_new0 (GValue, 1); - if (subtable_row.gobj_param_name != NULL) - { - g_object_get (addr, subtable_row.gobj_param_name, &s, NULL); - } - else - { - getter = gnc_sql_get_getter (GNC_ID_ADDRESS, subtable_row); - s = (gchar*) (*getter) (addr, NULL); - } - g_value_init (subfield_value, G_TYPE_STRING); - if (s) - { - g_value_set_string (subfield_value, s); - } - else - { - g_value_set_string (subfield_value, "NULL"); - } - (*pList) = g_slist_append ((*pList), subfield_value); - } + auto s = get_row_value_from_object(GNC_ID_ADDRESS, addr, + subtable_row); + if (s == nullptr) + continue; + std::ostringstream buf; + buf << table_row.col_name << "_" << subtable_row.col_name; + vec.emplace_back(make_pair(buf.str(), std::string{s})); } } static GncSqlColumnTypeHandler address_handler = { load_address, add_address_col_info_to_list, - add_address_colname_to_list, - add_gvalue_address_to_slist + add_value_address_to_vec }; /* ================================================================= */ diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 228cb0fe4e..989bb02767 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -57,6 +57,7 @@ extern "C" } #include +#include #include "gnc-backend-sql.h" @@ -179,15 +180,15 @@ create_tables(const OBEEntry& entry, GncSqlBackend* be) /* ================================================================= */ /* Main object load order */ -static const LoadOrder fixed_load_order +static const StrVec fixed_load_order { GNC_ID_BOOK, GNC_ID_COMMODITY, GNC_ID_ACCOUNT, GNC_ID_LOT }; /* Load order for objects from other modules */ -static LoadOrder other_load_order; +static StrVec other_load_order; void -gnc_sql_set_load_order(const LoadOrder& load_order) +gnc_sql_set_load_order(const StrVec& load_order) { other_load_order = load_order; } @@ -1056,7 +1057,7 @@ gnc_sql_run_query (QofBackend* pBEnd, gpointer pQuery) /* ================================================================= */ /* Order in which business objects need to be loaded */ -static const LoadOrder business_fixed_load_order = +static const StrVec business_fixed_load_order = { GNC_ID_BILLTERM, GNC_ID_TAXTABLE, GNC_ID_INVOICE }; static void @@ -1177,28 +1178,6 @@ gnc_sql_get_getter (QofIdTypeConst obj_name, return getter; } - -/* ----------------------------------------------------------------- */ -void -gnc_sql_add_colname_to_list (const GncSqlColumnTableEntry& table_row, - GList** pList) -{ - (*pList) = g_list_append ((*pList), g_strdup (table_row.col_name)); -} - -/* ----------------------------------------------------------------- */ -void -gnc_sql_add_subtable_colnames_to_list (const GncSqlColumnTableEntry& table_row, - const EntryVec& subtable, - GList** pList ) -{ - for (auto const& subtable_row : subtable) - { - char* buf = g_strdup_printf ("%s_%s", - table_row.col_name, subtable_row.col_name); - *pList = g_list_append (*pList, buf); - } -} /* ----------------------------------------------------------------- */ static void load_string (const GncSqlBackend* be, GncSqlRow* row, @@ -1243,56 +1222,33 @@ add_string_col_info_to_list(const GncSqlBackend* be, vec.emplace_back(std::move(info)); } -static void -add_gvalue_string_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) +/* char is unusual in that we get a pointer but don't deref it to pass + * it to operator<<(). + */ +template <> void +add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec) { - QofAccessFunc getter; - gchar* s = NULL; - GValue* value; + auto s = get_row_value_from_object(obj_name, pObject, table_row); - g_return_if_fail (be != NULL); - g_return_if_fail (obj_name != NULL); - g_return_if_fail (pObject != NULL); - g_return_if_fail (pList != NULL); - - value = g_new0 (GValue, 1); - g_assert (value != NULL); - memset (value, 0, sizeof (GValue)); - if (table_row.gobj_param_name != NULL) + if (s != nullptr) { - g_object_get (pObject, table_row.gobj_param_name, &s, NULL); + std::ostringstream stream; + stream << s; + vec.emplace_back (std::make_pair (std::string{table_row.col_name}, + stream.str())); + return; } - else - { - getter = gnc_sql_get_getter (obj_name, table_row); - if (getter != NULL) - { - s = (gchar*) (*getter) (pObject, NULL); - if (s != NULL) - { - s = g_strdup (s); - } - } - } - (void)g_value_init (value, G_TYPE_STRING); - if (s) - { - g_value_take_string (value, s); - } - - (*pList) = g_slist_append ((*pList), value); -} + } static GncSqlColumnTypeHandler string_handler = { load_string, add_string_col_info_to_list, - gnc_sql_add_colname_to_list, - add_gvalue_string_to_slist + add_value_to_vec }; /* ----------------------------------------------------------------- */ typedef gint (*IntAccessFunc) (const gpointer); @@ -1348,51 +1304,14 @@ add_int_col_info_to_list(const GncSqlBackend* be, vec.emplace_back(std::move(info)); } -static void -add_gvalue_int_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) -{ - gint int_value = 0; - IntAccessFunc i_getter; - GValue* value; - - g_return_if_fail (be != NULL); - g_return_if_fail (obj_name != NULL); - g_return_if_fail (pObject != NULL); - g_return_if_fail (pList != NULL); - - value = g_new0 (GValue, 1); - g_assert (value != NULL); - (void)g_value_init (value, G_TYPE_INT); - - if (table_row.gobj_param_name != NULL) - { - g_object_get_property (G_OBJECT (pObject), table_row.gobj_param_name, - value); - } - else - { - i_getter = (IntAccessFunc)gnc_sql_get_getter (obj_name, table_row); - if (i_getter != NULL) - { - int_value = (*i_getter) (pObject); - } - g_value_set_int (value, int_value); - } - - (*pList) = g_slist_append ((*pList), value); -} - static GncSqlColumnTypeHandler int_handler = { load_int, add_int_col_info_to_list, - gnc_sql_add_colname_to_list, - add_gvalue_int_to_slist + add_value_to_vec }; + /* ----------------------------------------------------------------- */ typedef gboolean (*BooleanAccessFunc) (const gpointer); typedef void (*BooleanSetterFunc) (const gpointer, gboolean); @@ -1447,50 +1366,14 @@ add_boolean_col_info_to_list(const GncSqlBackend* be, vec.emplace_back(std::move(info)); } -static void -add_gvalue_boolean_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) -{ - gint int_value = 0; - BooleanAccessFunc b_getter; - GValue* value; - - g_return_if_fail (be != NULL); - g_return_if_fail (obj_name != NULL); - g_return_if_fail (pObject != NULL); - g_return_if_fail (pList != NULL); - - value = g_new0 (GValue, 1); - g_assert (value != NULL); - - if (table_row.gobj_param_name != nullptr) - { - g_object_get (pObject, table_row.gobj_param_name, &int_value, NULL); - } - else - { - b_getter = (BooleanAccessFunc)gnc_sql_get_getter (obj_name, table_row); - if (b_getter != NULL) - { - int_value = ((*b_getter) (pObject)) ? 1 : 0; - } - } - (void)g_value_init (value, G_TYPE_INT); - g_value_set_int (value, int_value); - - (*pList) = g_slist_append ((*pList), value); -} - static GncSqlColumnTypeHandler boolean_handler = { load_boolean, add_boolean_col_info_to_list, - gnc_sql_add_colname_to_list, - add_gvalue_boolean_to_slist + add_value_to_vec }; + /* ----------------------------------------------------------------- */ typedef gint64 (*Int64AccessFunc) (const gpointer); typedef void (*Int64SetterFunc) (const gpointer, gint64); @@ -1539,48 +1422,12 @@ add_int64_col_info_to_list(const GncSqlBackend* be, vec.emplace_back(std::move(info)); } -static void -add_gvalue_int64_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) -{ - gint64 i64_value = 0; - Int64AccessFunc getter; - GValue* value; - - g_return_if_fail (be != NULL); - g_return_if_fail (obj_name != NULL); - g_return_if_fail (pObject != NULL); - g_return_if_fail (pList != NULL); - - value = g_new0 (GValue, 1); - g_assert (value != NULL); - if (table_row.gobj_param_name != nullptr) - { - g_object_get (pObject, table_row.gobj_param_name, &i64_value, NULL); - } - else - { - getter = (Int64AccessFunc)gnc_sql_get_getter (obj_name, table_row); - if (getter != NULL) - { - i64_value = (*getter) (pObject); - } - } - (void)g_value_init (value, G_TYPE_INT64); - g_value_set_int64 (value, i64_value); - - (*pList) = g_slist_append ((*pList), value); -} - static GncSqlColumnTypeHandler int64_handler = { load_int64, add_int64_col_info_to_list, - gnc_sql_add_colname_to_list, - add_gvalue_int64_to_slist + add_value_to_vec }; /* ----------------------------------------------------------------- */ @@ -1648,50 +1495,12 @@ add_double_col_info_to_list(const GncSqlBackend* be, vec.emplace_back(std::move(info)); } -static void -add_gvalue_double_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) -{ - QofAccessFunc getter; - gdouble* pDouble = NULL; - gdouble d_value; - GValue* value; - - g_return_if_fail (be != NULL); - g_return_if_fail (obj_name != NULL); - g_return_if_fail (pObject != NULL); - - value = g_new0 (GValue, 1); - g_assert (value != NULL); - getter = gnc_sql_get_getter (obj_name, table_row); - if (getter != NULL) - { - pDouble = static_cast ((*getter) (pObject, NULL)); - } - if (pDouble != NULL) - { - d_value = *pDouble; - (void)g_value_init (value, G_TYPE_DOUBLE); - g_value_set_double (value, d_value); - } - else - { - (void)g_value_init (value, G_TYPE_DOUBLE); - g_value_set_double (value, 0.0); - } - - (*pList) = g_slist_append ((*pList), value); -} - static GncSqlColumnTypeHandler double_handler = { load_double, add_double_col_info_to_list, - gnc_sql_add_colname_to_list, - add_gvalue_double_to_slist + add_value_to_vec }; /* ----------------------------------------------------------------- */ @@ -1749,44 +1558,22 @@ add_guid_col_info_to_list(const GncSqlBackend* be, vec.emplace_back(std::move(info)); } -static void -add_gvalue_guid_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, +template <> void +add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, const gpointer pObject, const GncSqlColumnTableEntry& table_row, - GSList** pList) + PairVec& vec) { - QofAccessFunc getter; - GncGUID* guid = NULL; - gchar guid_buf[GUID_ENCODING_LENGTH + 1]; - GValue* value; + auto s = get_row_value_from_object(obj_name, pObject, table_row); - g_return_if_fail (be != NULL); - g_return_if_fail (obj_name != NULL); - g_return_if_fail (pObject != NULL); - - value = g_new0 (GValue, 1); - g_assert (value != NULL); - if (table_row.gobj_param_name != NULL) + if (s != nullptr) { - g_object_get (pObject, table_row.gobj_param_name, &guid, NULL); + std::ostringstream stream; + stream << guid_to_string(s); + vec.emplace_back (std::make_pair (std::string{table_row.col_name}, + stream.str())); + return; } - else - { - getter = gnc_sql_get_getter (obj_name, table_row); - if (getter != NULL) - { - guid = static_cast ((*getter) (pObject, NULL)); - } - } - (void)g_value_init (value, G_TYPE_STRING); - if (guid != NULL) - { - (void)guid_to_string_buff (guid, guid_buf); - g_value_set_string (value, guid_buf); - } - - (*pList) = g_slist_append ((*pList), value); - } static GncSqlColumnTypeHandler guid_handler @@ -1794,54 +1581,28 @@ static GncSqlColumnTypeHandler guid_handler { load_guid, add_guid_col_info_to_list, - gnc_sql_add_colname_to_list, - add_gvalue_guid_to_slist + add_value_to_vec }; /* ----------------------------------------------------------------- */ void -gnc_sql_add_gvalue_objectref_guid_to_slist (const GncSqlBackend* be, - QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) +gnc_sql_add_objectref_guid_to_vec (const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec) { - QofAccessFunc getter; - const GncGUID* guid = NULL; - gchar guid_buf[GUID_ENCODING_LENGTH + 1]; - QofInstance* inst = NULL; - GValue* value; - - g_return_if_fail (be != NULL); - g_return_if_fail (obj_name != NULL); - g_return_if_fail (pObject != NULL); - - value = g_new0 (GValue, 1); - g_assert (value != NULL); - if (table_row.gobj_param_name != NULL) - { - g_object_get (pObject, table_row.gobj_param_name, &inst, NULL); - } - else - { - getter = gnc_sql_get_getter (obj_name, table_row); - if (getter != NULL) - { - inst = static_cast ((*getter) (pObject, NULL)); - } - } - if (inst != NULL) - { + auto inst = get_row_value_from_object(obj_name, pObject, + table_row); + const GncGUID* guid = nullptr; + if (inst != nullptr) guid = qof_instance_get_guid (inst); - } - (void)g_value_init (value, G_TYPE_STRING); - if (guid != NULL) + if (guid != nullptr) { - (void)guid_to_string_buff (guid, guid_buf); - g_value_set_string (value, guid_buf); + vec.emplace_back (std::make_pair (std::string{table_row.col_name}, + std::string{guid_to_string(guid)})); + return; } - - (*pList) = g_slist_append ((*pList), value); } void @@ -1964,20 +1725,20 @@ add_timespec_col_info_to_list(const GncSqlBackend* be, } static void -add_gvalue_timespec_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) +add_timespec_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec) { TimespecAccessFunc ts_getter; Timespec ts; - gchar* datebuf; - GValue* value; - +/* Can't use get_row_value_from_object because g_object_get returns a + * Timespec* and the getter returns a Timespec. Will be fixed by the + * replacement of timespecs with time64s. + */ g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - g_return_if_fail (pList != NULL); if (table_row.gobj_param_name != NULL) { @@ -1992,16 +1753,13 @@ add_gvalue_timespec_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, ts = (*ts_getter) (pObject); } - value = g_new0 (GValue, 1); - g_assert (value != NULL); - (void)g_value_init (value, G_TYPE_STRING); if (ts.tv_sec != 0 || ts.tv_nsec != 0) { - datebuf = gnc_sql_convert_timespec_to_string (be, ts); - g_value_take_string (value, datebuf); + char* datebuf = gnc_sql_convert_timespec_to_string (be, ts); + vec.emplace_back (std::make_pair (std::string{table_row.col_name}, + std::string{datebuf})); + return; } - - (*pList) = g_slist_append ((*pList), value); } static GncSqlColumnTypeHandler timespec_handler @@ -2009,8 +1767,7 @@ static GncSqlColumnTypeHandler timespec_handler { load_timespec, add_timespec_col_info_to_list, - gnc_sql_add_colname_to_list, - add_gvalue_timespec_to_slist + add_timespec_to_vec }; /* ----------------------------------------------------------------- */ #define DATE_COL_SIZE 8 @@ -2118,43 +1875,23 @@ add_date_col_info_to_list (const GncSqlBackend* be, } static void -add_gvalue_date_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) +add_date_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec) { - GDate* date = NULL; - QofAccessFunc getter; - gchar* buf; - GValue* value; - - g_return_if_fail (be != NULL); - g_return_if_fail (obj_name != NULL); - g_return_if_fail (pObject != NULL); - - value = g_new0 (GValue, 1); - g_assert (value != NULL); - (void)g_value_init (value, G_TYPE_STRING); - if (table_row.gobj_param_name != NULL) - { - g_object_get (pObject, table_row.gobj_param_name, &date, NULL); - } - else - { - getter = gnc_sql_get_getter (obj_name, table_row); - if (getter != NULL) - { - date = (GDate*) (*getter) (pObject, NULL); - } - } + GDate *date = get_row_value_from_object(obj_name, pObject, + table_row); if (date && g_date_valid (date)) { - buf = g_strdup_printf ("%04d%02d%02d", - g_date_get_year (date), g_date_get_month (date), g_date_get_day (date)); - g_value_take_string (value, buf); + std::ostringstream buf; + buf << std::setfill ('0') << std::setw (4) << g_date_get_year (date) << + std::setw (2) << g_date_get_month (date) << + std::setw (2) << static_cast(g_date_get_day (date)); + vec.emplace_back (std::make_pair (std::string{table_row.col_name}, + buf.str())); + return; } - - (*pList) = g_slist_append ((*pList), value); } static GncSqlColumnTypeHandler date_handler @@ -2162,8 +1899,7 @@ static GncSqlColumnTypeHandler date_handler { load_date, add_date_col_info_to_list, - gnc_sql_add_colname_to_list, - add_gvalue_date_to_slist + add_date_to_vec }; /* ----------------------------------------------------------------- */ typedef gnc_numeric (*NumericGetterFunc) (const gpointer); @@ -2254,22 +1990,14 @@ add_numeric_col_info_to_list(const GncSqlBackend* be, } static void -add_numeric_colname_to_list (const GncSqlColumnTableEntry& table_row, - GList** pList) -{ - gnc_sql_add_subtable_colnames_to_list (table_row, numeric_col_table, pList); -} - -static void -add_gvalue_numeric_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) +add_numeric_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec) { +/* We can't use get_row_value_from_object for the same reason as Timespec. */ NumericGetterFunc getter; gnc_numeric n; - GValue* num_value; - GValue* denom_value; g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); @@ -2294,24 +2022,22 @@ add_gvalue_numeric_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, } } - num_value = g_new0 (GValue, 1); - g_assert (num_value != NULL); - (void)g_value_init (num_value, G_TYPE_INT64); - g_value_set_int64 (num_value, gnc_numeric_num (n)); - denom_value = g_new0 (GValue, 1); - g_assert (denom_value != NULL); - (void)g_value_init (denom_value, G_TYPE_INT64); - g_value_set_int64 (denom_value, gnc_numeric_denom (n)); - - (*pList) = g_slist_append ((*pList), num_value); - (*pList) = g_slist_append ((*pList), denom_value); + std::ostringstream buf; + std::string num_col{table_row.col_name}; + std::string denom_col{table_row.col_name}; + num_col += "_num"; + denom_col += "_denom"; + buf << gnc_numeric_num (n); + vec.emplace_back (std::make_pair (num_col, buf.str ())); + buf.str (""); + buf << gnc_numeric_denom (n); + vec.emplace_back (denom_col, buf.str ()); } static GncSqlColumnTypeHandler numeric_handler = { load_numeric, add_numeric_col_info_to_list, - add_numeric_colname_to_list, - add_gvalue_numeric_to_slist + add_numeric_to_vec }; /* ================================================================= */ @@ -2627,7 +2353,7 @@ gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, GncSqlStatement* sqlStmt; guint count; GncSqlColumnTypeHandler* pHandler; - GSList* list = NULL; + PairVec values; g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); @@ -2641,10 +2367,9 @@ gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, /* WHERE */ pHandler = get_handler (table[0]); g_assert (pHandler != NULL); - pHandler->add_gvalue_to_slist_fn (be, obj_name, pObject, table[0], &list); - g_assert (list != NULL); - gnc_sql_statement_add_where_cond (sqlStmt, obj_name, pObject, table[0], - (GValue*) (list->data)); + pHandler->add_value_to_vec_fn (be, obj_name, pObject, table[0], values); + PairVec col_values {values[0]}; + gnc_sql_statement_add_where_cond (sqlStmt, obj_name, pObject, col_values); count = execute_statement_get_count (be, sqlStmt); gnc_sql_statement_dispose (sqlStmt); @@ -2709,12 +2434,11 @@ gnc_sql_do_db_operation (GncSqlBackend* be, return ok; } -static GSList* -create_gslist_from_values (GncSqlBackend* be, - QofIdTypeConst obj_name, gpointer pObject, - const EntryVec& table ) +static PairVec +get_object_values (GncSqlBackend* be, QofIdTypeConst obj_name, + gpointer pObject, const EntryVec& table) { - GSList* list = NULL; + PairVec vec; GncSqlColumnTypeHandler* pHandler; for (auto const& table_row : table) @@ -2723,97 +2447,11 @@ create_gslist_from_values (GncSqlBackend* be, { pHandler = get_handler (table_row); g_assert (pHandler != NULL); - pHandler->add_gvalue_to_slist_fn (be, obj_name, pObject, table_row, &list); + pHandler->add_value_to_vec_fn (be, obj_name, pObject, + table_row, vec); } } - - g_assert (list != NULL); - return list; -} - -gchar* -gnc_sql_get_sql_value (const GncSqlConnection* conn, const GValue* value) -{ - if (value != NULL && G_IS_VALUE (value)) - { - GType type = G_VALUE_TYPE (value); - - if (G_VALUE_HOLDS_STRING (value)) - { - if (g_value_get_string (value) != NULL) - { - gchar* before_str; - gchar* after_str; - before_str = g_value_dup_string (value); - after_str = gnc_sql_connection_quote_string (conn, before_str); - g_free (before_str); - return after_str; - } - else - { - return g_strdup ("NULL"); - } - } - else if (type == G_TYPE_INT64) - { - return g_strdup_printf ("%" G_GINT64_FORMAT, g_value_get_int64 (value)); - - } - else if (type == G_TYPE_INT) - { - return g_strdup_printf ("%d", g_value_get_int (value)); - - } - else if (type == G_TYPE_DOUBLE) - { - gchar doublestr[G_ASCII_DTOSTR_BUF_SIZE]; - g_ascii_dtostr (doublestr, sizeof (doublestr), - g_value_get_double (value)); - return g_strdup (doublestr); - - } - else if (g_value_type_transformable (type, G_TYPE_STRING)) - { - GValue* string; - gchar* str; - - string = g_new0 (GValue, 1); - g_assert (string != NULL); - (void)g_value_init (string, G_TYPE_STRING); - (void)g_value_transform (value, string); - str = g_value_dup_string (string); - g_value_unset (string); - g_free (string); - PWARN ("using g_value_transform(), gtype = '%s'\n", g_type_name (type)); - return str; - } - else - { - PWARN ("not transformable, gtype = '%s'\n", g_type_name (type)); - return g_strdup ("$$$"); - } - } - else - { - PWARN ("value is NULL or not G_IS_VALUE()\n"); - return g_strdup (""); - } -} - -static void -free_gvalue_list (GSList* list) -{ - GSList* node; - GValue* value; - - for (node = list; node != NULL; node = node->next) - { - value = (GValue*)node->data; - - g_value_unset (value); - g_free (value); - } - g_slist_free (list); + return vec; } static GncSqlStatement* @@ -2823,69 +2461,35 @@ build_insert_statement (GncSqlBackend* be, const EntryVec& table) { GncSqlStatement* stmt; - GString* sql; - GSList* values; - GSList* node; - gchar* sqlbuf; - GList* colnames = NULL; - GList* colname; + PairVec col_values; + std::ostringstream sql; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); g_return_val_if_fail (obj_name != NULL, NULL); g_return_val_if_fail (pObject != NULL, NULL); + PairVec values{get_object_values(be, obj_name, pObject, table)}; - sqlbuf = g_strdup_printf ("INSERT INTO %s(", table_name); - sql = g_string_new (sqlbuf); - g_free (sqlbuf); - - // Get all col names and all values - for (auto const& table_row : table) + sql << "INSERT INTO " << table_name <<"("; + for (auto const& col_value : values) { - if (!(table_row.flags & COL_AUTOINC)) - { - GncSqlColumnTypeHandler* pHandler; - - // Add col names to the list - pHandler = get_handler (table_row); - g_assert (pHandler != NULL); - pHandler->add_colname_to_list_fn (table_row, &colnames); - } + if (col_value != *values.begin()) + sql << ","; + sql << col_value.first; } - g_assert (colnames != NULL); - for (colname = colnames; colname != NULL; colname = colname->next) + sql << ") VALUES("; + for (auto col_value : values) { - if (colname != colnames) - { - g_string_append (sql, ","); - } - g_string_append (sql, (gchar*)colname->data); - g_free (colname->data); + if (col_value != *values.begin()) + sql << ","; + sql << + gnc_sql_connection_quote_string(be->conn, col_value.second.c_str()); } - g_list_free (colnames); - - g_string_append (sql, ") VALUES("); - values = create_gslist_from_values (be, obj_name, pObject, table); - for (node = values; node != NULL; node = node->next) - { - GValue* value = (GValue*)node->data; - gchar* value_str; - if (node != values) - { - (void)g_string_append (sql, ","); - } - value_str = gnc_sql_get_sql_value (be->conn, value); - (void)g_string_append (sql, value_str); - g_free (value_str); - (void)g_value_reset (value); - } - free_gvalue_list (values); - (void)g_string_append (sql, ")"); - - stmt = gnc_sql_connection_create_statement_from_sql (be->conn, sql->str); - (void)g_string_free (sql, TRUE); + sql << ")"; + stmt = gnc_sql_connection_create_statement_from_sql(be->conn, + sql.str().c_str()); return stmt; } @@ -2896,73 +2500,33 @@ build_update_statement (GncSqlBackend* be, const EntryVec& table) { GncSqlStatement* stmt; - GString* sql; - GSList* values; - GList* colnames = NULL; - GSList* value; - GList* colname; - gboolean firstCol; - gchar* sqlbuf; + std::ostringstream sql; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); g_return_val_if_fail (obj_name != NULL, NULL); g_return_val_if_fail (pObject != NULL, NULL); - // Get all col names and all values - for (auto const& table_row : table) - { - if (!(table_row.flags & COL_AUTOINC)) - { - GncSqlColumnTypeHandler* pHandler; - // Add col names to the list - pHandler = get_handler (table_row); - g_assert (pHandler != NULL); - pHandler->add_colname_to_list_fn (table_row, &colnames); - } - } - g_assert (colnames != NULL); - values = create_gslist_from_values (be, obj_name, pObject, table); + PairVec values{get_object_values (be, obj_name, pObject, table)}; // Create the SQL statement - sqlbuf = g_strdup_printf ("UPDATE %s SET ", table_name); - sql = g_string_new (sqlbuf); - g_free (sqlbuf); + sql << "UPDATE " << table_name << " SET "; - firstCol = TRUE; - for (colname = colnames->next, value = values->next; - colname != NULL && value != NULL; - colname = colname->next, value = value->next) + for (auto const& col_value : values) { - gchar* value_str; - if (!firstCol) - { - (void)g_string_append (sql, ","); - } - (void)g_string_append (sql, (gchar*)colname->data); - (void)g_string_append (sql, "="); - value_str = gnc_sql_get_sql_value (be->conn, (GValue*) (value->data)); - (void)g_string_append (sql, value_str); - g_free (value_str); - firstCol = FALSE; - } - for (colname = colnames; colname != NULL; colname = colname->next) - { - g_free (colname->data); - } - g_list_free (colnames); - if (value != NULL || colname != NULL) - { - PERR ("Mismatch in number of column names and values"); + if (col_value != *values.begin()) + sql << ","; + sql << col_value.first << "=" << + gnc_sql_connection_quote_string(be->conn, col_value.second.c_str()); } - stmt = gnc_sql_connection_create_statement_from_sql (be->conn, sql->str); - gnc_sql_statement_add_where_cond (stmt, obj_name, pObject, table[0], - (GValue*) (values->data)); - free_gvalue_list (values); - (void)g_string_free (sql, TRUE); - + stmt = gnc_sql_connection_create_statement_from_sql(be->conn, sql.str().c_str()); + /* We want our where condition to be just the first column and + * value, i.e. the guid of the object. + */ + values.erase(values.begin() + 1, values.end()); + gnc_sql_statement_add_where_cond(stmt, obj_name, pObject, values); return stmt; } @@ -2974,26 +2538,24 @@ build_delete_statement (GncSqlBackend* be, { GncSqlStatement* stmt; GncSqlColumnTypeHandler* pHandler; - GSList* list = NULL; - gchar* sqlbuf; + std::ostringstream sql; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); g_return_val_if_fail (obj_name != NULL, NULL); g_return_val_if_fail (pObject != NULL, NULL); - sqlbuf = g_strdup_printf ("DELETE FROM %s ", table_name); - stmt = gnc_sql_connection_create_statement_from_sql (be->conn, sqlbuf); - g_free (sqlbuf); + sql << "DELETE FROM " << table_name; + stmt = gnc_sql_connection_create_statement_from_sql (be->conn, + sql.str().c_str()); /* WHERE */ pHandler = get_handler (table[0]); g_assert (pHandler != NULL); - pHandler->add_gvalue_to_slist_fn (be, obj_name, pObject, table[0], &list); - g_assert (list != NULL); - gnc_sql_statement_add_where_cond (stmt, obj_name, pObject, table[0], - (GValue*) (list->data)); - free_gvalue_list (list); + PairVec values; + pHandler->add_value_to_vec_fn (be, obj_name, pObject, table[0], values); + PairVec col_values{values[0]}; + gnc_sql_statement_add_where_cond (stmt, obj_name, pObject, col_values); return stmt; } @@ -3339,4 +2901,32 @@ gnc_sql_set_table_version (GncSqlBackend* be, const gchar* table_name, return TRUE; } +/* This is necessary for 64-bit builds because g++ complains + * that reinterpret_casting a void* (64 bits) to an int (32 bits) + * loses precision, so we have to explicitly dispose of the precision. + * FIXME: We shouldn't be storing ints in ptrs in the first place. + */ +#ifdef __LP64__ +template <> int +get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, + const GncSqlColumnTableEntry& table_row, std::false_type) +{ + g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, 0); + int result = 0; + if (table_row.gobj_param_name != nullptr) + g_object_get(pObject, table_row.gobj_param_name, &result, NULL ); + else + { + QofAccessFunc getter = gnc_sql_get_getter(obj_name, table_row); + if (getter != nullptr) + { + auto value = ((getter)(pObject, nullptr)); + result = reinterpret_cast(value) & + UINT64_C(0x00000000FFFFFFFF); + } + } + return result; +} +#endif + /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index e2d0b82764..d1cbcb72a9 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -55,7 +55,8 @@ struct GncSqlColumnInfo; struct GncSqlColumnTableEntry; using EntryVec = std::vector; using ColVec = std::vector; -using LoadOrder = std::vector; +using StrVec = std::vector; +using PairVec = std::vector>; typedef struct GncSqlConnection GncSqlConnection; /** @@ -153,14 +154,14 @@ struct GncSqlStatement void (*dispose) (GncSqlStatement*); gchar* (*toSql) (GncSqlStatement*); void (*addWhereCond) (GncSqlStatement*, QofIdTypeConst, gpointer, - const GncSqlColumnTableEntry&, GValue*); + const PairVec&); }; #define gnc_sql_statement_dispose(STMT) \ (STMT)->dispose(STMT) #define gnc_sql_statement_to_sql(STMT) \ (STMT)->toSql(STMT) -#define gnc_sql_statement_add_where_cond(STMT,TYPENAME,OBJ,COLDESC,VALUE) \ - (STMT)->addWhereCond(STMT, TYPENAME, OBJ, COLDESC, VALUE) +#define gnc_sql_statement_add_where_cond(STMT,TYPENAME,OBJ,COL_VAL_PAIR) \ + (STMT)->addWhereCond(STMT, TYPENAME, OBJ, COL_VAL_PAIR) /** * @struct GncSqlConnection @@ -181,7 +182,7 @@ struct GncSqlConnection gboolean (*createTable) (GncSqlConnection*, const gchar*, const ColVec&); /**< Returns TRUE if successful, FALSE if error */ gboolean (*createIndex) (GncSqlConnection*, const gchar*, const gchar*, const EntryVec&); /**< Returns TRUE if successful, FALSE if error */ gboolean (*addColumnsToTable) (GncSqlConnection*, const gchar* table, const ColVec&); /**< Returns TRUE if successful, FALSE if error */ - gchar* (*quoteString) (const GncSqlConnection*, gchar*); + gchar* (*quoteString) (const GncSqlConnection*, const char*); }; #define gnc_sql_connection_dispose(CONN) (CONN)->dispose(CONN) #define gnc_sql_connection_execute_select_statement(CONN,STMT) \ @@ -434,18 +435,17 @@ typedef enum } E_DB_OPERATION; typedef void (*GNC_SQL_LOAD_FN) (const GncSqlBackend* be, - GncSqlRow* row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table); + GncSqlRow* row, QofSetterFunc setter, + gpointer pObject, + const GncSqlColumnTableEntry& table_row); typedef void (*GNC_SQL_ADD_COL_INFO_TO_LIST_FN) (const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, + const GncSqlColumnTableEntry& table_row, ColVec& vec); -typedef void (*GNC_SQL_ADD_COLNAME_TO_LIST_FN) (const GncSqlColumnTableEntry& table_row, GList** pList); -typedef void (*GNC_SQL_ADD_GVALUE_TO_SLIST_FN) (const GncSqlBackend* be, - QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList); +typedef void (*GNC_SQL_ADD_VALUE_TO_VEC_FN) (const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec); /** * @struct GncSqlColumnTypeHandler @@ -469,14 +469,11 @@ typedef struct GNC_SQL_ADD_COL_INFO_TO_LIST_FN add_col_info_to_list_fn; /** - * Routine to add a column name string for the column type to a GList. + * Add a pair of the table column heading and object's value's string + * representation to a PairVec; used for constructing WHERE clauses and + * UPDATE statements. */ - GNC_SQL_ADD_COLNAME_TO_LIST_FN add_colname_to_list_fn; - - /** - * Routine to add a GValue for the property to a GSList. - */ - GNC_SQL_ADD_GVALUE_TO_SLIST_FN add_gvalue_to_slist_fn; + GNC_SQL_ADD_VALUE_TO_VEC_FN add_value_to_vec_fn; } GncSqlColumnTypeHandler; /** @@ -489,16 +486,6 @@ typedef struct QofAccessFunc gnc_sql_get_getter (QofIdTypeConst obj_name, const GncSqlColumnTableEntry& table_row); -/** - * Adds a column name to a list. If the column type spans multiple columns, - * all of the column names for the pieces are added. - * - * @param table_row DB table column - * @param pList List - */ -void gnc_sql_add_colname_to_list (const GncSqlColumnTableEntry& table_row, - GList** pList); - /** * Performs an operation on the database. * @@ -691,11 +678,11 @@ void gnc_sql_register_col_type_handler (const gchar* colType, * @param table_row DB table column description * @param pList List */ -void gnc_sql_add_gvalue_objectref_guid_to_slist (const GncSqlBackend* be, - QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList); +void gnc_sql_add_objectref_guid_to_vec (const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec); /** * Adds a column info structure for an object reference GncGUID to the end of a @@ -720,28 +707,6 @@ void gnc_sql_add_objectref_guid_col_info_to_list (const GncSqlBackend* be, guint gnc_sql_append_guid_list_to_sql (GString* str, GList* list, guint maxCount); -/** - * Appends column names for a subtable to the end of a GList. - * - * @param table_row Main DB column description - * @param subtable Sub-column description table - * @param pList List - */ -void gnc_sql_add_subtable_colnames_to_list (const GncSqlColumnTableEntry& table_row, - const EntryVec& subtable, - GList** pList); - -/** - * Returns a string corresponding to the SQL representation of a GValue. The - * caller must free the string. - * - * @param conn SQL connection - * @param value Value to be converted - * @return String - */ -gchar* gnc_sql_get_sql_value (const GncSqlConnection* conn, - const GValue* value); - /** * Initializes DB table version information. * @@ -822,7 +787,7 @@ gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const char* table_name * * @param load_order NULL-terminated array of object type ID strings */ -void gnc_sql_set_load_order(LoadOrder&& load_order); +void gnc_sql_set_load_order(StrVec&& load_order); void _retrieve_guid_ (gpointer pObject, gpointer pValue); @@ -836,6 +801,95 @@ typedef struct gboolean is_ok; } write_objects_t; +template T +get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, + const GncSqlColumnTableEntry& table_row) +{ + return get_row_value_from_object(obj_name, pObject, table_row, + std::is_pointer()); +} + +template T +get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + std::true_type) +{ + g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, nullptr); + T result = nullptr; + if (table_row.gobj_param_name != nullptr) + g_object_get(pObject, table_row.gobj_param_name, &result, NULL ); + else + { + QofAccessFunc getter = gnc_sql_get_getter(obj_name, table_row); + if (getter != nullptr) + result = reinterpret_cast((getter)(pObject, nullptr)); + } + return result; +} + +template T +get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + std::false_type) +{ + g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, + static_cast(0)); + T result = static_cast(0); + if (table_row.gobj_param_name != nullptr) + g_object_get(pObject, table_row.gobj_param_name, &result, NULL ); + else + { + QofAccessFunc getter = gnc_sql_get_getter(obj_name, table_row); + if (getter != nullptr) + result = reinterpret_cast((getter)(pObject, nullptr)); + } + return result; +} + +template void +add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec) +{ + add_value_to_vec(be, obj_name, pObject, table_row, vec, + std::is_pointer()); +} + +template void +add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec, std::true_type) +{ + T s = get_row_value_from_object(obj_name, pObject, table_row); + + if (s != nullptr) + { + std::ostringstream stream; + stream << *s; + vec.emplace_back(std::make_pair(std::string{table_row.col_name}, + stream.str())); + return; + } +} + +template void +add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec, std::false_type) +{ + T s = get_row_value_from_object(obj_name, pObject, table_row); + + std::ostringstream stream; + stream << s; + vec.emplace_back(std::make_pair(std::string{table_row.col_name}, + stream.str())); + return; +} + + #endif /* GNC_BACKEND_SQL_H */ /** diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index ea609011de..abfc0ab24c 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -390,8 +390,7 @@ load_billterm_guid (const GncSqlBackend* be, GncSqlRow* row, static GncSqlColumnTypeHandler billterm_guid_handler = { load_billterm_guid, gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_colname_to_list, - gnc_sql_add_gvalue_objectref_guid_to_slist + gnc_sql_add_objectref_guid_to_vec }; /* ================================================================= */ void diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index 6be0140eaa..88df5e65bf 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -522,8 +522,7 @@ load_budget_guid (const GncSqlBackend* be, GncSqlRow* row, static GncSqlColumnTypeHandler budget_guid_handler = { load_budget_guid, gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_colname_to_list, - gnc_sql_add_gvalue_objectref_guid_to_slist + gnc_sql_add_objectref_guid_to_vec }; /* ================================================================= */ void diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index d571d7e7b2..5a1e815862 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -314,8 +314,7 @@ load_commodity_guid (const GncSqlBackend* be, GncSqlRow* row, static GncSqlColumnTypeHandler commodity_guid_handler = { load_commodity_guid, gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_colname_to_list, - gnc_sql_add_gvalue_objectref_guid_to_slist + gnc_sql_add_objectref_guid_to_vec }; /* ================================================================= */ void diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index c02d3d5aad..236b4a5abd 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -325,8 +325,7 @@ load_invoice_guid (const GncSqlBackend* be, GncSqlRow* row, static GncSqlColumnTypeHandler invoice_guid_handler = { load_invoice_guid, gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_colname_to_list, - gnc_sql_add_gvalue_objectref_guid_to_slist + gnc_sql_add_objectref_guid_to_vec }; /* ================================================================= */ void diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index e541fbebfc..15aff46607 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -256,8 +256,7 @@ load_lot_guid (const GncSqlBackend* be, GncSqlRow* row, static GncSqlColumnTypeHandler lot_guid_handler = { load_lot_guid, gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_colname_to_list, - gnc_sql_add_gvalue_objectref_guid_to_slist + gnc_sql_add_objectref_guid_to_vec }; /* ================================================================= */ void diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index 74a036ea49..525d312dab 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -240,8 +240,7 @@ load_order_guid (const GncSqlBackend* be, GncSqlRow* row, static GncSqlColumnTypeHandler order_guid_handler = { load_order_guid, gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_colname_to_list, - gnc_sql_add_gvalue_objectref_guid_to_slist + gnc_sql_add_objectref_guid_to_vec }; /* ================================================================= */ void diff --git a/src/backend/sql/gnc-owner-sql.cpp b/src/backend/sql/gnc-owner-sql.cpp index 279853485e..d25d939669 100644 --- a/src/backend/sql/gnc-owner-sql.cpp +++ b/src/backend/sql/gnc-owner-sql.cpp @@ -191,50 +191,33 @@ add_owner_col_info_to_list(const GncSqlBackend* be, } static void -add_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pList) +add_value_owner_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, + const gpointer pObject, + const GncSqlColumnTableEntry& table_row, + PairVec& vec) { - gchar* buf; - - buf = g_strdup_printf ("%s_type", table_row.col_name); - (*pList) = g_list_append ((*pList), buf); - buf = g_strdup_printf ("%s_guid", table_row.col_name); - (*pList) = g_list_append ((*pList), buf); -} - -static void -add_gvalue_owner_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - GSList** pList) -{ - GValue* subfield_value; - GncOwner* owner; - gchar* buf; - const GncGUID* guid; - gchar guid_buf[GUID_ENCODING_LENGTH + 1]; - GncOwnerType type; - QofInstance* inst = NULL; - OwnerGetterFunc getter; - g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - getter = (OwnerGetterFunc)gnc_sql_get_getter (obj_name, table_row); - owner = (*getter) (pObject); + auto getter = (OwnerGetterFunc)gnc_sql_get_getter (obj_name, table_row); + auto owner = (*getter) (pObject); - if (owner != NULL) + QofInstance* inst = nullptr; + GncOwnerType type; + + std::ostringstream buf; + + buf << table_row.col_name << "_type"; + std::string type_hdr{buf.str()}; + buf.str(""); + buf << table_row.col_name << "_guid"; + std::string guid_hdr{buf.str()}; + buf.str(""); + + if (owner != nullptr) { - buf = g_strdup_printf ("%s_type", table_row.col_name); - subfield_value = g_new0 (GValue, 1); - g_value_init (subfield_value, G_TYPE_INT); type = gncOwnerGetType (owner); - g_value_set_int (subfield_value, type); - (*pList) = g_slist_append ((*pList), subfield_value); - g_free (buf); - - buf = g_strdup_printf ("%s_guid", table_row.col_name); - subfield_value = g_new0 (GValue, 1); switch (type) { case GNC_OWNER_CUSTOMER: @@ -256,37 +239,31 @@ add_gvalue_owner_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, default: PWARN ("Invalid owner type: %d\n", type); } - g_value_init (subfield_value, G_TYPE_STRING); - if (inst != NULL) - { - guid = qof_instance_get_guid (inst); - if (guid != NULL) - { - (void)guid_to_string_buff (guid, guid_buf); - g_value_take_string (subfield_value, g_strdup_printf ("%s", guid_buf)); - } - } - (*pList) = g_slist_append ((*pList), subfield_value); - g_free (buf); } - else + + if (inst == nullptr) { - subfield_value = g_new0 (GValue, 1); - g_value_init (subfield_value, G_TYPE_STRING); - g_value_set_string (subfield_value, "NULL"); - (*pList) = g_slist_append ((*pList), subfield_value); - subfield_value = g_new0 (GValue, 1); - g_value_init (subfield_value, G_TYPE_STRING); - g_value_set_string (subfield_value, "NULL"); - (*pList) = g_slist_append ((*pList), subfield_value); + /* Twice, once for type, once for guid. */ + vec.emplace_back (std::make_pair (type_hdr, std::string{"NULL"})); + vec.emplace_back (std::make_pair (guid_hdr, std::string{"NULL"})); + + return; } + buf << type; + vec.emplace_back(std::make_pair(type_hdr, buf.str())); + buf.str(""); + auto guid = qof_instance_get_guid(inst); + if (guid != nullptr) + buf << guid; + else + buf << "NULL"; + vec.emplace_back(std::make_pair(guid_hdr, buf.str())); } static GncSqlColumnTypeHandler owner_handler = { load_owner, add_owner_col_info_to_list, - add_colname_to_list, - add_gvalue_owner_to_slist + add_value_owner_to_vec }; /* ================================================================= */ diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index b0f4b689d7..b1dc6c687a 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -546,8 +546,7 @@ load_taxtable_guid (const GncSqlBackend* be, GncSqlRow* row, static GncSqlColumnTypeHandler taxtable_guid_handler = { load_taxtable_guid, gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_colname_to_list, - gnc_sql_add_gvalue_objectref_guid_to_slist + gnc_sql_add_objectref_guid_to_vec }; /* ================================================================= */ void diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index 41fd3d29bc..a65963a7f5 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -1491,8 +1491,7 @@ load_tx_guid (const GncSqlBackend* be, GncSqlRow* row, static GncSqlColumnTypeHandler tx_guid_handler = { load_tx_guid, gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_colname_to_list, - gnc_sql_add_gvalue_objectref_guid_to_slist + gnc_sql_add_objectref_guid_to_vec }; /* ================================================================= */ void diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index b8c6e0db48..b2feed203f 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -556,12 +556,12 @@ test_add_gvalue_guid_to_slist (Fixture *fixture, gconstpointer pData) { }*/ // Not Used -/* gnc_sql_add_gvalue_objectref_guid_to_slist +/* gnc_sql_add_objectref_guid_to_vec void -gnc_sql_add_gvalue_objectref_guid_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name,// 1 +gnc_sql_add_objectref_guid_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name,// 1 */ /* static void -test_gnc_sql_add_gvalue_objectref_guid_to_slist (Fixture *fixture, gconstpointer pData) +test_gnc_sql_add_objectref_guid_to_vec (Fixture *fixture, gconstpointer pData) { }*/ // Not Used @@ -624,12 +624,12 @@ add_timespec_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableE test_add_timespec_col_info_to_list (Fixture *fixture, gconstpointer pData) { }*/ -/* add_gvalue_timespec_to_slist +/* add_value_timespec_to_vec static void add_gvalue_timespec_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name,// 2 */ /* static void -test_add_gvalue_timespec_to_slist (Fixture *fixture, gconstpointer pData) +test_add_value_timespec_to_vec (Fixture *fixture, gconstpointer pData) { }*/ /* load_date @@ -648,12 +648,12 @@ add_date_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry test_add_date_col_info_to_list (Fixture *fixture, gconstpointer pData) { }*/ -/* add_gvalue_date_to_slist +/* add_value_date_to_vec static void -add_gvalue_date_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name,// 2 +add_value_date_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name,// 2 */ /* static void -test_add_gvalue_date_to_slist (Fixture *fixture, gconstpointer pData) +test_add_value_date_to_vec (Fixture *fixture, gconstpointer pData) { }*/ /* load_numeric @@ -680,12 +680,12 @@ add_numeric_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pL test_add_numeric_colname_to_list (Fixture *fixture, gconstpointer pData) { }*/ -/* add_gvalue_numeric_to_slist +/* add_value_numeric_to_vec static void -add_gvalue_numeric_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name,// 2 +add_value_numeric_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name,// 2 */ /* static void -test_add_gvalue_numeric_to_slist (Fixture *fixture, gconstpointer pData) +test_add_value_numeric_to_vec (Fixture *fixture, gconstpointer pData) { }*/ /* get_handler @@ -980,36 +980,36 @@ test_suite_gnc_backend_sql (void) // GNC_TEST_ADD (suitename, "gnc sql add subtable colnames to list", Fixture, nullptr, test_gnc_sql_add_subtable_colnames_to_list, teardown); // GNC_TEST_ADD (suitename, "load string", Fixture, nullptr, test_load_string, teardown); // GNC_TEST_ADD (suitename, "add string col info to list", Fixture, nullptr, test_add_string_col_info_to_list, teardown); -// GNC_TEST_ADD (suitename, "add gvalue string to slist", Fixture, nullptr, test_add_gvalue_string_to_slist, teardown); +// GNC_TEST_ADD (suitename, "add value string to vec", Fixture, nullptr, test_add_value_string_to_vec, teardown); // GNC_TEST_ADD (suitename, "load int", Fixture, nullptr, test_load_int, teardown); // GNC_TEST_ADD (suitename, "add int col info to list", Fixture, nullptr, test_add_int_col_info_to_list, teardown); -// GNC_TEST_ADD (suitename, "add gvalue int to slist", Fixture, nullptr, test_add_gvalue_int_to_slist, teardown); +// GNC_TEST_ADD (suitename, "add value int to vec", Fixture, nullptr, test_add_value_int_to_vec, teardown); // GNC_TEST_ADD (suitename, "load boolean", Fixture, nullptr, test_load_boolean, teardown); // GNC_TEST_ADD (suitename, "add boolean col info to list", Fixture, nullptr, test_add_boolean_col_info_to_list, teardown); -// GNC_TEST_ADD (suitename, "add gvalue boolean to slist", Fixture, nullptr, test_add_gvalue_boolean_to_slist, teardown); +// GNC_TEST_ADD (suitename, "add value boolean to vec", Fixture, nullptr, test_add_value_boolean_to_vec, teardown); // GNC_TEST_ADD (suitename, "load int64", Fixture, nullptr, test_load_int64, teardown); // GNC_TEST_ADD (suitename, "add int64 col info to list", Fixture, nullptr, test_add_int64_col_info_to_list, teardown); -// GNC_TEST_ADD (suitename, "add gvalue int64 to slist", Fixture, nullptr, test_add_gvalue_int64_to_slist, teardown); +// GNC_TEST_ADD (suitename, "add value int64 to vec", Fixture, nullptr, test_add_value_int64_to_vec, teardown); // GNC_TEST_ADD (suitename, "load double", Fixture, nullptr, test_load_double, teardown); // GNC_TEST_ADD (suitename, "add double col info to list", Fixture, nullptr, test_add_double_col_info_to_list, teardown); -// GNC_TEST_ADD (suitename, "add gvalue double to slist", Fixture, nullptr, test_add_gvalue_double_to_slist, teardown); +// GNC_TEST_ADD (suitename, "add value double to vec", Fixture, nullptr, test_add_value_double_to_vec, teardown); // GNC_TEST_ADD (suitename, "load guid", Fixture, nullptr, test_load_guid, teardown); // GNC_TEST_ADD (suitename, "add guid col info to list", Fixture, nullptr, test_add_guid_col_info_to_list, teardown); -// GNC_TEST_ADD (suitename, "add gvalue guid to slist", Fixture, nullptr, test_add_gvalue_guid_to_slist, teardown); -// GNC_TEST_ADD (suitename, "gnc sql add gvalue objectref guid to slist", Fixture, nullptr, test_gnc_sql_add_gvalue_objectref_guid_to_slist, teardown); +// GNC_TEST_ADD (suitename, "add value guid to vec", Fixture, nullptr, test_add_value_guid_to_vec, teardown); +// GNC_TEST_ADD (suitename, "gnc sql add gvalue objectref guid to slist", Fixture, nullptr, test_gnc_sql_add_objectref_guid_to_vec, teardown); // GNC_TEST_ADD (suitename, "gnc sql add objectref guid col info to list", Fixture, nullptr, test_gnc_sql_add_objectref_guid_col_info_to_list, teardown); GNC_TEST_ADD_FUNC (suitename, "gnc sql convert timespec to string", test_gnc_sql_convert_timespec_to_string); // GNC_TEST_ADD (suitename, "load timespec", Fixture, nullptr, test_load_timespec, teardown); // GNC_TEST_ADD (suitename, "add timespec col info to list", Fixture, nullptr, test_add_timespec_col_info_to_list, teardown); -// GNC_TEST_ADD (suitename, "add gvalue timespec to slist", Fixture, nullptr, test_add_gvalue_timespec_to_slist, teardown); +// GNC_TEST_ADD (suitename, "add value timespec to vec", Fixture, nullptr, test_add_value_timespec_to_vec, teardown); // GNC_TEST_ADD (suitename, "load date", Fixture, nullptr, test_load_date, teardown); // GNC_TEST_ADD (suitename, "add date col info to list", Fixture, nullptr, test_add_date_col_info_to_list, teardown); -// GNC_TEST_ADD (suitename, "add gvalue date to slist", Fixture, nullptr, test_add_gvalue_date_to_slist, teardown); +// GNC_TEST_ADD (suitename, "add value date to vec", Fixture, nullptr, test_add_value_date_to_vec, teardown); // GNC_TEST_ADD (suitename, "load numeric", Fixture, nullptr, test_load_numeric, teardown); // GNC_TEST_ADD (suitename, "add numeric col info to list", Fixture, nullptr, test_add_numeric_col_info_to_list, teardown); // GNC_TEST_ADD (suitename, "add numeric colname to list", Fixture, nullptr, test_add_numeric_colname_to_list, teardown); -// GNC_TEST_ADD (suitename, "add gvalue numeric to slist", Fixture, nullptr, test_add_gvalue_numeric_to_slist, teardown); +// GNC_TEST_ADD (suitename, "add value numeric to vec", Fixture, nullptr, test_add_value_numeric_to_vec, teardown); // GNC_TEST_ADD (suitename, "get handler", Fixture, nullptr, test_get_handler, teardown); // GNC_TEST_ADD (suitename, "register standard col type handlers", Fixture, nullptr, test_register_standard_col_type_handlers, teardown); // GNC_TEST_ADD (suitename, " retrieve guid ", Fixture, nullptr, test__retrieve_guid_, teardown); diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp index e24796daae..058f50c275 100644 --- a/src/libqof/qof/gnc-datetime.hpp +++ b/src/libqof/qof/gnc-datetime.hpp @@ -39,6 +39,8 @@ typedef struct class GncDateImpl; class GncDateTimeImpl; using time64 = int64_t; +constexpr const time64 MINTIME = -17987443200; +constexpr const time64 MAXTIME = 253402214400; class GncDate { From 7e3ba421d77f05389b163e4f52c8b1f8b6f84798 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 11 Mar 2016 16:36:32 -0800 Subject: [PATCH 07/63] Fix potential dereference error. Thanks Geert Janssens. --- src/backend/sql/gnc-backend-sql.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 989bb02767..787b0df38d 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -267,6 +267,8 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) [type](const OBEEntry& entry){ return type == std::get<0>(entry); }); + if (entry == backend_registry.end()) + continue; auto obe = std::get<1>(*entry); if (entry != backend_registry.end() && obe->initial_load != nullptr) From 2f0b5ec8fee49c729938a920740fdcf846615668 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 26 Mar 2016 17:53:17 -0700 Subject: [PATCH 08/63] Remove tabs from gnc-backend-sql*. --- src/backend/sql/gnc-backend-sql.cpp | 8 ++++---- src/backend/sql/gnc-backend-sql.h | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 787b0df38d..2e43bb386e 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -1343,11 +1343,11 @@ load_boolean (const GncSqlBackend* be, GncSqlRow* row, } if (table_row.gobj_param_name != nullptr) { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); g_object_set (pObject, table_row.gobj_param_name, int_value, nullptr); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } else { diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index d1cbcb72a9..7ccd032adc 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -1,4 +1,3 @@ - /******************************************************************** * gnc-backend-sql.h: load and save data to SQL * * * @@ -262,8 +261,8 @@ struct GncSqlResult */ typedef struct { - int version; /**< Backend version number */ - const std::string type_name; /**< Engine object type name */ + int version; /**< Backend version number */ + const std::string type_name; /**< Engine object type name */ /** Commit an instance of this object to the database * @return TRUE if successful, FALSE if error */ @@ -284,7 +283,7 @@ typedef struct gboolean (*write) (GncSqlBackend* be); } GncSqlObjectBackend; #define GNC_SQL_BACKEND "gnc:sql:1" -#define GNC_SQL_BACKEND_VERSION 1 +#define GNC_SQL_BACKEND_VERSION 1 using GncSqlObjectBackendPtr = GncSqlObjectBackend*; using OBEEntry = std::tuple; using OBEVec = std::vector; @@ -473,7 +472,7 @@ typedef struct * representation to a PairVec; used for constructing WHERE clauses and * UPDATE statements. */ - GNC_SQL_ADD_VALUE_TO_VEC_FN add_value_to_vec_fn; + GNC_SQL_ADD_VALUE_TO_VEC_FN add_value_to_vec_fn; } GncSqlColumnTypeHandler; /** From 8078c41a3535beaf982622eab20da181d9f4298a Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 27 Mar 2016 23:48:02 -0700 Subject: [PATCH 09/63] Make GncSqlRow a class and replace GValues with typed transfer functions. --- src/backend/dbi/gnc-backend-dbi-priv.h | 18 + src/backend/dbi/gnc-backend-dbi.cpp | 230 ++++------- src/backend/sql/gnc-account-sql.cpp | 10 +- src/backend/sql/gnc-address-sql.cpp | 51 ++- src/backend/sql/gnc-backend-sql.cpp | 517 ++++++++++-------------- src/backend/sql/gnc-backend-sql.h | 20 +- src/backend/sql/gnc-bill-term-sql.cpp | 11 +- src/backend/sql/gnc-budget-sql.cpp | 10 +- src/backend/sql/gnc-commodity-sql.cpp | 11 +- src/backend/sql/gnc-invoice-sql.cpp | 11 +- src/backend/sql/gnc-lots-sql.cpp | 11 +- src/backend/sql/gnc-order-sql.cpp | 11 +- src/backend/sql/gnc-owner-sql.cpp | 28 +- src/backend/sql/gnc-slots-sql.cpp | 23 +- src/backend/sql/gnc-tax-table-sql.cpp | 11 +- src/backend/sql/gnc-transaction-sql.cpp | 12 +- 16 files changed, 412 insertions(+), 573 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi-priv.h b/src/backend/dbi/gnc-backend-dbi-priv.h index 09d2f73666..0e0d3b6762 100644 --- a/src/backend/dbi/gnc-backend-dbi-priv.h +++ b/src/backend/dbi/gnc-backend-dbi-priv.h @@ -119,4 +119,22 @@ typedef struct /* external access required for tests */ std::string adjust_sql_options_string(const std::string&); +class GncDbiSqlRow : public GncSqlRow +{ +public: + GncDbiSqlRow (dbi_result result) : m_result{result} {} + ~GncDbiSqlRow() = default; + int64_t get_int_at_col(const char*); + float get_float_at_col(const char*); + double get_double_at_col(const char*); + std::string get_string_at_col(const char*); + time64 get_time64_at_col(const char*); + bool is_col_null(const char* col) const noexcept + { + return dbi_result_field_is_null(m_result, col); + } +private: + dbi_result m_result; +}; + #endif //GNC_BACKEND_DBI_PRIV_H diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 9b67cbb0ca..db0c1ec04b 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -2156,143 +2156,95 @@ gnc_module_finalize_backend_dbi (void) } /* --------------------------------------------------------- */ -typedef struct + +int64_t +GncDbiSqlRow::get_int_at_col(const char* col) { - GncSqlRow base; - - dbi_result result; - GList* gvalue_list; -} GncDbiSqlRow; - -static void -row_dispose (GncSqlRow* row) -{ - GncDbiSqlRow* dbi_row = (GncDbiSqlRow*)row; - GList* node; - - if (dbi_row->gvalue_list != NULL) - { - for (node = dbi_row->gvalue_list; node != NULL; node = node->next) - { - GValue* value; - if (!G_IS_VALUE (node->data)) - continue; - value = (GValue*)node->data; - if (G_VALUE_HOLDS_STRING (value)) - { - g_free ((gpointer)g_value_get_string (value)); - } - g_free (value); - } - g_list_free (dbi_row->gvalue_list); - } - g_free (dbi_row); + auto type = dbi_result_get_field_type (m_result, col); + if(type != DBI_TYPE_INTEGER) + throw (std::invalid_argument{"Requested integer from non-integer column."}); + return dbi_result_get_longlong (m_result, col); } -static const GValue* -row_get_value_at_col_name (GncSqlRow* row, const gchar* col_name) +float +GncDbiSqlRow::get_float_at_col(const char* col) { - GncDbiSqlRow* dbi_row = (GncDbiSqlRow*)row; - gushort type; - guint attrs; - GValue *value; + auto type = dbi_result_get_field_type (m_result, col); + auto attrs = dbi_result_get_field_attribs (m_result, col); + if(type != DBI_TYPE_DECIMAL || + (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE4) + throw (std::invalid_argument{"Requested float from non-float column."}); + gnc_push_locale (LC_NUMERIC, "C"); + auto retval = dbi_result_get_float(m_result, col); + gnc_pop_locale (LC_NUMERIC); + return retval; +} - type = dbi_result_get_field_type (dbi_row->result, col_name); - attrs = dbi_result_get_field_attribs (dbi_row->result, col_name); +double +GncDbiSqlRow::get_double_at_col(const char* col) +{ + auto type = dbi_result_get_field_type (m_result, col); + auto attrs = dbi_result_get_field_attribs (m_result, col); + if(type != DBI_TYPE_DECIMAL || + (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE8) + throw (std::invalid_argument{"Requested double from non-double column."}); + gnc_push_locale (LC_NUMERIC, "C"); + auto retval = dbi_result_get_double(m_result, col); + gnc_pop_locale (LC_NUMERIC); + return retval; +} - switch (type) +std::string +GncDbiSqlRow::get_string_at_col(const char* col) +{ + auto type = dbi_result_get_field_type (m_result, col); + auto attrs = dbi_result_get_field_attribs (m_result, col); + if(type != DBI_TYPE_STRING) + throw (std::invalid_argument{"Requested string from non-string column."}); + gnc_push_locale (LC_NUMERIC, "C"); + auto strval = dbi_result_get_string(m_result, col); + if (strval == nullptr) { - case DBI_TYPE_INTEGER: - value = g_new0 (GValue, 1); - g_assert (value != NULL); - (void)g_value_init (value, G_TYPE_INT64); - g_value_set_int64 (value, dbi_result_get_longlong (dbi_row->result, col_name)); - break; - case DBI_TYPE_DECIMAL: - gnc_push_locale (LC_NUMERIC, "C"); - if ((attrs & DBI_DECIMAL_SIZEMASK) == DBI_DECIMAL_SIZE4) - { - value = g_new0 (GValue, 1); - g_assert (value != NULL); - (void)g_value_init (value, G_TYPE_FLOAT); - g_value_set_float (value, dbi_result_get_float (dbi_row->result, col_name)); - } - else if ((attrs & DBI_DECIMAL_SIZEMASK) == DBI_DECIMAL_SIZE8) - { - value = g_new0 (GValue, 1); - g_assert (value != NULL); - (void)g_value_init (value, G_TYPE_DOUBLE); - g_value_set_double (value, dbi_result_get_double (dbi_row->result, col_name)); - } - else - { - PERR ("Field %s: strange decimal length attrs=%d\n", col_name, attrs); - } gnc_pop_locale (LC_NUMERIC); - break; - case DBI_TYPE_STRING: - value = g_new0 (GValue, 1); - g_assert (value != NULL); - (void)g_value_init (value, G_TYPE_STRING); - g_value_take_string (value, dbi_result_get_string_copy (dbi_row->result, - col_name)); - break; - case DBI_TYPE_DATETIME: - if (dbi_result_field_is_null (dbi_row->result, col_name)) - { - return NULL; - } - else - { -#if HAVE_LIBDBI_TO_LONGLONG - /* A less evil hack than the one equrie by libdbi-0.8, but - * still necessary to work around the same bug. - */ - time64 time = dbi_result_get_as_longlong(dbi_row->result, - col_name); -#else - /* A seriously evil hack to work around libdbi bug #15 - * https://sourceforge.net/p/libdbi/bugs/15/. When libdbi - * v0.9 is widely available this can be replaced with - * dbi_result_get_as_longlong. - */ - dbi_result_t* result = (dbi_result_t*) (dbi_row->result); - guint64 row = dbi_result_get_currow (result); - guint idx = dbi_result_get_field_idx (result, col_name) - 1; - time64 time = result->rows[row]->field_values[idx].d_datetime; - if (time < MINTIME || time > MAXTIME) - return nullptr; - value = g_new0 (GValue, 1); - g_assert (value != NULL); -#endif //HAVE_LIBDBI_TO_LONGLONG - - (void)g_value_init (value, G_TYPE_INT64); - g_value_set_int64 (value, time); - } - break; - default: - PERR ("Field %s: unknown DBI_TYPE: %d\n", col_name, type); - return NULL; + throw (std::invalid_argument{"Column empty."}); } - - dbi_row->gvalue_list = g_list_prepend (dbi_row->gvalue_list, value); - return value; + auto retval = std::string{strval}; + gnc_pop_locale (LC_NUMERIC); + return retval; } - -static GncSqlRow* -create_dbi_row (dbi_result result) +time64 +GncDbiSqlRow::get_time64_at_col (const char* col) { - GncDbiSqlRow* row; - - row = g_new0 (GncDbiSqlRow, 1); - g_assert (row != NULL); - - row->base.getValueAtColName = row_get_value_at_col_name; - row->base.dispose = row_dispose; - row->result = result; - - return (GncSqlRow*)row; + auto type = dbi_result_get_field_type (m_result, col); + auto attrs = dbi_result_get_field_attribs (m_result, col); + if (type != DBI_TYPE_DATETIME) + throw (std::invalid_argument{"Requested double from non-double column."}); + gnc_push_locale (LC_NUMERIC, "C"); +#if HAVE_LIBDBI_TO_LONGLONG + /* A less evil hack than the one equrie by libdbi-0.8, but + * still necessary to work around the same bug. + */ + auto retval = dbi_result_get_as_longlong(dbi_row->result, + col_name); +#else + /* A seriously evil hack to work around libdbi bug #15 + * https://sourceforge.net/p/libdbi/bugs/15/. When libdbi + * v0.9 is widely available this can be replaced with + * dbi_result_get_as_longlong. + * Note: 0.9 is available in Debian Jessie and Fedora 21. + */ + auto result = (dbi_result_t*) (m_result); + auto row = dbi_result_get_currow (result); + auto idx = dbi_result_get_field_idx (result, col) - 1; + time64 retval = result->rows[row]->field_values[idx].d_datetime; + if (retval < MINTIME || retval > MAXTIME) + retval = 0; +#endif //HAVE_LIBDBI_TO_LONGLONG + gnc_pop_locale (LC_NUMERIC); + return retval; } + + /* --------------------------------------------------------- */ typedef struct { @@ -2302,7 +2254,7 @@ typedef struct dbi_result result; guint num_rows; guint cur_row; - GncSqlRow* row; + GncDbiSqlRow* row; } GncDbiSqlResult; static void @@ -2310,10 +2262,7 @@ result_dispose (GncSqlResult* result) { GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result; - if (dbi_result->row != NULL) - { - gnc_sql_row_dispose (dbi_result->row); - } + delete dbi_result->row; if (dbi_result->result != NULL) { gint status; @@ -2341,11 +2290,6 @@ result_get_first_row (GncSqlResult* result) { GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result; - if (dbi_result->row != NULL) - { - gnc_sql_row_dispose (dbi_result->row); - dbi_result->row = NULL; - } if (dbi_result->num_rows > 0) { gint status = dbi_result_first_row (dbi_result->result); @@ -2355,13 +2299,10 @@ result_get_first_row (GncSqlResult* result) qof_backend_set_error (dbi_result->dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); } dbi_result->cur_row = 1; - dbi_result->row = create_dbi_row (dbi_result->result); return dbi_result->row; } else - { - return NULL; - } + return nullptr; } static GncSqlRow* @@ -2369,11 +2310,6 @@ result_get_next_row (GncSqlResult* result) { GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result; - if (dbi_result->row != NULL) - { - gnc_sql_row_dispose (dbi_result->row); - dbi_result->row = NULL; - } if (dbi_result->cur_row < dbi_result->num_rows) { gint status = dbi_result_next_row (dbi_result->result); @@ -2383,13 +2319,10 @@ result_get_next_row (GncSqlResult* result) qof_backend_set_error (dbi_result->dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); } dbi_result->cur_row++; - dbi_result->row = create_dbi_row (dbi_result->result); return dbi_result->row; } else - { - return NULL; - } + return nullptr; } static GncSqlResult* @@ -2407,6 +2340,7 @@ create_dbi_result (GncDbiSqlConnection* dbi_conn, dbi_result result) dbi_result->result = result; dbi_result->num_rows = (guint)dbi_result_get_numrows (result); dbi_result->cur_row = 0; + dbi_result->row = new GncDbiSqlRow{result}; dbi_result->dbi_conn = dbi_conn; return (GncSqlResult*)dbi_result; diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index e2fb2b7bed..7c5633ca07 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -411,11 +411,10 @@ load_account_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val != NULL && G_VALUE_HOLDS_STRING (val) && - g_value_get_string (val) != NULL) + try { - (void)string_to_guid (g_value_get_string (val), &guid); + auto val = row->get_string_at_col (table_row.col_name); + (void)string_to_guid (val.c_str(), &guid); account = xaccAccountLookup (&guid, be->book); if (account != NULL) { @@ -433,9 +432,10 @@ load_account_guid (const GncSqlBackend* be, GncSqlRow* row, } else { - PWARN ("Account ref '%s' not found", g_value_get_string (val)); + PWARN ("Account ref '%s' not found", val.c_str()); } } + catch (std::invalid_argument) {} } static GncSqlColumnTypeHandler account_guid_handler diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index 9c6eb83b67..3ce4a6f329 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -70,48 +70,45 @@ load_address (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; - gchar* buf; - GncAddress* addr; AddressSetterFunc a_setter = (AddressSetterFunc)setter; const gchar* s; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - addr = gncAddressCreate (be->book, QOF_INSTANCE(pObject)); + auto addr = gncAddressCreate (be->book, QOF_INSTANCE(pObject)); + for (auto const& subtable_row : col_table) { - buf = g_strdup_printf ("%s_%s", table_row.col_name, - subtable_row.col_name); - val = gnc_sql_row_get_value_at_col_name (row, buf); - g_free (buf); - if (val == NULL) + auto buf = g_strdup_printf ("%s_%s", table_row.col_name, + subtable_row.col_name); + try { - s = NULL; - } - else - { - s = g_value_get_string (val); - } - if (subtable_row.gobj_param_name != NULL) - { - g_object_set (addr, subtable_row.gobj_param_name, s, NULL); - } - else - { - if (subtable_row.qof_param_name != NULL) + auto val = row->get_string_at_col (buf); + g_free (buf); + if (subtable_row.gobj_param_name != NULL) { - setter = qof_class_get_parameter_setter (GNC_ID_ADDRESS, - subtable_row.qof_param_name); + g_object_set (addr, subtable_row.gobj_param_name, + val.c_str(), NULL); } else { - setter = subtable_row.setter; + if (subtable_row.qof_param_name != NULL) + { + setter = qof_class_get_parameter_setter (GNC_ID_ADDRESS, + subtable_row.qof_param_name); + } + else + { + setter = subtable_row.setter; + } + (*setter) (addr, (const gpointer)val.c_str()); } - (*setter) (addr, (const gpointer)s); + } + catch (std::invalid_argument) + { + return; } } if (table_row.gobj_param_name != NULL) diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 2e43bb386e..2231f8e8f7 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -1180,37 +1180,54 @@ gnc_sql_get_getter (QofIdTypeConst obj_name, return getter; } + +template +void set_object_parameter(gpointer pObject, T item, QofSetterFunc setter, + const char* param) +{ + if (param != NULL) + { + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); + g_object_set (pObject, param, item, NULL); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); + } + else + { + g_return_if_fail (setter != NULL); + (*setter) (pObject, (const gpointer)(item)); + } +} + /* ----------------------------------------------------------------- */ static void load_string (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; - const gchar* s; - - g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - g_return_if_fail (val != NULL); - s = g_value_get_string (val); - if (table_row.gobj_param_name != NULL) + try { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, s, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); + auto s = row->get_string_at_col (table_row.col_name); + if (table_row.gobj_param_name != NULL) + { + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); + g_object_set (pObject, table_row.gobj_param_name, s.c_str(), NULL); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); + } + else + { + g_return_if_fail (setter != NULL); + (*setter) (pObject, (const gpointer)s.c_str()); + } } - else - { - g_return_if_fail (setter != NULL); - (*setter) (pObject, (const gpointer)s); - } + catch (std::invalid_argument) {} } static void @@ -1261,37 +1278,24 @@ load_int (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; - gint int_value; - IntSetterFunc i_setter; - g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val == NULL) - { - int_value = 0; - } - else - { - int_value = (gint)gnc_sql_get_integer_value (val); - } + auto val = row->get_int_at_col(table_row.col_name); if (table_row.gobj_param_name != NULL) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, int_value, NULL); + g_object_set (pObject, table_row.gobj_param_name, val, NULL); if (QOF_IS_INSTANCE (pObject)) qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } else { g_return_if_fail (setter != NULL); - i_setter = (IntSetterFunc)setter; - (*i_setter) (pObject, int_value); + auto _setter = (IntSetterFunc)setter; + (*_setter) (pObject, val); } } @@ -1323,37 +1327,23 @@ load_boolean (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; - gint int_value; - BooleanSetterFunc b_setter; - - g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val == NULL) - { - int_value = 0; - } - else - { - int_value = (gint)gnc_sql_get_integer_value (val); - } + auto val = row->get_int_at_col (table_row.col_name); if (table_row.gobj_param_name != nullptr) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, int_value, nullptr); + g_object_set (pObject, table_row.gobj_param_name, val, nullptr); if (QOF_IS_INSTANCE (pObject)) qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } else { g_return_if_fail (setter != NULL); - b_setter = (BooleanSetterFunc)setter; - (*b_setter) (pObject, (int_value != 0) ? TRUE : FALSE); + auto b_setter = (BooleanSetterFunc)setter; + (*b_setter) (pObject, (val != 0) ? TRUE : FALSE); } } @@ -1385,31 +1375,22 @@ load_int64 (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; - gint64 i64_value = 0; - Int64SetterFunc i64_setter = (Int64SetterFunc)setter; - - g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (table_row.gobj_param_name != nullptr || setter != nullptr); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val != NULL) - { - i64_value = gnc_sql_get_integer_value (val); - } + auto val = row->get_int_at_col (table_row.col_name); if (table_row.gobj_param_name != nullptr) { if (QOF_IS_INSTANCE (pObject)) qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, i64_value, nullptr); + g_object_set (pObject, table_row.gobj_param_name, val, nullptr); if (QOF_IS_INSTANCE (pObject)) qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } else { - (*i64_setter) (pObject, i64_value); + auto i64_setter = reinterpret_cast(setter); + (*i64_setter) (pObject, val); } } @@ -1438,51 +1419,44 @@ load_double (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; - gdouble d_value; - - g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != nullptr || setter != nullptr); - - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val == NULL) + double val; + try { - (*setter) (pObject, (gpointer)NULL); + val = static_cast(row->get_int_at_col(table_row.col_name)); + } + catch (std::invalid_argument) + { + try + { + val = static_cast(row->get_float_at_col(table_row.col_name)); + } + catch (std::invalid_argument) + { + try + { + val = row->get_double_at_col(table_row.col_name); + } + catch (std::invalid_argument) + { + val = 0.0; + } + } + } + + if (table_row.gobj_param_name != NULL) + { + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); + g_object_set (pObject, table_row.gobj_param_name, val, NULL); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } else { - if (G_VALUE_HOLDS (val, G_TYPE_INT)) - { - d_value = (gdouble)g_value_get_int (val); - } - else if (G_VALUE_HOLDS (val, G_TYPE_FLOAT)) - { - d_value = g_value_get_float (val); - } - else if (G_VALUE_HOLDS (val, G_TYPE_DOUBLE)) - { - d_value = g_value_get_double (val); - } - else - { - PWARN ("Unknown float value type: %s\n", g_type_name (G_VALUE_TYPE (val))); - d_value = 0; - } - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, d_value, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - } - else - { - (*setter) (pObject, (gpointer)&d_value); - } + (*setter) (pObject, (gpointer)&val); } } @@ -1511,41 +1485,39 @@ load_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; + GncGUID guid; const GncGUID* pGuid; - g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != nullptr || setter != nullptr); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val == NULL || g_value_get_string (val) == NULL) + std::string str; + try { - pGuid = NULL; + str = row->get_string_at_col(table_row.col_name); + } + catch (std::invalid_argument) + { + return; + } + (void)string_to_guid (str.c_str(), &guid); + if (table_row.gobj_param_name != NULL) + { + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); + g_object_set (pObject, table_row.gobj_param_name, &guid, NULL); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } else { - (void)string_to_guid (g_value_get_string (val), &guid); - pGuid = &guid; - } - if (pGuid != NULL) - { - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, pGuid, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - } - else - { - g_return_if_fail (setter != NULL); - (*setter) (pObject, (const gpointer)pGuid); - } + g_return_if_fail (setter != NULL); + /* FIXME: The setter had damn well better dereference and copy its + * arg! + */ + (*setter) (pObject, (const gpointer)(&guid)); } } @@ -1651,67 +1623,51 @@ load_timespec (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; + Timespec ts = {0, 0}; TimespecSetterFunc ts_setter; gboolean isOK = FALSE; - g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); + g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != nullptr || setter != nullptr); ts_setter = (TimespecSetterFunc)setter; - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val == NULL) + try { - isOK = TRUE; + auto val = row->get_time64_at_col(table_row.col_name); + timespecFromTime64 (&ts, val); + } + catch (std::invalid_argument) + { + try + { + auto val = row->get_string_at_col(table_row.col_name); + auto s = val.c_str(); + auto buf = g_strdup_printf ("%c%c%c%c-%c%c-%c%c %c%c:%c%c:%c%c", + s[0], s[1], s[2], s[3], s[4], s[5], + s[6], s[7], s[8], s[9], s[10], s[11], + s[12], s[13]); + ts = gnc_iso8601_to_timespec_gmt (buf); + g_free (buf); + } + catch (std::invalid_argument) + { + return; + } + } + if (table_row.gobj_param_name != NULL) + { + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); + g_object_set (pObject, table_row.gobj_param_name, &ts, NULL); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); } else { - if (G_VALUE_HOLDS_INT64 (val)) - { - timespecFromTime64 (&ts, (time64) (g_value_get_int64 (val))); - isOK = TRUE; - } - else if (G_VALUE_HOLDS_STRING (val)) - { - const gchar* s = g_value_get_string (val); - if (s != NULL) - { - gchar* buf; - buf = g_strdup_printf ("%c%c%c%c-%c%c-%c%c %c%c:%c%c:%c%c", - s[0], s[1], s[2], s[3], - s[4], s[5], - s[6], s[7], - s[8], s[9], - s[10], s[11], - s[12], s[13]); - ts = gnc_iso8601_to_timespec_gmt (buf); - g_free (buf); - isOK = TRUE; - } - } - else - { - PWARN ("Unknown timespec type: %s", G_VALUE_TYPE_NAME (val)); - } - } - if (isOK) - { - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, &ts, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - } - else - { - (*ts_setter) (pObject, ts); - } + (*ts_setter) (pObject, ts); } } @@ -1779,90 +1735,56 @@ load_date (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; - - g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != nullptr || setter != nullptr); - - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val != NULL) + if (row->is_col_null(table_row.col_name)) + return; + GDate date; + g_date_clear (&date, 1); + try { - if (G_VALUE_HOLDS_INT64 (val)) + /* timespec_to_gdate applies the tz, and gdates are saved + * as ymd, so we don't want that. + */ + auto time = row->get_time64_at_col(table_row.col_name); + auto tm = gnc_gmtime(&time); + g_date_set_dmy(&date, tm->tm_mday, + static_cast(tm->tm_mon + 1), + tm->tm_year + 1900); + free(tm); + } + catch (std::invalid_argument) + { + try { - /* timespec_to_gdate applies the tz, and gdates are saved - * as ymd, so we don't want that. - */ - auto time = g_value_get_int64 (val); - auto tm = gnc_gmtime(&time); + std::string str = row->get_string_at_col(table_row.col_name); + if (str.empty()) return; + auto year = static_cast(stoi (str.substr (0,4))); + auto month = static_cast(stoi (str.substr (4,2))); + auto day = static_cast(stoi (str.substr (6,2))); + + if (year != 0 || month != 0 || day != (GDateDay)0) + g_date_set_dmy(&date, day, month, year); - GDate date; - g_date_clear(&date, 1); - g_date_set_dmy(&date, tm->tm_mday, - static_cast(tm->tm_mon + 1), - tm->tm_year + 1900); - free(tm); - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, &date, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - } - else - { - (*setter) (pObject, &date); - } } - else if (G_VALUE_HOLDS_STRING (val)) + catch (std::invalid_argument) { - // Format of date is YYYYMMDD - const gchar* s = g_value_get_string (val); - GDate* date; - if (s != NULL) - { - gchar buf[5]; - GDateDay day; - GDateMonth month; - GDateYear year; - - strncpy (buf, &s[0], 4); - buf[4] = '\0'; - year = (GDateYear)atoi (buf); - strncpy (buf, &s[4], 2); - buf[2] = '\0'; - month = static_cast (atoi (buf)); - strncpy (buf, &s[6], 2); - day = (GDateDay)atoi (buf); - - if (year != 0 || month != 0 || day != (GDateDay)0) - { - date = g_date_new_dmy (day, month, year); - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, - date, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - } - else - { - (*setter) (pObject, date); - } - g_date_free (date); - } - } - } - else - { - PWARN ("Unknown date type: %s", G_VALUE_TYPE_NAME (val)); + return; } } + if (table_row.gobj_param_name != NULL) + { + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); + g_object_set (pObject, table_row.gobj_param_name, &date, NULL); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); + } + else + { + (*setter) (pObject, &date); + } } static void @@ -1918,58 +1840,37 @@ load_numeric (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; - gchar* buf; - gint64 num, denom; - gnc_numeric n; - gboolean isNull = FALSE; - g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); + g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != nullptr || setter != nullptr); - - buf = g_strdup_printf ("%s_num", table_row.col_name); - val = gnc_sql_row_get_value_at_col_name (row, buf); - g_free (buf); - if (val == NULL) + gnc_numeric n; + try { - isNull = TRUE; - num = 0; + auto buf = g_strdup_printf ("%s_num", table_row.col_name); + auto num = row->get_int_at_col (buf); + g_free (buf); + buf = g_strdup_printf ("%s_denom", table_row.col_name); + auto denom = row->get_int_at_col (buf); + n = gnc_numeric_create (num, denom); + } + catch (std::invalid_argument) + { + return; + } + if (table_row.gobj_param_name != nullptr) + { + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); + g_object_set (pObject, table_row.gobj_param_name, &n, NULL); + if (QOF_IS_INSTANCE (pObject)) + qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); } else { - num = gnc_sql_get_integer_value (val); - } - buf = g_strdup_printf ("%s_denom", table_row.col_name); - val = gnc_sql_row_get_value_at_col_name (row, buf); - g_free (buf); - if (val == NULL) - { - isNull = TRUE; - denom = 1; - } - else - { - denom = gnc_sql_get_integer_value (val); - } - n = gnc_numeric_create (num, denom); - if (!isNull) - { - if (table_row.gobj_param_name != nullptr) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, &n, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - } - else - { - NumericSetterFunc n_setter = (NumericSetterFunc)setter; - (*n_setter) (pObject, n); - } + NumericSetterFunc n_setter = (NumericSetterFunc)setter; + (*n_setter) (pObject, n); } } @@ -2158,7 +2059,6 @@ gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow* row, GncSqlColumnTypeHandler* pHandler; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); for (auto const& table_row : table) @@ -2778,24 +2678,20 @@ gnc_sql_init_version_info (GncSqlBackend* be) sql = g_strdup_printf ("SELECT * FROM %s", VERSION_TABLE_NAME); result = gnc_sql_execute_select_sql (be, sql); g_free (sql); - if (result != NULL) + if (result != nullptr) { - const GValue* name; - const GValue* version; - GncSqlRow* row; - - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + for (auto row = gnc_sql_result_get_first_row (result); + row != nullptr ; + row = gnc_sql_result_get_next_row (result)) { - name = gnc_sql_row_get_value_at_col_name (row, TABLE_COL_NAME); - version = gnc_sql_row_get_value_at_col_name (row, VERSION_COL_NAME); + auto name = row->get_string_at_col (TABLE_COL_NAME); + auto version = row->get_int_at_col (VERSION_COL_NAME); g_hash_table_insert (be->versions, - g_strdup (g_value_get_string (name)), - GINT_TO_POINTER ((gint)g_value_get_int64 (version))); - row = gnc_sql_result_get_next_row (result); + g_strdup (name.c_str()), + GINT_TO_POINTER (version)); } - gnc_sql_result_dispose (result); } + gnc_sql_result_dispose (result); } else { @@ -2911,7 +2807,8 @@ gnc_sql_set_table_version (GncSqlBackend* be, const gchar* table_name, #ifdef __LP64__ template <> int get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry& table_row, std::false_type) + const GncSqlColumnTableEntry& table_row, + std::false_type) { g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, 0); int result = 0; diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 7ccd032adc..e18ed0b96b 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -140,7 +140,6 @@ void gnc_sql_commit_edit (GncSqlBackend* qbe, QofInstance* inst); */ typedef struct GncSqlStatement GncSqlStatement; typedef struct GncSqlResult GncSqlResult; -typedef struct GncSqlRow GncSqlRow; /** *@struct GncSqlStatement @@ -208,20 +207,21 @@ struct GncSqlConnection (CONN)->quoteString(CONN,STR) /** - * @struct GncSqlRow - * * Struct used to represent a row in the result of an SQL SELECT statement. * SQL backends must provide a structure which implements all of the functions. */ -struct GncSqlRow + +class GncSqlRow { - const GValue* (*getValueAtColName) (GncSqlRow*, const gchar*); - void (*dispose) (GncSqlRow*); +public: + virtual ~GncSqlRow() = default; + virtual int64_t get_int_at_col (const char* col) = 0; + virtual float get_float_at_col (const char* col) = 0; + virtual double get_double_at_col (const char* col) = 0; + virtual std::string get_string_at_col (const char* col) = 0; + virtual time64 get_time64_at_col (const char* col) = 0; + virtual bool is_col_null (const char* col) const noexcept = 0; }; -#define gnc_sql_row_get_value_at_col_name(ROW,N) \ - (ROW)->getValueAtColName(ROW,N) -#define gnc_sql_row_dispose(ROW) \ - (ROW)->dispose(ROW) /** * @struct GncSqlResult diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index abfc0ab24c..6d5dbba707 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -353,7 +353,6 @@ load_billterm_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; GncGUID guid; GncBillTerm* term = NULL; @@ -361,11 +360,10 @@ load_billterm_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val != NULL && G_VALUE_HOLDS_STRING (val) && - g_value_get_string (val) != NULL) + try { - string_to_guid (g_value_get_string (val), &guid); + auto val = row->get_string_at_col (table_row.col_name); + string_to_guid (val.c_str(), &guid); term = gncBillTermLookup (be->book, &guid); if (term != NULL) { @@ -382,9 +380,10 @@ load_billterm_guid (const GncSqlBackend* be, GncSqlRow* row, } else { - PWARN ("Billterm ref '%s' not found", g_value_get_string (val)); + PWARN ("Billterm ref '%s' not found", val.c_str()); } } + catch (std::invalid_argument) {} } static GncSqlColumnTypeHandler billterm_guid_handler diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index 88df5e65bf..aedc2f70dd 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -492,11 +492,10 @@ load_budget_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val != NULL && G_VALUE_HOLDS_STRING (val) && - g_value_get_string (val) != NULL) + try { - (void)string_to_guid (g_value_get_string (val), &guid); + auto val = row->get_string_at_col (table_row.col_name); + (void)string_to_guid (val.c_str(), &guid); budget = gnc_budget_lookup (&guid, be->book); if (budget != NULL) { @@ -514,9 +513,10 @@ load_budget_guid (const GncSqlBackend* be, GncSqlRow* row, } else { - PWARN ("Budget ref '%s' not found", g_value_get_string (val)); + PWARN ("Budget ref '%s' not found", val.c_str()); } } + catch (std::invalid_argument) {} } static GncSqlColumnTypeHandler budget_guid_handler diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index 5a1e815862..b31be69d12 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -277,7 +277,6 @@ load_commodity_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; GncGUID guid; gnc_commodity* commodity = NULL; @@ -285,11 +284,10 @@ load_commodity_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val != NULL && G_VALUE_HOLDS_STRING (val) && - g_value_get_string (val) != NULL) + try { - (void)string_to_guid (g_value_get_string (val), &guid); + auto val = row->get_string_at_col (table_row.col_name); + (void)string_to_guid (val.c_str(), &guid); commodity = gnc_commodity_find_commodity_by_guid (&guid, be->book); if (commodity != NULL) { @@ -306,9 +304,10 @@ load_commodity_guid (const GncSqlBackend* be, GncSqlRow* row, } else { - PWARN ("Commodity ref '%s' not found", g_value_get_string (val)); + PWARN ("Commodity ref '%s' not found", val.c_str()); } } + catch (std::invalid_argument) {} } static GncSqlColumnTypeHandler commodity_guid_handler diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index 236b4a5abd..74db65b11e 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -288,7 +288,6 @@ load_invoice_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; GncGUID guid; GncInvoice* invoice = NULL; @@ -296,11 +295,10 @@ load_invoice_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val != NULL && G_VALUE_HOLDS_STRING (val) && - g_value_get_string (val) != NULL) + try { - string_to_guid (g_value_get_string (val), &guid); + auto val = row->get_string_at_col (table_row.col_name); + string_to_guid (val.c_str(), &guid); invoice = gncInvoiceLookup (be->book, &guid); if (invoice != NULL) { @@ -317,9 +315,10 @@ load_invoice_guid (const GncSqlBackend* be, GncSqlRow* row, } else { - PWARN ("Invoice ref '%s' not found", g_value_get_string (val)); + PWARN ("Invoice ref '%s' not found", val.c_str()); } } + catch (std::invalid_argument) {} } static GncSqlColumnTypeHandler invoice_guid_handler diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index 15aff46607..a8ba9f7892 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -218,7 +218,6 @@ load_lot_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; GncGUID guid; GNCLot* lot; @@ -226,11 +225,10 @@ load_lot_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val != NULL && G_VALUE_HOLDS_STRING (val) && - g_value_get_string (val) != NULL) + try { - (void)string_to_guid (g_value_get_string (val), &guid); + auto val = row->get_string_at_col (table_row.col_name); + (void)string_to_guid (val.c_str(), &guid); lot = gnc_lot_lookup (&guid, be->book); if (lot != NULL) { @@ -248,9 +246,10 @@ load_lot_guid (const GncSqlBackend* be, GncSqlRow* row, } else { - PWARN ("Lot ref '%s' not found", g_value_get_string (val)); + PWARN ("Lot ref '%s' not found", val.c_str()); } } + catch (std::invalid_argument) {} } static GncSqlColumnTypeHandler lot_guid_handler diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index 525d312dab..2ac48a22ef 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -203,7 +203,6 @@ load_order_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; GncGUID guid; GncOrder* order = NULL; @@ -211,11 +210,10 @@ load_order_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val != NULL && G_VALUE_HOLDS_STRING (val) && - g_value_get_string (val) != NULL) + try { - string_to_guid (g_value_get_string (val), &guid); + auto val = row->get_string_at_col (table_row.col_name); + string_to_guid (val.c_str(), &guid); order = gncOrderLookup (be->book, &guid); if (order != NULL) { @@ -232,9 +230,10 @@ load_order_guid (const GncSqlBackend* be, GncSqlRow* row, } else { - PWARN ("Order ref '%s' not found", g_value_get_string (val)); + PWARN ("Order ref '%s' not found", val.c_str()); } } + catch (std::invalid_argument) {} } static GncSqlColumnTypeHandler order_guid_handler diff --git a/src/backend/sql/gnc-owner-sql.cpp b/src/backend/sql/gnc-owner-sql.cpp index d25d939669..21efa59f05 100644 --- a/src/backend/sql/gnc-owner-sql.cpp +++ b/src/backend/sql/gnc-owner-sql.cpp @@ -53,11 +53,8 @@ load_owner (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; - gchar* buf; GncOwnerType type; GncGUID guid; - QofBook* book; GncOwner owner; GncGUID* pGuid = NULL; @@ -65,21 +62,22 @@ load_owner (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - book = be->book; - buf = g_strdup_printf ("%s_type", table_row.col_name); - val = gnc_sql_row_get_value_at_col_name (row, buf); - type = (GncOwnerType)gnc_sql_get_integer_value (val); - g_free (buf); - buf = g_strdup_printf ("%s_guid", table_row.col_name); - val = gnc_sql_row_get_value_at_col_name (row, buf); - g_free (buf); - - if (val != NULL && G_VALUE_HOLDS_STRING (val) && - g_value_get_string (val) != NULL) + auto book = be->book; + auto buf = g_strdup_printf ("%s_type", table_row.col_name); + try { - string_to_guid (g_value_get_string (val), &guid); + type = static_cast(row->get_int_at_col (buf)); + g_free (buf); + buf = g_strdup_printf ("%s_guid", table_row.col_name); + auto val = row->get_string_at_col (buf); + g_free (buf); + string_to_guid (val.c_str(), &guid); pGuid = &guid; } + catch (std::invalid_argument) + { + return; + } switch (type) { diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index 25730ef78e..68419d89ed 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -748,17 +748,20 @@ gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid) while (row != NULL) { - const GncSqlColumnTableEntry& table_row = - col_table[guid_val_col]; - GncGUID child_guid; - const GValue* val = - gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val == NULL) + try + { + const GncSqlColumnTableEntry& table_row = + col_table[guid_val_col]; + GncGUID child_guid; + auto val = row->get_string_at_col (table_row.col_name); + (void)string_to_guid (val.c_str(), &child_guid); + gnc_sql_slots_delete (be, &child_guid); + row = gnc_sql_result_get_next_row (result); + } + catch (std::invalid_argument) + { continue; - - (void)string_to_guid (g_value_get_string (val), &child_guid); - gnc_sql_slots_delete (be, &child_guid); - row = gnc_sql_result_get_next_row (result); + } } gnc_sql_result_dispose (result); } diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index b1dc6c687a..90c439dc3d 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -509,7 +509,6 @@ load_taxtable_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; GncGUID guid; GncTaxTable* taxtable = NULL; @@ -517,11 +516,10 @@ load_taxtable_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - if (val != NULL && G_VALUE_HOLDS_STRING (val) && - g_value_get_string (val) != NULL) + try { - string_to_guid (g_value_get_string (val), &guid); + auto val = row->get_string_at_col (table_row.col_name); + string_to_guid (val.c_str(), &guid); taxtable = gncTaxTableLookup (be->book, &guid); if (taxtable != NULL) { @@ -538,9 +536,10 @@ load_taxtable_guid (const GncSqlBackend* be, GncSqlRow* row, } else { - PWARN ("Taxtable ref '%s' not found", g_value_get_string (val)); + PWARN ("Taxtable ref '%s' not found", val.c_str()); } } + catch (std::invalid_argument) {} } static GncSqlColumnTypeHandler taxtable_guid_handler diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index a65963a7f5..3f5c360c63 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -1440,7 +1440,6 @@ load_tx_guid (const GncSqlBackend* be, GncSqlRow* row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - const GValue* val; GncGUID guid; Transaction* tx; const gchar* guid_str; @@ -1449,12 +1448,10 @@ load_tx_guid (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); - val = gnc_sql_row_get_value_at_col_name (row, table_row.col_name); - g_assert (val != NULL); - guid_str = g_value_get_string (val); - if (guid_str != NULL) + try { - (void)string_to_guid (guid_str, &guid); + auto val = row->get_string_at_col (table_row.col_name); + (void)string_to_guid (val.c_str(), &guid); tx = xaccTransLookup (&guid, be->book); // If the transaction is not found, try loading it @@ -1464,7 +1461,7 @@ load_tx_guid (const GncSqlBackend* be, GncSqlRow* row, GncSqlStatement* stmt; buf = g_strdup_printf ("SELECT * FROM %s WHERE guid='%s'", - TRANSACTION_TABLE, guid_str); + TRANSACTION_TABLE, val.c_str()); stmt = gnc_sql_create_statement_from_sql ((GncSqlBackend*)be, buf); g_free (buf); query_transactions ((GncSqlBackend*)be, stmt); @@ -1486,6 +1483,7 @@ load_tx_guid (const GncSqlBackend* be, GncSqlRow* row, } } } + catch (std::invalid_argument) {} } static GncSqlColumnTypeHandler tx_guid_handler From 576bc8ae7d682a3101ab98b41b4e1f9c0d271e07 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 7 Aug 2016 13:10:47 -0700 Subject: [PATCH 10/63] Don't override an already-set QofBackend error. --- src/backend/sql/gnc-backend-sql.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 2231f8e8f7..474f48ff11 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -2130,7 +2130,8 @@ gnc_sql_execute_select_statement (GncSqlBackend* be, GncSqlStatement* stmt) if (result == NULL) { PERR ("SQL error: %s\n", gnc_sql_statement_to_sql (stmt)); - qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); + if (!qof_backend_check_error(&be->be)) + qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); } return result; @@ -2148,7 +2149,8 @@ gnc_sql_create_statement_from_sql (GncSqlBackend* be, const gchar* sql) if (stmt == NULL) { PERR ("SQL error: %s\n", sql); - qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); + if (!qof_backend_check_error(&be->be)) + qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); } return stmt; @@ -2173,7 +2175,8 @@ gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) if (result == NULL) { PERR ("SQL error: %s\n", sql); - qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); + if (!qof_backend_check_error(&be->be)) + qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); } return result; @@ -2324,7 +2327,8 @@ gnc_sql_do_db_operation (GncSqlBackend* be, if (result == -1) { PERR ("SQL error: %s\n", gnc_sql_statement_to_sql (stmt)); - qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); + if (!qof_backend_check_error(&be->be)) + qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); } else { @@ -2788,7 +2792,8 @@ gnc_sql_set_table_version (GncSqlBackend* be, const gchar* table_name, if (status == -1) { PERR ("SQL error: %s\n", sql); - qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); + if (!qof_backend_check_error(&be->be)) + qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); } g_free (sql); } From a0ae59a96a27b22d80f3da8bdfec7b555f23f2d1 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 9 Apr 2016 15:31:36 -0700 Subject: [PATCH 11/63] Reimplement row retrieval as an iterator on GncSqlResults. Replaces a much-copied and longish while loop with a simple range-for loop that's guaranteed not to iterate if the result-set is empty. --- src/backend/dbi/gnc-backend-dbi-priv.h | 51 ++- src/backend/dbi/gnc-backend-dbi.cpp | 176 +++----- src/backend/sql/gnc-account-sql.cpp | 153 ++++--- src/backend/sql/gnc-address-sql.cpp | 4 +- src/backend/sql/gnc-backend-sql.cpp | 147 +++---- src/backend/sql/gnc-backend-sql.h | 111 +++-- src/backend/sql/gnc-bill-term-sql.cpp | 88 ++-- src/backend/sql/gnc-book-sql.cpp | 39 +- src/backend/sql/gnc-budget-sql.cpp | 54 +-- src/backend/sql/gnc-commodity-sql.cpp | 40 +- src/backend/sql/gnc-customer-sql.cpp | 35 +- src/backend/sql/gnc-employee-sql.cpp | 39 +- src/backend/sql/gnc-entry-sql.cpp | 35 +- src/backend/sql/gnc-invoice-sql.cpp | 40 +- src/backend/sql/gnc-job-sql.cpp | 36 +- src/backend/sql/gnc-lots-sql.cpp | 35 +- src/backend/sql/gnc-order-sql.cpp | 41 +- src/backend/sql/gnc-owner-sql.cpp | 7 +- src/backend/sql/gnc-price-sql.cpp | 43 +- src/backend/sql/gnc-recurrence-sql.cpp | 59 +-- src/backend/sql/gnc-schedxaction-sql.cpp | 43 +- src/backend/sql/gnc-slots-sql.cpp | 94 ++--- src/backend/sql/gnc-tax-table-sql.cpp | 80 ++-- src/backend/sql/gnc-transaction-sql.cpp | 384 ++++++++---------- src/backend/sql/gnc-vendor-sql.cpp | 37 +- .../sql/test/utest-gnc-backend-sql.cpp | 24 +- 26 files changed, 817 insertions(+), 1078 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi-priv.h b/src/backend/dbi/gnc-backend-dbi-priv.h index 0e0d3b6762..0743771217 100644 --- a/src/backend/dbi/gnc-backend-dbi-priv.h +++ b/src/backend/dbi/gnc-backend-dbi-priv.h @@ -119,22 +119,47 @@ typedef struct /* external access required for tests */ std::string adjust_sql_options_string(const std::string&); -class GncDbiSqlRow : public GncSqlRow + +class GncDbiSqlResult : public GncSqlResult { public: - GncDbiSqlRow (dbi_result result) : m_result{result} {} - ~GncDbiSqlRow() = default; - int64_t get_int_at_col(const char*); - float get_float_at_col(const char*); - double get_double_at_col(const char*); - std::string get_string_at_col(const char*); - time64 get_time64_at_col(const char*); - bool is_col_null(const char* col) const noexcept - { - return dbi_result_field_is_null(m_result, col); - } + GncDbiSqlResult(GncDbiSqlConnection* conn, dbi_result result) : + m_conn{conn}, m_dbi_result{result}, m_iter{this}, m_row{&m_iter}, + m_sentinel{nullptr} {} + ~GncDbiSqlResult(); + int dberror(); + uint64_t size() const noexcept; + GncSqlRow& begin(); + GncSqlRow& end() { return m_sentinel; } +protected: + class IteratorImpl : public GncSqlResult::IteratorImpl + { + public: + ~IteratorImpl() = default; + IteratorImpl(GncDbiSqlResult* inst) : m_inst{inst} {} + virtual GncSqlRow& operator++(); + virtual GncSqlRow& operator++(int) { return ++(*this); }; + virtual GncSqlResult* operator*() { return m_inst; } + virtual int64_t get_int_at_col (const char* col) const; + virtual float get_float_at_col (const char* col) const; + virtual double get_double_at_col (const char* col) const; + virtual std::string get_string_at_col (const char* col)const; + virtual time64 get_time64_at_col (const char* col) const; + virtual bool is_col_null(const char* col) const noexcept + { + return dbi_result_field_is_null(m_inst->m_dbi_result, col); + } + private: + GncDbiSqlResult* m_inst; + }; private: - dbi_result m_result; + GncDbiSqlConnection* m_conn; + dbi_result m_dbi_result; + IteratorImpl m_iter; + GncSqlRow m_row; + GncSqlRow m_sentinel; + }; + #endif //GNC_BACKEND_DBI_PRIV_H diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index db0c1ec04b..b6a3aaafd4 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -2156,53 +2156,66 @@ gnc_module_finalize_backend_dbi (void) } /* --------------------------------------------------------- */ +GncSqlRow& +GncDbiSqlResult::IteratorImpl::operator++() +{ + int status = dbi_result_next_row (m_inst->m_dbi_result); + if (status) + return m_inst->m_row; + int error = m_inst->dberror(); + if (error == DBI_ERROR_BADIDX || error == 0) //ran off the end of the results + return m_inst->m_sentinel; + PERR("Error %d incrementing results iterator.", error); + qof_backend_set_error (m_inst->m_conn->qbe, ERR_BACKEND_SERVER_ERR); + return m_inst->m_sentinel; +} int64_t -GncDbiSqlRow::get_int_at_col(const char* col) +GncDbiSqlResult::IteratorImpl::get_int_at_col(const char* col) const { - auto type = dbi_result_get_field_type (m_result, col); + auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); if(type != DBI_TYPE_INTEGER) throw (std::invalid_argument{"Requested integer from non-integer column."}); - return dbi_result_get_longlong (m_result, col); + return dbi_result_get_longlong (m_inst->m_dbi_result, col); } float -GncDbiSqlRow::get_float_at_col(const char* col) +GncDbiSqlResult::IteratorImpl::get_float_at_col(const char* col) const { - auto type = dbi_result_get_field_type (m_result, col); - auto attrs = dbi_result_get_field_attribs (m_result, col); + auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); + auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); if(type != DBI_TYPE_DECIMAL || (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE4) throw (std::invalid_argument{"Requested float from non-float column."}); gnc_push_locale (LC_NUMERIC, "C"); - auto retval = dbi_result_get_float(m_result, col); + auto retval = dbi_result_get_float(m_inst->m_dbi_result, col); gnc_pop_locale (LC_NUMERIC); return retval; } double -GncDbiSqlRow::get_double_at_col(const char* col) +GncDbiSqlResult::IteratorImpl::get_double_at_col(const char* col) const { - auto type = dbi_result_get_field_type (m_result, col); - auto attrs = dbi_result_get_field_attribs (m_result, col); + auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); + auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); if(type != DBI_TYPE_DECIMAL || (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE8) throw (std::invalid_argument{"Requested double from non-double column."}); gnc_push_locale (LC_NUMERIC, "C"); - auto retval = dbi_result_get_double(m_result, col); + auto retval = dbi_result_get_double(m_inst->m_dbi_result, col); gnc_pop_locale (LC_NUMERIC); return retval; } std::string -GncDbiSqlRow::get_string_at_col(const char* col) +GncDbiSqlResult::IteratorImpl::get_string_at_col(const char* col) const { - auto type = dbi_result_get_field_type (m_result, col); - auto attrs = dbi_result_get_field_attribs (m_result, col); + auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); + auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); if(type != DBI_TYPE_STRING) throw (std::invalid_argument{"Requested string from non-string column."}); gnc_push_locale (LC_NUMERIC, "C"); - auto strval = dbi_result_get_string(m_result, col); + auto strval = dbi_result_get_string(m_inst->m_dbi_result, col); if (strval == nullptr) { gnc_pop_locale (LC_NUMERIC); @@ -2213,10 +2226,10 @@ GncDbiSqlRow::get_string_at_col(const char* col) return retval; } time64 -GncDbiSqlRow::get_time64_at_col (const char* col) +GncDbiSqlResult::IteratorImpl::get_time64_at_col (const char* col) const { - auto type = dbi_result_get_field_type (m_result, col); - auto attrs = dbi_result_get_field_attribs (m_result, col); + auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); + auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); if (type != DBI_TYPE_DATETIME) throw (std::invalid_argument{"Requested double from non-double column."}); gnc_push_locale (LC_NUMERIC, "C"); @@ -2233,7 +2246,7 @@ GncDbiSqlRow::get_time64_at_col (const char* col) * dbi_result_get_as_longlong. * Note: 0.9 is available in Debian Jessie and Fedora 21. */ - auto result = (dbi_result_t*) (m_result); + auto result = (dbi_result_t*) (m_inst->m_dbi_result); auto row = dbi_result_get_currow (result); auto idx = dbi_result_get_field_idx (result, col) - 1; time64 retval = result->rows[row]->field_values[idx].d_datetime; @@ -2246,105 +2259,50 @@ GncDbiSqlRow::get_time64_at_col (const char* col) /* --------------------------------------------------------- */ -typedef struct + +GncDbiSqlResult::~GncDbiSqlResult() { - GncSqlResult base; + int status = dbi_result_free (m_dbi_result); + + if (status == 0) + return; - GncDbiSqlConnection* dbi_conn; - dbi_result result; - guint num_rows; - guint cur_row; - GncDbiSqlRow* row; -} GncDbiSqlResult; + PERR ("Error %d in dbi_result_free() result.", dberror() ); + qof_backend_set_error (m_conn->qbe, ERR_BACKEND_SERVER_ERR); +} -static void -result_dispose (GncSqlResult* result) +GncSqlRow& +GncDbiSqlResult::begin() { - GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result; - delete dbi_result->row; - if (dbi_result->result != NULL) + if (m_dbi_result == nullptr || + dbi_result_get_numrows(m_dbi_result) == 0) + return m_sentinel; + int status = dbi_result_first_row(m_dbi_result); + if (status) + return m_row; + int error = dberror(); // + + if (error != DBI_ERROR_BADIDX) //otherwise just an empty result set { - gint status; - - status = dbi_result_free (dbi_result->result); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (dbi_result->dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); - } + PERR ("Error %d in dbi_result_first_row()", dberror()); + qof_backend_set_error (m_conn->qbe, ERR_BACKEND_SERVER_ERR); } - g_free (result); + return m_sentinel; } -static guint -result_get_num_rows (GncSqlResult* result) +int +GncDbiSqlResult::dberror() { - GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result; - - return dbi_result->num_rows; + return dbi_conn_error(m_conn->conn, nullptr); } -static GncSqlRow* -result_get_first_row (GncSqlResult* result) +uint64_t +GncDbiSqlResult::size() const noexcept { - GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result; - - if (dbi_result->num_rows > 0) - { - gint status = dbi_result_first_row (dbi_result->result); - if (status == 0) - { - PERR ("Error in dbi_result_first_row()\n"); - qof_backend_set_error (dbi_result->dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); - } - dbi_result->cur_row = 1; - return dbi_result->row; - } - else - return nullptr; + return dbi_result_get_numrows(m_dbi_result); } -static GncSqlRow* -result_get_next_row (GncSqlResult* result) -{ - GncDbiSqlResult* dbi_result = (GncDbiSqlResult*)result; - - if (dbi_result->cur_row < dbi_result->num_rows) - { - gint status = dbi_result_next_row (dbi_result->result); - if (status == 0) - { - PERR ("Error in dbi_result_first_row()\n"); - qof_backend_set_error (dbi_result->dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); - } - dbi_result->cur_row++; - return dbi_result->row; - } - else - return nullptr; -} - -static GncSqlResult* -create_dbi_result (GncDbiSqlConnection* dbi_conn, dbi_result result) -{ - GncDbiSqlResult* dbi_result; - - dbi_result = g_new0 (GncDbiSqlResult, 1); - g_assert (dbi_result != NULL); - - dbi_result->base.dispose = result_dispose; - dbi_result->base.getNumRows = result_get_num_rows; - dbi_result->base.getFirstRow = result_get_first_row; - dbi_result->base.getNextRow = result_get_next_row; - dbi_result->result = result; - dbi_result->num_rows = (guint)dbi_result_get_numrows (result); - dbi_result->cur_row = 0; - dbi_result->row = new GncDbiSqlRow{result}; - dbi_result->dbi_conn = dbi_conn; - - return (GncSqlResult*)dbi_result; -} /* --------------------------------------------------------- */ typedef struct { @@ -2417,7 +2375,7 @@ conn_dispose (GncSqlConnection* conn) g_free (conn); } -static GncSqlResult* +static GncSqlResultPtr conn_execute_select_statement (GncSqlConnection* conn, GncSqlStatement* stmt) { GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; @@ -2432,13 +2390,10 @@ conn_execute_select_statement (GncSqlConnection* conn, GncSqlStatement* stmt) result = dbi_conn_query (dbi_conn->conn, dbi_stmt->sql->str); } while (dbi_conn->retry); - if (result == NULL) - { + if (result == nullptr) PERR ("Error executing SQL %s\n", dbi_stmt->sql->str); - return NULL; - } gnc_pop_locale (LC_NUMERIC); - return create_dbi_result (dbi_conn, result); + return GncSqlResultPtr(new GncDbiSqlResult (dbi_conn, result)); } static gint @@ -2562,7 +2517,8 @@ conn_rollback_transaction (GncSqlConnection* conn) gboolean success = FALSE; DEBUG ("ROLLBACK\n"); - result = dbi_conn_queryf (dbi_conn->conn, "ROLLBACK"); + const char* command = "ROLLBACK"; + result = dbi_conn_query (dbi_conn->conn, command); success = (result != NULL); status = dbi_result_free (result); diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index 7c5633ca07..e12cb11ff6 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -152,14 +152,13 @@ set_parent_guid (gpointer pObject, gpointer pValue) } static Account* -load_single_account (GncSqlBackend* be, GncSqlRow* row, +load_single_account (GncSqlBackend* be, GncSqlRow& row, GList** l_accounts_needing_parents) { const GncGUID* guid; Account* pAccount = NULL; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); g_return_val_if_fail (l_accounts_needing_parents != NULL, NULL); guid = gnc_sql_load_guid (be, row); @@ -196,7 +195,6 @@ static void load_all_accounts (GncSqlBackend* be) { GncSqlStatement* stmt = NULL; - GncSqlResult* result; QofBook* pBook; GList* l_accounts_needing_parents = NULL; GSList* bal_slist; @@ -214,99 +212,89 @@ load_all_accounts (GncSqlBackend* be) LEAVE ("stmt == NULL"); return; } - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + for (auto row : *result) + load_single_account (be, row, &l_accounts_needing_parents); + + auto sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", TABLE_NAME); + gnc_sql_slots_load_for_sql_subquery (be, sql, (BookLookupFn)xaccAccountLookup); + g_free (sql); + + /* While there are items on the list of accounts needing parents, + try to see if the parent has now been loaded. Theory says that if + items are removed from the front and added to the back if the + parent is still not available, then eventually, the list will + shrink to size 0. */ + if (l_accounts_needing_parents != NULL) { - GncSqlRow* row = gnc_sql_result_get_first_row (result); - gchar* sql; + gboolean progress_made = TRUE; + Account* root; + Account* pParent; + GList* elem; - while (row != NULL) + while (progress_made) { - load_single_account (be, row, &l_accounts_needing_parents); - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - - sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", TABLE_NAME); - gnc_sql_slots_load_for_sql_subquery (be, sql, (BookLookupFn)xaccAccountLookup); - g_free (sql); - - /* While there are items on the list of accounts needing parents, - try to see if the parent has now been loaded. Theory says that if - items are removed from the front and added to the back if the - parent is still not available, then eventually, the list will - shrink to size 0. */ - if (l_accounts_needing_parents != NULL) - { - gboolean progress_made = TRUE; - Account* root; - Account* pParent; - GList* elem; - - while (progress_made) + progress_made = FALSE; + for (elem = l_accounts_needing_parents; elem != NULL;) { - progress_made = FALSE; - for (elem = l_accounts_needing_parents; elem != NULL;) + account_parent_guid_struct* s = (account_parent_guid_struct*)elem->data; + pParent = xaccAccountLookup (&s->guid, be->book); + if (pParent != NULL) { - account_parent_guid_struct* s = (account_parent_guid_struct*)elem->data; - pParent = xaccAccountLookup (&s->guid, be->book); - if (pParent != NULL) - { - GList* next_elem; + GList* next_elem; - gnc_account_append_child (pParent, s->pAccount); - next_elem = g_list_next (elem); - l_accounts_needing_parents = g_list_delete_link (l_accounts_needing_parents, - elem); - g_free (s); - elem = next_elem; - progress_made = TRUE; - } - else - { - /* Can't be up in the for loop because the 'then' clause reads inside a node freed - by g_list_delete_link(). */ - elem = g_list_next (elem); - } + gnc_account_append_child (pParent, s->pAccount); + next_elem = g_list_next (elem); + l_accounts_needing_parents = g_list_delete_link (l_accounts_needing_parents, + elem); + g_free (s); + elem = next_elem; + progress_made = TRUE; + } + else + { + /* Can't be up in the for loop because the 'then' clause reads inside a node freed + by g_list_delete_link(). */ + elem = g_list_next (elem); } } + } - /* Any non-ROOT accounts left over must be parented by the root account */ - root = gnc_book_get_root_account (pBook); - while (l_accounts_needing_parents != NULL) + /* Any non-ROOT accounts left over must be parented by the root account */ + root = gnc_book_get_root_account (pBook); + while (l_accounts_needing_parents != NULL) + { + account_parent_guid_struct* s = (account_parent_guid_struct*) + l_accounts_needing_parents->data; + if (xaccAccountGetType (s->pAccount) != ACCT_TYPE_ROOT) { - account_parent_guid_struct* s = (account_parent_guid_struct*) - l_accounts_needing_parents->data; - if (xaccAccountGetType (s->pAccount) != ACCT_TYPE_ROOT) - { - gnc_account_append_child (root, s->pAccount); - } - g_free (s); - l_accounts_needing_parents = g_list_delete_link (l_accounts_needing_parents, - l_accounts_needing_parents); + gnc_account_append_child (root, s->pAccount); } + g_free (s); + l_accounts_needing_parents = g_list_delete_link (l_accounts_needing_parents, + l_accounts_needing_parents); } + } - /* Load starting balances */ - bal_slist = gnc_sql_get_account_balances_slist (be); - for (bal = bal_slist; bal != NULL; bal = bal->next) - { - acct_balances_t* balances = (acct_balances_t*)bal->data; + /* Load starting balances */ + bal_slist = gnc_sql_get_account_balances_slist (be); + for (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_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); - } + qof_instance_decrease_editlevel (balances->acct); + } + if (bal_slist != NULL) + { + g_slist_free (bal_slist); } LEAVE (""); @@ -399,7 +387,7 @@ gnc_sql_save_account (GncSqlBackend* be, QofInstance* inst) /* ================================================================= */ static void -load_account_guid (const GncSqlBackend* be, GncSqlRow* row, +load_account_guid (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -408,12 +396,11 @@ load_account_guid (const GncSqlBackend* be, GncSqlRow* row, Account* account = NULL; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); try { - auto val = row->get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (table_row.col_name); (void)string_to_guid (val.c_str(), &guid); account = xaccAccountLookup (&guid, be->book); if (account != NULL) diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index 3ce4a6f329..f83964d362 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -66,7 +66,7 @@ typedef void (*AddressSetterFunc) (gpointer, GncAddress*); typedef GncAddress* (*AddressGetterFunc) (const gpointer); static void -load_address (const GncSqlBackend* be, GncSqlRow* row, +load_address (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -85,7 +85,7 @@ load_address (const GncSqlBackend* be, GncSqlRow* row, subtable_row.col_name); try { - auto val = row->get_string_at_col (buf); + auto val = row.get_string_at_col (buf); g_free (buf); if (subtable_row.gobj_param_name != NULL) { diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 474f48ff11..605e3723f4 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -1202,7 +1202,7 @@ void set_object_parameter(gpointer pObject, T item, QofSetterFunc setter, /* ----------------------------------------------------------------- */ static void -load_string (const GncSqlBackend* be, GncSqlRow* row, +load_string (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -1211,7 +1211,7 @@ load_string (const GncSqlBackend* be, GncSqlRow* row, try { - auto s = row->get_string_at_col (table_row.col_name); + auto s = row.get_string_at_col (table_row.col_name); if (table_row.gobj_param_name != NULL) { if (QOF_IS_INSTANCE (pObject)) @@ -1274,7 +1274,7 @@ typedef gint (*IntAccessFunc) (const gpointer); typedef void (*IntSetterFunc) (const gpointer, gint); static void -load_int (const GncSqlBackend* be, GncSqlRow* row, +load_int (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -1282,7 +1282,7 @@ load_int (const GncSqlBackend* be, GncSqlRow* row, g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); - auto val = row->get_int_at_col(table_row.col_name); + auto val = row.get_int_at_col(table_row.col_name); if (table_row.gobj_param_name != NULL) { if (QOF_IS_INSTANCE (pObject)) @@ -1323,14 +1323,14 @@ typedef gboolean (*BooleanAccessFunc) (const gpointer); typedef void (*BooleanSetterFunc) (const gpointer, gboolean); static void -load_boolean (const GncSqlBackend* be, GncSqlRow* row, +load_boolean (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); - auto val = row->get_int_at_col (table_row.col_name); + auto val = row.get_int_at_col (table_row.col_name); if (table_row.gobj_param_name != nullptr) { if (QOF_IS_INSTANCE (pObject)) @@ -1371,14 +1371,14 @@ typedef gint64 (*Int64AccessFunc) (const gpointer); typedef void (*Int64SetterFunc) (const gpointer, gint64); static void -load_int64 (const GncSqlBackend* be, GncSqlRow* row, +load_int64 (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { g_return_if_fail (table_row.gobj_param_name != nullptr || setter != nullptr); - auto val = row->get_int_at_col (table_row.col_name); + auto val = row.get_int_at_col (table_row.col_name); if (table_row.gobj_param_name != nullptr) { if (QOF_IS_INSTANCE (pObject)) @@ -1415,7 +1415,7 @@ static GncSqlColumnTypeHandler int64_handler /* ----------------------------------------------------------------- */ static void -load_double (const GncSqlBackend* be, GncSqlRow* row, +load_double (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -1425,19 +1425,19 @@ load_double (const GncSqlBackend* be, GncSqlRow* row, double val; try { - val = static_cast(row->get_int_at_col(table_row.col_name)); + val = static_cast(row.get_int_at_col(table_row.col_name)); } catch (std::invalid_argument) { try { - val = static_cast(row->get_float_at_col(table_row.col_name)); + val = static_cast(row.get_float_at_col(table_row.col_name)); } catch (std::invalid_argument) { try { - val = row->get_double_at_col(table_row.col_name); + val = row.get_double_at_col(table_row.col_name); } catch (std::invalid_argument) { @@ -1481,7 +1481,7 @@ static GncSqlColumnTypeHandler double_handler /* ----------------------------------------------------------------- */ static void -load_guid (const GncSqlBackend* be, GncSqlRow* row, +load_guid (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -1496,7 +1496,7 @@ load_guid (const GncSqlBackend* be, GncSqlRow* row, std::string str; try { - str = row->get_string_at_col(table_row.col_name); + str = row.get_string_at_col(table_row.col_name); } catch (std::invalid_argument) { @@ -1619,7 +1619,7 @@ gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, Timespec ts) #pragma GCC diagnostic warning "-Wformat-nonliteral" static void -load_timespec (const GncSqlBackend* be, GncSqlRow* row, +load_timespec (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -1636,14 +1636,14 @@ load_timespec (const GncSqlBackend* be, GncSqlRow* row, ts_setter = (TimespecSetterFunc)setter; try { - auto val = row->get_time64_at_col(table_row.col_name); + auto val = row.get_time64_at_col(table_row.col_name); timespecFromTime64 (&ts, val); } catch (std::invalid_argument) { try { - auto val = row->get_string_at_col(table_row.col_name); + auto val = row.get_string_at_col(table_row.col_name); auto s = val.c_str(); auto buf = g_strdup_printf ("%c%c%c%c-%c%c-%c%c %c%c:%c%c:%c%c", s[0], s[1], s[2], s[3], s[4], s[5], @@ -1731,14 +1731,14 @@ static GncSqlColumnTypeHandler timespec_handler #define DATE_COL_SIZE 8 static void -load_date (const GncSqlBackend* be, GncSqlRow* row, +load_date (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { g_return_if_fail (pObject != NULL); g_return_if_fail (table_row.gobj_param_name != nullptr || setter != nullptr); - if (row->is_col_null(table_row.col_name)) + if (row.is_col_null(table_row.col_name)) return; GDate date; g_date_clear (&date, 1); @@ -1747,7 +1747,7 @@ load_date (const GncSqlBackend* be, GncSqlRow* row, /* timespec_to_gdate applies the tz, and gdates are saved * as ymd, so we don't want that. */ - auto time = row->get_time64_at_col(table_row.col_name); + auto time = row.get_time64_at_col(table_row.col_name); auto tm = gnc_gmtime(&time); g_date_set_dmy(&date, tm->tm_mday, static_cast(tm->tm_mon + 1), @@ -1758,7 +1758,7 @@ load_date (const GncSqlBackend* be, GncSqlRow* row, { try { - std::string str = row->get_string_at_col(table_row.col_name); + std::string str = row.get_string_at_col(table_row.col_name); if (str.empty()) return; auto year = static_cast(stoi (str.substr (0,4))); auto month = static_cast(stoi (str.substr (4,2))); @@ -1836,7 +1836,7 @@ static const EntryVec numeric_col_table = }; static void -load_numeric (const GncSqlBackend* be, GncSqlRow* row, +load_numeric (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -1849,10 +1849,10 @@ load_numeric (const GncSqlBackend* be, GncSqlRow* row, try { auto buf = g_strdup_printf ("%s_num", table_row.col_name); - auto num = row->get_int_at_col (buf); + auto num = row.get_int_at_col (buf); g_free (buf); buf = g_strdup_printf ("%s_denom", table_row.col_name); - auto denom = row->get_int_at_col (buf); + auto denom = row.get_int_at_col (buf); n = gnc_numeric_create (num, denom); } catch (std::invalid_argument) @@ -2018,12 +2018,11 @@ static EntryVec guid_table }; const GncGUID* -gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow* row) +gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow& row) { static GncGUID guid; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); gnc_sql_load_object (be, row, NULL, &guid, guid_table); @@ -2038,12 +2037,11 @@ static EntryVec tx_guid_table const GncGUID* -gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow* row) +gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow& row) { static GncGUID guid; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); gnc_sql_load_object (be, row, NULL, &guid, tx_guid_table); @@ -2051,7 +2049,7 @@ gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow* row) } void -gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow* row, +gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow& row, QofIdTypeConst obj_name, gpointer pObject, const EntryVec& table) { @@ -2118,15 +2116,14 @@ create_single_col_select_statement (GncSqlBackend* be, /* ================================================================= */ -GncSqlResult* +GncSqlResultPtr gnc_sql_execute_select_statement (GncSqlBackend* be, GncSqlStatement* stmt) { - GncSqlResult* result; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (stmt != NULL, NULL); - result = gnc_sql_connection_execute_select_statement (be->conn, stmt); + auto result = gnc_sql_connection_execute_select_statement (be->conn, stmt); if (result == NULL) { PERR ("SQL error: %s\n", gnc_sql_statement_to_sql (stmt)); @@ -2156,11 +2153,10 @@ gnc_sql_create_statement_from_sql (GncSqlBackend* be, const gchar* sql) return stmt; } -GncSqlResult* +GncSqlResultPtr gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) { GncSqlStatement* stmt; - GncSqlResult* result = NULL; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (sql != NULL, NULL); @@ -2170,7 +2166,7 @@ gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) { return NULL; } - result = gnc_sql_connection_execute_select_statement (be->conn, stmt); + auto result = gnc_sql_connection_execute_select_statement (be->conn, stmt); gnc_sql_statement_dispose (stmt); if (result == NULL) { @@ -2201,25 +2197,6 @@ gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql) return result; } -static guint -execute_statement_get_count (GncSqlBackend* be, GncSqlStatement* stmt) -{ - GncSqlResult* result; - guint count = 0; - - g_return_val_if_fail (be != NULL, 0); - g_return_val_if_fail (stmt != NULL, 0); - - result = gnc_sql_execute_select_statement (be, stmt); - if (result != NULL) - { - count = gnc_sql_result_get_num_rows (result); - gnc_sql_result_dispose (result); - } - - return count; -} - guint gnc_sql_append_guid_list_to_sql (GString* sql, GList* list, guint maxCount) { @@ -2255,7 +2232,6 @@ gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, const EntryVec& table) { - GncSqlStatement* sqlStmt; guint count; GncSqlColumnTypeHandler* pHandler; PairVec values; @@ -2266,26 +2242,25 @@ gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, g_return_val_if_fail (pObject != NULL, FALSE); /* SELECT * FROM */ - sqlStmt = create_single_col_select_statement (be, table_name, table[0]); - g_assert (sqlStmt != NULL); + auto stmt = create_single_col_select_statement (be, table_name, table[0]); + g_assert (stmt != NULL); /* WHERE */ pHandler = get_handler (table[0]); g_assert (pHandler != NULL); pHandler->add_value_to_vec_fn (be, obj_name, pObject, table[0], values); PairVec col_values {values[0]}; - gnc_sql_statement_add_where_cond (sqlStmt, obj_name, pObject, col_values); + gnc_sql_statement_add_where_cond (stmt, obj_name, pObject, col_values); - count = execute_statement_get_count (be, sqlStmt); - gnc_sql_statement_dispose (sqlStmt); - if (count == 0) + auto result = gnc_sql_execute_select_statement (be, stmt); + gnc_sql_statement_dispose (stmt); + if (result != NULL) { - return FALSE; - } - else - { - return TRUE; + auto retval = result->size() > 0; + delete result; + return retval; } + return false; } gboolean @@ -2676,26 +2651,16 @@ gnc_sql_init_version_info (GncSqlBackend* be) if (gnc_sql_connection_does_table_exist (be->conn, VERSION_TABLE_NAME)) { - GncSqlResult* result; - gchar* sql; - - sql = g_strdup_printf ("SELECT * FROM %s", VERSION_TABLE_NAME); - result = gnc_sql_execute_select_sql (be, sql); + auto sql = g_strdup_printf ("SELECT * FROM %s", VERSION_TABLE_NAME); + auto result = gnc_sql_execute_select_sql (be, sql); g_free (sql); - if (result != nullptr) + for (const auto& row : *result) { - for (auto row = gnc_sql_result_get_first_row (result); - row != nullptr ; - row = gnc_sql_result_get_next_row (result)) - { - auto name = row->get_string_at_col (TABLE_COL_NAME); - auto version = row->get_int_at_col (VERSION_COL_NAME); - g_hash_table_insert (be->versions, - g_strdup (name.c_str()), - GINT_TO_POINTER (version)); - } + auto name = row.get_string_at_col (TABLE_COL_NAME); + auto version = row.get_int_at_col (VERSION_COL_NAME); + g_hash_table_insert (be->versions, g_strdup (name.c_str()), + GINT_TO_POINTER (version)); } - gnc_sql_result_dispose (result); } else { @@ -2833,4 +2798,20 @@ get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, } #endif +GncSqlRow& +GncSqlRow::operator++() +{ + auto& new_row = m_iter->operator++(); + if (new_row != *this) + m_iter = nullptr; + return new_row; +} + +/* +GncSqlResult* +GncSqlRow::operator*() +{ + return m_iter->operator*(); +} +*/ /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index e18ed0b96b..7f5255b610 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -139,7 +139,9 @@ void gnc_sql_commit_edit (GncSqlBackend* qbe, QofInstance* inst); /** */ typedef struct GncSqlStatement GncSqlStatement; -typedef struct GncSqlResult GncSqlResult; +class GncSqlResult; +//using GncSqlResultPtr = std::unique_ptr; +using GncSqlResultPtr = GncSqlResult*; /** *@struct GncSqlStatement @@ -170,7 +172,7 @@ struct GncSqlStatement struct GncSqlConnection { void (*dispose) (GncSqlConnection*); - GncSqlResult* (*executeSelectStatement) (GncSqlConnection*, GncSqlStatement*); /**< Returns NULL if error */ + GncSqlResultPtr (*executeSelectStatement) (GncSqlConnection*, GncSqlStatement*); /**< Returns NULL if error */ gint (*executeNonSelectStatement) (GncSqlConnection*, GncSqlStatement*); /**< Returns -1 if error */ GncSqlStatement* (*createStatementFromSql) (GncSqlConnection*, const gchar*); gboolean (*doesTableExist) (GncSqlConnection*, const gchar*); /**< Returns true if successful */ @@ -211,39 +213,82 @@ struct GncSqlConnection * SQL backends must provide a structure which implements all of the functions. */ -class GncSqlRow +class GncSqlRow; +/** + * Pure virtual class to iterate over a query result set. + */ +class GncSqlResult { public: - virtual ~GncSqlRow() = default; - virtual int64_t get_int_at_col (const char* col) = 0; - virtual float get_float_at_col (const char* col) = 0; - virtual double get_double_at_col (const char* col) = 0; - virtual std::string get_string_at_col (const char* col) = 0; - virtual time64 get_time64_at_col (const char* col) = 0; - virtual bool is_col_null (const char* col) const noexcept = 0; + virtual ~GncSqlResult() = default; + virtual uint64_t size() const noexcept = 0; + virtual GncSqlRow& begin() = 0; + virtual GncSqlRow& end() = 0; + friend GncSqlRow; +protected: + class IteratorImpl { + public: + virtual ~IteratorImpl() = default; + virtual GncSqlRow& operator++() = 0; + virtual GncSqlResult* operator*() = 0; + virtual int64_t get_int_at_col (const char* col) const = 0; + virtual float get_float_at_col (const char* col) const = 0; + virtual double get_double_at_col (const char* col) const = 0; + virtual std::string get_string_at_col (const char* col) const = 0; + virtual time64 get_time64_at_col (const char* col) const = 0; + virtual bool is_col_null (const char* col) const noexcept = 0; + }; }; /** - * @struct GncSqlResult + * Row of SQL Query results. * - * Struct used to represent the result of an SQL SELECT statement. SQL - * backends must provide a structure which implements all of the functions. + * This is a "pointer" class of a pimpl pattern, the implementation being + * GncSqlResul::IteratorImpl. It's designed to present a std::forward_iterator + * like interface for use with range-for while allowing for wrapping a C API. + * + * Important Implementation Note: Operator++() as written requires that the + * sentinel GncSqlRow returned by GncSqlResult::end() has m_impl = nullptr in + * order to terminate the loop condition. This is a bit of a hack and might be a + * problem with a different SQL interface library from libdbi. + * + * Note that GncSqlResult::begin and GncSqlRow::operator++() return + * GncSqlRow&. This is necessary for operator++() to be called: Using operator + * ++() on a pointer performs pointer arithmetic rather than calling the + * pointed-to-class's operator++() and C++'s range-for uses operator++() + * directly on whatever begin() gives it. */ -struct GncSqlResult +class GncSqlRow { - guint (*getNumRows) (GncSqlResult*); - GncSqlRow* (*getFirstRow) (GncSqlResult*); - GncSqlRow* (*getNextRow) (GncSqlResult*); - void (*dispose) (GncSqlResult*); +public: + GncSqlRow (GncSqlResult::IteratorImpl* iter) : m_iter{iter} {} + ~GncSqlRow() { } + GncSqlRow& operator++(); + GncSqlRow& operator*() { return *this; } + friend bool operator!=(const GncSqlRow&, const GncSqlRow&); + int64_t get_int_at_col (const char* col) const { + return m_iter->get_int_at_col (col); } + float get_float_at_col (const char* col) const { + return m_iter->get_float_at_col (col); } + double get_double_at_col (const char* col) const { + return m_iter->get_double_at_col (col); } + std::string get_string_at_col (const char* col) const { + return m_iter->get_string_at_col (col); } + time64 get_time64_at_col (const char* col) const { + return m_iter->get_time64_at_col (col); } + bool is_col_null (const char* col) const noexcept { + return m_iter->is_col_null (col); } +private: + GncSqlResult::IteratorImpl* m_iter; }; -#define gnc_sql_result_get_num_rows(RESULT) \ - (RESULT)->getNumRows(RESULT) -#define gnc_sql_result_get_first_row(RESULT) \ - (RESULT)->getFirstRow(RESULT) -#define gnc_sql_result_get_next_row(RESULT) \ - (RESULT)->getNextRow(RESULT) -#define gnc_sql_result_dispose(RESULT) \ - (RESULT)->dispose(RESULT) + +inline bool operator!=(const GncSqlRow& lr, const GncSqlRow& rr) { + return lr.m_iter != rr.m_iter; +} + +inline bool operator==(const GncSqlRow& lr, const GncSqlRow& rr) { + return !(lr != rr); +} /** * @struct GncSqlObjectBackend @@ -434,7 +479,7 @@ typedef enum } E_DB_OPERATION; typedef void (*GNC_SQL_LOAD_FN) (const GncSqlBackend* be, - GncSqlRow* row, QofSetterFunc setter, + GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row); typedef void (*GNC_SQL_ADD_COL_INFO_TO_LIST_FN) (const GncSqlBackend* be, @@ -512,8 +557,8 @@ gboolean gnc_sql_do_db_operation (GncSqlBackend* be, * @param statement Statement * @return Results, or NULL if an error has occured */ -GncSqlResult* gnc_sql_execute_select_statement (GncSqlBackend* be, - GncSqlStatement* statement); +GncSqlResultPtr gnc_sql_execute_select_statement (GncSqlBackend* be, + GncSqlStatement* statement); /** * Executes an SQL SELECT statement from an SQL char string and returns the @@ -524,7 +569,7 @@ GncSqlResult* gnc_sql_execute_select_statement (GncSqlBackend* be, * @param sql SQL SELECT string * @return Results, or NULL if an error has occured */ -GncSqlResult* gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql); +GncSqlResultPtr gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql); /** * Executes an SQL non-SELECT statement from an SQL char string. @@ -554,7 +599,7 @@ GncSqlStatement* gnc_sql_create_statement_from_sql (GncSqlBackend* be, * @param pObject Object to be loaded * @param table DB table description */ -void gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow* row, +void gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow& row, QofIdTypeConst obj_name, gpointer pObject, const EntryVec& table); @@ -636,7 +681,7 @@ gboolean gnc_sql_create_index (const GncSqlBackend* be, const char* index_name, * @return GncGUID */ -const GncGUID* gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow* row); +const GncGUID* gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow& row); /** * Loads the transaction guid from a database row. The table must have a column @@ -647,7 +692,7 @@ const GncGUID* gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow* row); * @return GncGUID */ -const GncGUID* gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow* row); +const GncGUID* gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow& row); /** * Creates a basic SELECT statement for a table. diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index 6d5dbba707..8370f41509 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -172,14 +172,13 @@ bt_set_parent_guid (gpointer pObject, gpointer pValue) } static GncBillTerm* -load_single_billterm (GncSqlBackend* be, GncSqlRow* row, +load_single_billterm (GncSqlBackend* be, GncSqlRow& row, GList** l_billterms_needing_parents) { const GncGUID* guid; GncBillTerm* pBillTerm; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); pBillTerm = gncBillTermLookup (be->book, guid); @@ -221,60 +220,50 @@ static void load_all_billterms (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + GList* list = NULL; + GList* l_billterms_needing_parents = NULL; + + for (auto row : *result) { - GncSqlRow* row; - GList* list = NULL; - GList* l_billterms_needing_parents = NULL; + auto pBillTerm = + load_single_billterm (be, row, &l_billterms_needing_parents); + if (pBillTerm != NULL) + list = g_list_append (list, pBillTerm); + } - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + if (list != NULL) + { + gnc_sql_slots_load_for_list (be, list); + g_list_free (list); + } + + /* 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 + items are removed from the front and added to the back if the + parent is still not available, then eventually, the list will + shrink to size 0. */ + if (l_billterms_needing_parents != NULL) + { + gboolean progress_made = TRUE; + GList* elem; + + while (progress_made) { - GncBillTerm* pBillTerm = load_single_billterm (be, row, - &l_billterms_needing_parents); - if (pBillTerm != NULL) + progress_made = FALSE; + for (elem = l_billterms_needing_parents; elem != NULL; + elem = g_list_next (elem)) { - list = g_list_append (list, pBillTerm); - } - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } - - /* 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 - items are removed from the front and added to the back if the - parent is still not available, then eventually, the list will - shrink to size 0. */ - if (l_billterms_needing_parents != NULL) - { - gboolean progress_made = TRUE; - GList* elem; - - while (progress_made) - { - progress_made = FALSE; - for (elem = l_billterms_needing_parents; elem != NULL; - elem = g_list_next (elem)) - { - billterm_parent_guid_struct* s = (billterm_parent_guid_struct*)elem->data; - bt_set_parent (s->billterm, &s->guid); - l_billterms_needing_parents = g_list_delete_link (l_billterms_needing_parents, - elem); - progress_made = TRUE; - } + billterm_parent_guid_struct* s = (billterm_parent_guid_struct*)elem->data; + bt_set_parent (s->billterm, &s->guid); + l_billterms_needing_parents = g_list_delete_link (l_billterms_needing_parents, + elem); + progress_made = TRUE; } } } @@ -349,7 +338,7 @@ gnc_sql_save_billterm (GncSqlBackend* be, QofInstance* inst) /* ================================================================= */ static void -load_billterm_guid (const GncSqlBackend* be, GncSqlRow* row, +load_billterm_guid (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -357,12 +346,11 @@ load_billterm_guid (const GncSqlBackend* be, GncSqlRow* row, GncBillTerm* term = NULL; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); try { - auto val = row->get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (table_row.col_name); string_to_guid (val.c_str(), &guid); term = gncBillTermLookup (be->book, &guid); if (term != NULL) diff --git a/src/backend/sql/gnc-book-sql.cpp b/src/backend/sql/gnc-book-sql.cpp index 500c2f94e4..627651d5b8 100644 --- a/src/backend/sql/gnc-book-sql.cpp +++ b/src/backend/sql/gnc-book-sql.cpp @@ -136,12 +136,11 @@ set_root_template_guid (gpointer pObject, gpointer pValue) /* ================================================================= */ static void -load_single_book (GncSqlBackend* be, GncSqlRow* row) +load_single_book (GncSqlBackend* be, GncSqlRow& row) { QofBook* pBook; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); gnc_sql_load_guid (be, row); @@ -163,35 +162,29 @@ static void load_all_books (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, BOOK_TABLE); if (stmt != NULL) { - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + auto row = result->begin(); + + /* If there are no rows, try committing the book; unset + * loading so that it will actually get saved. + */ + if (row == result->end()) { - GncSqlRow* row = gnc_sql_result_get_first_row (result); - - /* If there are no rows, try committing the book; unset - * loading so that it will actually get saved. - */ - if (row == NULL) - { - be->loading = FALSE; - (void)gnc_sql_save_book (be, QOF_INSTANCE (be->book)); - be->loading = TRUE; - } - else - { - // Otherwise, load the 1st book. - load_single_book (be, row); - } - - gnc_sql_result_dispose (result); + be->loading = FALSE; + (void)gnc_sql_save_book (be, QOF_INSTANCE (be->book)); + be->loading = TRUE; + } + else + { + // Otherwise, load the 1st book. + load_single_book (be, *row); } } } diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index aedc2f70dd..18c7c869bd 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -193,7 +193,6 @@ load_budget_amounts (GncSqlBackend* be, GncBudget* budget) gchar guid_buf[GUID_ENCODING_LENGTH + 1]; gchar* sql; GncSqlStatement* stmt; - GncSqlResult* result; g_return_if_fail (be != NULL); g_return_if_fail (budget != NULL); @@ -206,20 +205,12 @@ load_budget_amounts (GncSqlBackend* be, GncBudget* budget) g_free (sql); if (stmt != NULL) { - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) - { - GncSqlRow* row = gnc_sql_result_get_first_row (result); - budget_amount_info_t info = { budget, NULL, 0 }; + budget_amount_info_t info = { budget, NULL, 0 }; - while (row != NULL) - { - gnc_sql_load_object (be, row, NULL, &info, budget_amounts_col_table); - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - } + for (auto row : *result) + gnc_sql_load_object (be, row, NULL, &info, budget_amounts_col_table); } } @@ -294,14 +285,13 @@ save_budget_amounts (GncSqlBackend* be, GncBudget* budget) } /*----------------------------------------------------------------*/ static GncBudget* -load_single_budget (GncSqlBackend* be, GncSqlRow* row) +load_single_budget (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; GncBudget* pBudget = NULL; Recurrence* r; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); if (guid != NULL) @@ -331,7 +321,6 @@ static void load_all_budgets (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; GList* list = NULL; g_return_if_fail (be != NULL); @@ -339,29 +328,21 @@ load_all_budgets (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, BUDGET_TABLE); if (stmt != NULL) { - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + for (auto row : *result) { - GncSqlRow* row = gnc_sql_result_get_first_row (result); - GncBudget* b; - - while (row != NULL) + auto b = load_single_budget (be, row); + if (b != NULL) { - b = load_single_budget (be, row); - if (b != NULL) - { - list = g_list_prepend (list, b); - } - row = gnc_sql_result_get_next_row (result); + list = g_list_prepend (list, b); } - gnc_sql_result_dispose (result); + } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (list != NULL) + { + gnc_sql_slots_load_for_list (be, list); + g_list_free (list); } } } @@ -480,7 +461,7 @@ write_budgets (GncSqlBackend* be) /* ================================================================= */ static void -load_budget_guid (const GncSqlBackend* be, GncSqlRow* row, +load_budget_guid (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -489,12 +470,11 @@ load_budget_guid (const GncSqlBackend* be, GncSqlRow* row, GncBudget* budget = NULL; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); try { - auto val = row->get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (table_row.col_name); (void)string_to_guid (val.c_str(), &guid); budget = gnc_budget_lookup (&guid, be->book); if (budget != NULL) diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index b31be69d12..8c3ccb6c99 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -112,7 +112,7 @@ set_quote_source_name (gpointer pObject, gpointer pValue) } static gnc_commodity* -load_single_commodity (GncSqlBackend* be, GncSqlRow* row) +load_single_commodity (GncSqlBackend* be, GncSqlRow& row) { QofBook* pBook = be->book; gnc_commodity* pCommodity; @@ -129,39 +129,30 @@ static void load_all_commodities (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; gnc_commodity_table* pTable; pTable = gnc_commodity_table_get_table (be->book); stmt = gnc_sql_create_select_statement (be, COMMODITIES_TABLE); if (stmt == NULL) return; - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + + for (auto row : *result) { - gnc_commodity* pCommodity; - GncSqlRow* row = gnc_sql_result_get_first_row (result); - gchar* sql; + auto pCommodity = load_single_commodity (be, row); - while (row != NULL) + if (pCommodity != NULL) { - pCommodity = load_single_commodity (be, row); + GncGUID guid; - if (pCommodity != NULL) - { - GncGUID guid; - - guid = *qof_instance_get_guid (QOF_INSTANCE (pCommodity)); - pCommodity = gnc_commodity_table_insert (pTable, pCommodity); - if (qof_instance_is_dirty (QOF_INSTANCE (pCommodity))) - gnc_sql_push_commodity_for_postload_processing (be, (gpointer)pCommodity); - qof_instance_set_guid (QOF_INSTANCE (pCommodity), &guid); - } - row = gnc_sql_result_get_next_row (result); + guid = *qof_instance_get_guid (QOF_INSTANCE (pCommodity)); + pCommodity = gnc_commodity_table_insert (pTable, pCommodity); + if (qof_instance_is_dirty (QOF_INSTANCE (pCommodity))) + gnc_sql_push_commodity_for_postload_processing (be, (gpointer)pCommodity); + qof_instance_set_guid (QOF_INSTANCE (pCommodity), &guid); } - gnc_sql_result_dispose (result); - sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", COMMODITIES_TABLE); + auto sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", COMMODITIES_TABLE); gnc_sql_slots_load_for_sql_subquery (be, sql, (BookLookupFn)gnc_commodity_find_commodity_by_guid); g_free (sql); @@ -273,7 +264,7 @@ gnc_sql_commit_commodity (gnc_commodity* pCommodity) /* ----------------------------------------------------------------- */ static void -load_commodity_guid (const GncSqlBackend* be, GncSqlRow* row, +load_commodity_guid (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -281,12 +272,11 @@ load_commodity_guid (const GncSqlBackend* be, GncSqlRow* row, gnc_commodity* commodity = NULL; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); try { - auto val = row->get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (table_row.col_name); (void)string_to_guid (val.c_str(), &guid); commodity = gnc_commodity_find_commodity_by_guid (&guid, be->book); if (commodity != NULL) diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index a647cce88c..86db2ac715 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -86,13 +86,12 @@ static EntryVec col_table }); static GncCustomer* -load_single_customer (GncSqlBackend* be, GncSqlRow* row) +load_single_customer (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; GncCustomer* pCustomer; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); pCustomer = gncCustomerLookup (be->book, guid); @@ -110,36 +109,28 @@ static void load_all_customers (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + GList* list = NULL; + + for (auto row : *result) { - GList* list = NULL; - GncSqlRow* row; - - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + GncCustomer* pCustomer = load_single_customer (be, row); + if (pCustomer != NULL) { - GncCustomer* pCustomer = load_single_customer (be, row); - if (pCustomer != NULL) - { - list = g_list_append (list, pCustomer); - } - row = gnc_sql_result_get_next_row (result); + list = g_list_append (list, pCustomer); } - gnc_sql_result_dispose (result); + } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (list != NULL) + { + gnc_sql_slots_load_for_list (be, list); + g_list_free (list); } } diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index f80accd66e..d71030c85c 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -74,13 +74,12 @@ static EntryVec col_table }); static GncEmployee* -load_single_employee (GncSqlBackend* be, GncSqlRow* row) +load_single_employee (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; GncEmployee* pEmployee; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); pEmployee = gncEmployeeLookup (be->book, guid); @@ -98,36 +97,30 @@ static void load_all_employees (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + + GList* list = NULL; + + for (auto row : *result) { - GncSqlRow* row; - GList* list = NULL; - - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + GncEmployee* pEmployee = load_single_employee (be, row); + if (pEmployee != NULL) { - GncEmployee* pEmployee = load_single_employee (be, row); - if (pEmployee != NULL) - { - list = g_list_append (list, pEmployee); - } - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); + list = g_list_append (list, pEmployee); } } + + if (list != NULL) + { + gnc_sql_slots_load_for_list (be, list); + g_list_free (list); + } + } /* ================================================================= */ diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index ac2d8dcb6f..a44057cf66 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -150,13 +150,12 @@ entry_set_bill (gpointer pObject, gpointer val) } static GncEntry* -load_single_entry (GncSqlBackend* be, GncSqlRow* row) +load_single_entry (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; GncEntry* pEntry; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); pEntry = gncEntryLookup (be->book, guid); @@ -174,35 +173,27 @@ static void load_all_entries (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + GList* list = NULL; + + for (auto row : *result) { - GncSqlRow* row; - GList* list = NULL; - - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + GncEntry* pEntry = load_single_entry (be, row); + if (pEntry != NULL) { - GncEntry* pEntry = load_single_entry (be, row); - if (pEntry != NULL) - { - list = g_list_append (list, pEntry); - } - row = gnc_sql_result_get_next_row (result); + list = g_list_append (list, pEntry); } - gnc_sql_result_dispose (result); + } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (list != NULL) + { + gnc_sql_slots_load_for_list (be, list); + g_list_free (list); } } diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index 74db65b11e..2f80683053 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -94,13 +94,12 @@ static EntryVec col_table }); static GncInvoice* -load_single_invoice (GncSqlBackend* be, GncSqlRow* row) +load_single_invoice (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; GncInvoice* pInvoice; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); pInvoice = gncInvoiceLookup (be->book, guid); @@ -118,35 +117,27 @@ static void load_all_invoices (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + GList* list = NULL; + + for (auto row : *result) { - GncSqlRow* row; - GList* list = NULL; - - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + GncInvoice* pInvoice = load_single_invoice (be, row); + if (pInvoice != NULL) { - GncInvoice* pInvoice = load_single_invoice (be, row); - if (pInvoice != NULL) - { - list = g_list_append (list, pInvoice); - } - row = gnc_sql_result_get_next_row (result); + list = g_list_append (list, pInvoice); } - gnc_sql_result_dispose (result); + } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (list != NULL) + { + gnc_sql_slots_load_for_list (be, list); + g_list_free (list); } } @@ -284,7 +275,7 @@ write_invoices (GncSqlBackend* be) /* ================================================================= */ static void -load_invoice_guid (const GncSqlBackend* be, GncSqlRow* row, +load_invoice_guid (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -292,12 +283,11 @@ load_invoice_guid (const GncSqlBackend* be, GncSqlRow* row, GncInvoice* invoice = NULL; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); try { - auto val = row->get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (table_row.col_name); string_to_guid (val.c_str(), &guid); invoice = gncInvoiceLookup (be->book, &guid); if (invoice != NULL) diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index f7f9ba7190..0f4b9c7c7c 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -71,13 +71,12 @@ static EntryVec col_table }); static GncJob* -load_single_job (GncSqlBackend* be, GncSqlRow* row) +load_single_job (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; GncJob* pJob; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); pJob = gncJobLookup (be->book, guid); @@ -95,35 +94,26 @@ static void load_all_jobs (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; - g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + GList* list = NULL; + + for (auto row : *result) { - GncSqlRow* row; - GList* list = NULL; - - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + GncJob* pJob = load_single_job (be, row); + if (pJob != NULL) { - GncJob* pJob = load_single_job (be, row); - if (pJob != NULL) - { - list = g_list_append (list, pJob); - } - row = gnc_sql_result_get_next_row (result); + list = g_list_append (list, pJob); } - gnc_sql_result_dispose (result); + } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (list != NULL) + { + gnc_sql_slots_load_for_list (be, list); + g_list_free (list); } } diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index a8ba9f7892..644c28e6d5 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -97,12 +97,11 @@ set_lot_account (gpointer pObject, gpointer pValue) } static GNCLot* -load_single_lot (GncSqlBackend* be, GncSqlRow* row) +load_single_lot (GncSqlBackend* be, GncSqlRow& row) { GNCLot* lot; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); lot = gnc_lot_new (be->book); @@ -117,31 +116,22 @@ static void load_all_lots (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; - g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, TABLE_NAME); if (stmt != NULL) { - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) - { - GncSqlRow* row = gnc_sql_result_get_first_row (result); - gchar* sql; + if (result->begin () == nullptr) + return; + for (auto row : *result) + load_single_lot (be, row); - while (row != NULL) - { - load_single_lot (be, row); - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - - sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", TABLE_NAME); - gnc_sql_slots_load_for_sql_subquery (be, sql, (BookLookupFn)gnc_lot_lookup); - g_free (sql); - } + auto sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", + TABLE_NAME); + gnc_sql_slots_load_for_sql_subquery (be, sql, (BookLookupFn)gnc_lot_lookup); + g_free (sql); } } @@ -214,7 +204,7 @@ write_lots (GncSqlBackend* be) /* ================================================================= */ static void -load_lot_guid (const GncSqlBackend* be, GncSqlRow* row, +load_lot_guid (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -222,12 +212,11 @@ load_lot_guid (const GncSqlBackend* be, GncSqlRow* row, GNCLot* lot; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); try { - auto val = row->get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (table_row.col_name); (void)string_to_guid (val.c_str(), &guid); lot = gnc_lot_lookup (&guid, be->book); if (lot != NULL) diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index 2ac48a22ef..ad4685e85c 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -67,13 +67,12 @@ static EntryVec col_table }); static GncOrder* -load_single_order (GncSqlBackend* be, GncSqlRow* row) +load_single_order (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; GncOrder* pOrder; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); pOrder = gncOrderLookup (be->book, guid); @@ -91,35 +90,26 @@ static void load_all_orders (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; - g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + GList* list = NULL; + + for (auto row : *result) { - GncSqlRow* row; - GList* list = NULL; - - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + GncOrder* pOrder = load_single_order (be, row); + if (pOrder != NULL) { - GncOrder* pOrder = load_single_order (be, row); - if (pOrder != NULL) - { - list = g_list_append (list, pOrder); - } - row = gnc_sql_result_get_next_row (result); + list = g_list_append (list, pOrder); } - gnc_sql_result_dispose (result); + } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (list != NULL) + { + gnc_sql_slots_load_for_list (be, list); + g_list_free (list); } } @@ -199,7 +189,7 @@ write_orders (GncSqlBackend* be) /* ================================================================= */ static void -load_order_guid (const GncSqlBackend* be, GncSqlRow* row, +load_order_guid (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -207,12 +197,11 @@ load_order_guid (const GncSqlBackend* be, GncSqlRow* row, GncOrder* order = NULL; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); try { - auto val = row->get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (table_row.col_name); string_to_guid (val.c_str(), &guid); order = gncOrderLookup (be->book, &guid); if (order != NULL) diff --git a/src/backend/sql/gnc-owner-sql.cpp b/src/backend/sql/gnc-owner-sql.cpp index 21efa59f05..b1764fd5c7 100644 --- a/src/backend/sql/gnc-owner-sql.cpp +++ b/src/backend/sql/gnc-owner-sql.cpp @@ -49,7 +49,7 @@ typedef void (*OwnerSetterFunc) (gpointer, GncOwner*); typedef GncOwner* (*OwnerGetterFunc) (const gpointer); static void -load_owner (const GncSqlBackend* be, GncSqlRow* row, +load_owner (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -59,17 +59,16 @@ load_owner (const GncSqlBackend* be, GncSqlRow* row, GncGUID* pGuid = NULL; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); auto book = be->book; auto buf = g_strdup_printf ("%s_type", table_row.col_name); try { - type = static_cast(row->get_int_at_col (buf)); + type = static_cast(row.get_int_at_col (buf)); g_free (buf); buf = g_strdup_printf ("%s_guid", table_row.col_name); - auto val = row->get_string_at_col (buf); + auto val = row.get_string_at_col (buf); g_free (buf); string_to_guid (val.c_str(), &guid); pGuid = &guid; diff --git a/src/backend/sql/gnc-price-sql.cpp b/src/backend/sql/gnc-price-sql.cpp index 2360b9af45..41c6c68258 100644 --- a/src/backend/sql/gnc-price-sql.cpp +++ b/src/backend/sql/gnc-price-sql.cpp @@ -67,12 +67,11 @@ static const EntryVec col_table /* ================================================================= */ static GNCPrice* -load_single_price (GncSqlBackend* be, GncSqlRow* row) +load_single_price (GncSqlBackend* be, GncSqlRow& row) { GNCPrice* pPrice; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); pPrice = gnc_price_create (be->book); @@ -87,7 +86,6 @@ static void load_all_prices (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; QofBook* pBook; GNCPriceDB* pPriceDB; @@ -98,33 +96,30 @@ load_all_prices (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, TABLE_NAME); if (stmt != NULL) { - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + if (result->begin() == result->end()) + return; + + GNCPrice* pPrice; + gchar* sql; + + gnc_pricedb_set_bulk_update (pPriceDB, TRUE); + for (auto row : *result) { - GNCPrice* pPrice; - GncSqlRow* row = gnc_sql_result_get_first_row (result); - gchar* sql; + pPrice = load_single_price (be, row); - gnc_pricedb_set_bulk_update (pPriceDB, TRUE); - while (row != NULL) + if (pPrice != NULL) { - pPrice = load_single_price (be, row); - - if (pPrice != NULL) - { - (void)gnc_pricedb_add_price (pPriceDB, pPrice); - gnc_price_unref (pPrice); - } - row = gnc_sql_result_get_next_row (result); + (void)gnc_pricedb_add_price (pPriceDB, pPrice); + gnc_price_unref (pPrice); } - gnc_sql_result_dispose (result); - 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 (be, sql, (BookLookupFn)gnc_price_lookup); - g_free (sql); } + 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 (be, sql, (BookLookupFn)gnc_price_lookup); + g_free (sql); } } diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index 2d3925f5f5..8cd1a4711d 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -284,12 +284,11 @@ gnc_sql_recurrence_delete (GncSqlBackend* be, const GncGUID* guid) } static void -load_recurrence (GncSqlBackend* be, GncSqlRow* row, Recurrence* r) +load_recurrence (GncSqlBackend* be, GncSqlRow& row, Recurrence* r) { recurrence_info_t recurrence_info; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (r != NULL); recurrence_info.be = be; @@ -298,13 +297,12 @@ load_recurrence (GncSqlBackend* be, GncSqlRow* row, Recurrence* r) gnc_sql_load_object (be, row, TABLE_NAME, &recurrence_info, col_table); } -static GncSqlResult* +static GncSqlResultPtr gnc_sql_set_recurrences_from_db (GncSqlBackend* be, const GncGUID* guid) { gchar* buf; gchar guid_buf[GUID_ENCODING_LENGTH + 1]; GncSqlStatement* stmt; - GncSqlResult* result; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (guid != NULL, NULL); @@ -314,7 +312,7 @@ gnc_sql_set_recurrences_from_db (GncSqlBackend* be, const GncGUID* guid) guid_buf); stmt = gnc_sql_connection_create_statement_from_sql (be->conn, buf); g_free (buf); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); return result; } @@ -322,33 +320,24 @@ gnc_sql_set_recurrences_from_db (GncSqlBackend* be, const GncGUID* guid) Recurrence* gnc_sql_recurrence_load (GncSqlBackend* be, const GncGUID* guid) { - GncSqlResult* result; Recurrence* r = NULL; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (guid != NULL, NULL); - result = gnc_sql_set_recurrences_from_db (be, guid); - if (result != NULL) + auto result = gnc_sql_set_recurrences_from_db (be, guid); + auto row = result->begin(); + if (row == nullptr) { - guint numRows = gnc_sql_result_get_num_rows (result); - - if (numRows > 0) - { - if (numRows > 1) - { - g_warning ("More than 1 recurrence found: first one used"); - } - r = g_new0 (Recurrence, 1); - g_assert (r != NULL); - load_recurrence (be, gnc_sql_result_get_first_row (result), r); - } - else - { - g_warning ("No recurrences found"); - } - gnc_sql_result_dispose (result); + g_warning ("No recurrences found"); + return r; } + r = g_new0 (Recurrence, 1); + g_assert (r != NULL); + load_recurrence (be, *(result->begin()), r); + + if (++row != nullptr) + g_warning ("More than 1 recurrence found: first one used"); return r; } @@ -356,26 +345,18 @@ gnc_sql_recurrence_load (GncSqlBackend* be, const GncGUID* guid) GList* gnc_sql_recurrence_load_list (GncSqlBackend* be, const GncGUID* guid) { - GncSqlResult* result; GList* list = NULL; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (guid != NULL, NULL); - result = gnc_sql_set_recurrences_from_db (be, guid); - if (result != NULL) + auto result = gnc_sql_set_recurrences_from_db (be, guid); + for (auto row : *result) { - GncSqlRow* row = gnc_sql_result_get_first_row (result); - - while (row != NULL) - { - Recurrence* pRecurrence = g_new0 (Recurrence, 1); - g_assert (pRecurrence != NULL); - load_recurrence (be, row, pRecurrence); - list = g_list_append (list, pRecurrence); - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); + Recurrence* pRecurrence = g_new0 (Recurrence, 1); + g_assert (pRecurrence != NULL); + load_recurrence (be, row, pRecurrence); + list = g_list_append (list, pRecurrence); } return list; diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index 91d7f0c05a..722744b25a 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -75,7 +75,7 @@ static const EntryVec col_table /* ================================================================= */ static SchedXaction* -load_single_sx (GncSqlBackend* be, GncSqlRow* row) +load_single_sx (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; SchedXaction* pSx; @@ -83,7 +83,6 @@ load_single_sx (GncSqlBackend* be, GncSqlRow* row) GDate start_date; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); g_assert (guid != NULL); @@ -105,41 +104,33 @@ static void load_all_sxes (GncSqlBackend* be) { GncSqlStatement* stmt = NULL; - GncSqlResult* result; g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, SCHEDXACTION_TABLE); if (stmt == NULL) return; - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + SchedXactions* sxes; + GList* list = NULL; + sxes = gnc_book_get_schedxactions (be->book); + + for (auto row : *result) { - GncSqlRow* row; - SchedXactions* sxes; - GList* list = NULL; - sxes = gnc_book_get_schedxactions (be->book); + SchedXaction* sx; - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + sx = load_single_sx (be, row); + if (sx != NULL) { - SchedXaction* sx; - - sx = load_single_sx (be, row); - if (sx != NULL) - { - gnc_sxes_add_sx (sxes, sx); - list = g_list_prepend (list, sx); - } - row = gnc_sql_result_get_next_row (result); + gnc_sxes_add_sx (sxes, sx); + list = g_list_prepend (list, sx); } - gnc_sql_result_dispose (result); + } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (list != NULL) + { + gnc_sql_slots_load_for_list (be, list); + g_list_free (list); } } diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index 68419d89ed..2f3581b06a 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -724,7 +724,6 @@ gboolean gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid) { gchar* buf; - GncSqlResult* result; gchar guid_buf[GUID_ENCODING_LENGTH + 1]; GncSqlStatement* stmt; slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID, NULL, FRAME, NULL, g_string_new (NULL) }; @@ -740,30 +739,23 @@ gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid) g_free (buf); if (stmt != NULL) { - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + for (auto row : *result) { - GncSqlRow* row = gnc_sql_result_get_first_row (result); - - while (row != NULL) + try { - try - { - const GncSqlColumnTableEntry& table_row = - col_table[guid_val_col]; - GncGUID child_guid; - auto val = row->get_string_at_col (table_row.col_name); - (void)string_to_guid (val.c_str(), &child_guid); - gnc_sql_slots_delete (be, &child_guid); - row = gnc_sql_result_get_next_row (result); - } - catch (std::invalid_argument) - { - continue; - } + const GncSqlColumnTableEntry& table_row = + col_table[guid_val_col]; + GncGUID child_guid; + auto val = row.get_string_at_col (table_row.col_name); + (void)string_to_guid (val.c_str(), &child_guid); + gnc_sql_slots_delete (be, &child_guid); + } + catch (std::invalid_argument) + { + continue; } - gnc_sql_result_dispose (result); } } @@ -777,13 +769,12 @@ gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid) } static void -load_slot (slot_info_t* pInfo, GncSqlRow* row) +load_slot (slot_info_t* pInfo, GncSqlRow& row) { slot_info_t* slot_info; g_return_if_fail (pInfo != NULL); g_return_if_fail (pInfo->be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pInfo->pKvpFrame != NULL); slot_info = slot_info_copy (pInfo, NULL); @@ -829,7 +820,6 @@ static void slots_load_info (slot_info_t* pInfo) { gchar* buf; - GncSqlResult* result; gchar guid_buf[GUID_ENCODING_LENGTH + 1]; GncSqlStatement* stmt; @@ -846,29 +836,19 @@ slots_load_info (slot_info_t* pInfo) g_free (buf); if (stmt != NULL) { - result = gnc_sql_execute_select_statement (pInfo->be, stmt); + auto result = gnc_sql_execute_select_statement (pInfo->be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) - { - GncSqlRow* row = gnc_sql_result_get_first_row (result); - - while (row != NULL) - { - load_slot (pInfo, row); - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - } + for (auto row : *result) + load_slot (pInfo, row); } } static const GncGUID* -load_obj_guid (const GncSqlBackend* be, GncSqlRow* row) +load_obj_guid (const GncSqlBackend* be, GncSqlRow& row) { static GncGUID guid; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); gnc_sql_load_object (be, row, NULL, &guid, obj_guid_col_table); @@ -876,7 +856,7 @@ load_obj_guid (const GncSqlBackend* be, GncSqlRow* row) } static void -load_slot_for_list_item (GncSqlBackend* be, GncSqlRow* row, +load_slot_for_list_item (GncSqlBackend* be, GncSqlRow& row, QofCollection* coll) { slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID, NULL, FRAME, NULL, NULL }; @@ -884,7 +864,6 @@ load_slot_for_list_item (GncSqlBackend* be, GncSqlRow* row, QofInstance* inst; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (coll != NULL); guid = load_obj_guid (be, row); @@ -909,7 +888,6 @@ gnc_sql_slots_load_for_list (GncSqlBackend* be, GList* list) QofCollection* coll; GncSqlStatement* stmt; GString* sql; - GncSqlResult* result; gboolean single_item; g_return_if_fail (be != NULL); @@ -949,23 +927,14 @@ gnc_sql_slots_load_for_list (GncSqlBackend* be, GList* list) return; } (void)g_string_free (sql, TRUE); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) - { - GncSqlRow* row = gnc_sql_result_get_first_row (result); - - while (row != NULL) - { - load_slot_for_list_item (be, row, coll); - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - } + for (auto row : *result) + load_slot_for_list_item (be, row, coll); } static void -load_slot_for_book_object (GncSqlBackend* be, GncSqlRow* row, +load_slot_for_book_object (GncSqlBackend* be, GncSqlRow& row, BookLookupFn lookup_fn) { slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID, NULL, FRAME, NULL, NULL }; @@ -973,7 +942,6 @@ load_slot_for_book_object (GncSqlBackend* be, GncSqlRow* row, QofInstance* inst; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (lookup_fn != NULL); guid = load_obj_guid (be, row); @@ -1008,7 +976,6 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be, { gchar* sql; GncSqlStatement* stmt; - GncSqlResult* result; g_return_if_fail (be != NULL); @@ -1028,19 +995,10 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be, return; } g_free (sql); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) - { - GncSqlRow* row = gnc_sql_result_get_first_row (result); - - while (row != NULL) - { - load_slot_for_book_object (be, row, lookup_fn); - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - } + for (auto row : *result) + load_slot_for_book_object (be, row, lookup_fn); } /* ================================================================= */ diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index 90c439dc3d..3b3dd38b4f 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -200,12 +200,11 @@ tt_set_parent_guid (gpointer pObject, gpointer pValue) } static void -load_single_ttentry (GncSqlBackend* be, GncSqlRow* row, GncTaxTable* tt) +load_single_ttentry (GncSqlBackend* be, GncSqlRow& row, GncTaxTable* tt) { GncTaxTableEntry* e = gncTaxTableEntryCreate (); g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (tt != NULL); gnc_sql_load_object (be, row, GNC_ID_TAXTABLE, e, ttentries_col_table); @@ -215,7 +214,6 @@ load_single_ttentry (GncSqlBackend* be, GncSqlRow* row, GncTaxTable* tt) static void load_taxtable_entries (GncSqlBackend* be, GncTaxTable* tt) { - GncSqlResult* result; gchar guid_buf[GUID_ENCODING_LENGTH + 1]; GValue value; gchar* buf; @@ -232,31 +230,20 @@ load_taxtable_entries (GncSqlBackend* be, GncTaxTable* tt) TTENTRIES_TABLE_NAME, guid_buf); stmt = gnc_sql_connection_create_statement_from_sql (be->conn, buf); g_free (buf); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) - { - GncSqlRow* row; - - row = gnc_sql_result_get_first_row (result); - while (row != NULL) - { - load_single_ttentry (be, row, tt); - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - } + for (auto row : *result) + load_single_ttentry (be, row, tt); } static void -load_single_taxtable (GncSqlBackend* be, GncSqlRow* row, +load_single_taxtable (GncSqlBackend* be, GncSqlRow& row, GList** l_tt_needing_parents) { const GncGUID* guid; GncTaxTable* tt; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); guid = gnc_sql_load_guid (be, row); tt = gncTaxTableLookup (be->book, guid); @@ -297,47 +284,37 @@ static void load_all_taxtables (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; g_return_if_fail (be != NULL); /* First time, create the query */ stmt = gnc_sql_create_select_statement (be, TT_TABLE_NAME); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + GList* tt_needing_parents = NULL; + + for (auto row : *result) + load_single_taxtable (be, row, &tt_needing_parents); + + /* While there are items on the list of taxtables needing parents, + try to see if the parent has now been loaded. Theory says that if + items are removed from the front and added to the back if the + parent is still not available, then eventually, the list will + shrink to size 0. */ + if (tt_needing_parents != NULL) { - GncSqlRow* row; - GList* tt_needing_parents = NULL; + gboolean progress_made = TRUE; + GList* elem; - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + while (progress_made) { - load_single_taxtable (be, row, &tt_needing_parents); - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - - /* While there are items on the list of taxtables needing parents, - try to see if the parent has now been loaded. Theory says that if - items are removed from the front and added to the back if the - parent is still not available, then eventually, the list will - shrink to size 0. */ - if (tt_needing_parents != NULL) - { - gboolean progress_made = TRUE; - GList* elem; - - while (progress_made) + progress_made = FALSE; + for (elem = tt_needing_parents; elem != NULL; elem = g_list_next (elem)) { - progress_made = FALSE; - for (elem = tt_needing_parents; elem != NULL; elem = g_list_next (elem)) - { - taxtable_parent_guid_struct* s = (taxtable_parent_guid_struct*)elem->data; - tt_set_parent (s->tt, &s->guid); - tt_needing_parents = g_list_delete_link (tt_needing_parents, elem); - progress_made = TRUE; - } + taxtable_parent_guid_struct* s = (taxtable_parent_guid_struct*)elem->data; + tt_set_parent (s->tt, &s->guid); + tt_needing_parents = g_list_delete_link (tt_needing_parents, elem); + progress_made = TRUE; } } } @@ -505,7 +482,7 @@ write_taxtables (GncSqlBackend* be) /* ================================================================= */ static void -load_taxtable_guid (const GncSqlBackend* be, GncSqlRow* row, +load_taxtable_guid (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -513,12 +490,11 @@ load_taxtable_guid (const GncSqlBackend* be, GncSqlRow* row, GncTaxTable* taxtable = NULL; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); try { - auto val = row->get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (table_row.col_name); string_to_guid (val.c_str(), &guid); taxtable = gncTaxTableLookup (be->book, &guid); if (taxtable != NULL) diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index 3f5c360c63..e0fb09cad5 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -174,7 +174,7 @@ set_split_lot (gpointer pObject, gpointer pLot) } static Split* -load_single_split (GncSqlBackend* be, GncSqlRow* row) +load_single_split (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; GncGUID split_guid; @@ -182,7 +182,6 @@ load_single_split (GncSqlBackend* be, GncSqlRow* row) gboolean bad_guid = FALSE; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); if (guid == NULL) return NULL; @@ -225,7 +224,6 @@ static void load_splits_for_tx_list (GncSqlBackend* be, GList* list) { GString* sql; - GncSqlResult* result; g_return_if_fail (be != NULL); @@ -239,44 +237,34 @@ load_splits_for_tx_list (GncSqlBackend* be, GList* list) (void)g_string_append (sql, ")"); // Execute the query and load the splits - result = gnc_sql_execute_select_sql (be, sql->str); - if (result != NULL) + auto result = gnc_sql_execute_select_sql (be, sql->str); + GList* split_list = NULL; + for (auto row : *result) { - GList* split_list = NULL; - GncSqlRow* row; - - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + Split* s; + s = load_single_split (be, row); + if (s != NULL) { - Split* s; - s = load_single_split (be, row); - if (s != NULL) - { - split_list = g_list_prepend (split_list, s); - } - row = gnc_sql_result_get_next_row (result); + split_list = g_list_prepend (split_list, s); } + } - if (split_list != NULL) - { - gnc_sql_slots_load_for_list (be, split_list); - g_list_free (split_list); - } - - gnc_sql_result_dispose (result); + if (split_list != NULL) + { + gnc_sql_slots_load_for_list (be, split_list); + g_list_free (split_list); } (void)g_string_free (sql, TRUE); } static Transaction* -load_single_tx (GncSqlBackend* be, GncSqlRow* row) +load_single_tx (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; GncGUID tx_guid; Transaction* pTx; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); if (guid == NULL) return NULL; @@ -332,126 +320,120 @@ typedef struct static void query_transactions (GncSqlBackend* be, GncSqlStatement* stmt) { - GncSqlResult* result; - g_return_if_fail (be != NULL); g_return_if_fail (stmt != NULL); - result = gnc_sql_execute_select_statement (be, stmt); - if (result != NULL) + auto result = gnc_sql_execute_select_statement (be, stmt); + if (result->begin() == result->end()) + return; + + GList* tx_list = NULL; + GList* node; + Transaction* tx; +#if LOAD_TRANSACTIONS_AS_NEEDED + GSList* bal_list = NULL; + GSList* nextbal; + Account* root = gnc_book_get_root_account (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 (be->primary_book), + save_account_balances, + &bal_list); +#endif + + // Load the transactions + for (auto row : *result) { - GList* tx_list = NULL; - GList* node; - GncSqlRow* row; - Transaction* tx; -#if LOAD_TRANSACTIONS_AS_NEEDED - GSList* bal_list = NULL; - GSList* nextbal; - Account* root = gnc_book_get_root_account (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 (be->primary_book), - save_account_balances, - &bal_list); -#endif - - // Load the transactions - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + tx = load_single_tx (be, row); + if (tx != NULL) { - tx = load_single_tx (be, row); - if (tx != NULL) - { - tx_list = g_list_prepend (tx_list, tx); - xaccTransScrubPostedDate (tx); - } - row = gnc_sql_result_get_next_row (result); + xaccTransScrubPostedDate (tx); + tx_list = g_list_prepend (tx_list, tx); } - gnc_sql_result_dispose (result); - - // Load all splits and slots for the transactions - if (tx_list != NULL) - { - gnc_sql_slots_load_for_list (be, tx_list); - load_splits_for_tx_list (be, tx_list); - } - - // Commit all of the transactions - for (node = tx_list; node != NULL; node = node->next) - { - Transaction* pTx = GNC_TRANSACTION (node->data); - xaccTransCommitEdit (pTx); - } - g_list_free (tx_list); - -#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 (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 } + + // Load all splits and slots for the transactions + if (tx_list != NULL) + { + gnc_sql_slots_load_for_list (be, tx_list); + load_splits_for_tx_list (be, tx_list); + } + + // Commit all of the transactions + for (node = tx_list; node != NULL; node = node->next) + { + Transaction* pTx = GNC_TRANSACTION (node->data); + xaccTransCommitEdit (pTx); + } + g_list_free (tx_list); + +#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 (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 } /* ================================================================= */ @@ -1325,12 +1307,11 @@ static const EntryVec acct_balances_col_table }; G_GNUC_UNUSED static single_acct_balance_t* -load_single_acct_balances (const GncSqlBackend* be, GncSqlRow* row) +load_single_acct_balances (const GncSqlBackend* be, GncSqlRow& row) { single_acct_balance_t* bal = NULL; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); bal = static_cast (g_malloc (sizeof (single_acct_balance_t))); g_assert (bal != NULL); @@ -1345,7 +1326,6 @@ GSList* gnc_sql_get_account_balances_slist (GncSqlBackend* be) { #if LOAD_TRANSACTIONS_AS_NEEDED - GncSqlResult* result; GncSqlStatement* stmt; gchar* buf; GSList* bal_slist = NULL; @@ -1357,75 +1337,68 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be) stmt = gnc_sql_create_statement_from_sql (be, buf); g_assert (stmt != NULL); g_free (buf); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + acct_balances_t* bal = NULL; + + for (auto row : *result) { - GncSqlRow* row; - acct_balances_t* bal = NULL; + single_acct_balance_t* single_bal; - row = gnc_sql_result_get_first_row (result); - while (row != NULL) + // Get the next reconcile state balance and merge with other balances + single_bal = load_single_acct_balances (be, row); + if (single_bal != NULL) { - single_acct_balance_t* single_bal; - - // Get the next reconcile state balance and merge with other balances - single_bal = load_single_acct_balances (be, row); - if (single_bal != NULL) + if (bal != NULL && bal->acct != single_bal->acct) { - 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); + 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; } - row = gnc_sql_result_get_next_row (result); - } + if (bal == NULL) + { + bal = g_malloc ((gsize)sizeof (acct_balances_t)); + g_assert (bal != NULL); - // 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); + 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); } - gnc_sql_result_dispose (result); + } + + // 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; @@ -1436,7 +1409,7 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be) /* ----------------------------------------------------------------- */ static void -load_tx_guid (const GncSqlBackend* be, GncSqlRow* row, +load_tx_guid (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { @@ -1445,12 +1418,11 @@ load_tx_guid (const GncSqlBackend* be, GncSqlRow* row, const gchar* guid_str; g_return_if_fail (be != NULL); - g_return_if_fail (row != NULL); g_return_if_fail (pObject != NULL); try { - auto val = row->get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (table_row.col_name); (void)string_to_guid (val.c_str(), &guid); tx = xaccTransLookup (&guid, be->book); diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index 87daeab884..4e3563870a 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -77,13 +77,12 @@ static EntryVec col_table }); static GncVendor* -load_single_vendor (GncSqlBackend* be, GncSqlRow* row) +load_single_vendor (GncSqlBackend* be, GncSqlRow& row) { const GncGUID* guid; GncVendor* pVendor; g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (row != NULL, NULL); guid = gnc_sql_load_guid (be, row); pVendor = gncVendorLookup (be->book, guid); @@ -101,35 +100,25 @@ static void load_all_vendors (GncSqlBackend* be) { GncSqlStatement* stmt; - GncSqlResult* result; g_return_if_fail (be != NULL); stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - result = gnc_sql_execute_select_statement (be, stmt); + auto result = gnc_sql_execute_select_statement (be, stmt); gnc_sql_statement_dispose (stmt); - if (result != NULL) + GList* list = NULL; + + for (auto row : *result) { - GncSqlRow* row; - GList* list = NULL; + GncVendor* pVendor = load_single_vendor (be, row); + if (pVendor != NULL) + list = g_list_append (list, pVendor); + } - row = gnc_sql_result_get_first_row (result); - while (row != NULL) - { - GncVendor* pVendor = load_single_vendor (be, row); - if (pVendor != NULL) - { - list = g_list_append (list, pVendor); - } - row = gnc_sql_result_get_next_row (result); - } - gnc_sql_result_dispose (result); - - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (list != NULL) + { + gnc_sql_slots_load_for_list (be, list); + g_list_free (list); } } diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index b2feed203f..699119f271 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -410,7 +410,7 @@ test_gnc_sql_add_subtable_colnames_to_list (Fixture *fixture, gconstpointer pDat }*/ /* load_string static void -load_string (const GncSqlBackend* be, GncSqlRow* row, +load_string (const GncSqlBackend* be, GncSqlRow& row, const GncSqlColumnTableEntry& table_row)// 2 */ /* static void @@ -437,7 +437,7 @@ test_add_gvalue_string_to_slist (Fixture *fixture, gconstpointer pData) }*/ /* load_int static void -load_int (const GncSqlBackend* be, GncSqlRow* row,// 4 +load_int (const GncSqlBackend* be, GncSqlRow& row,// 4 */ /* static void test_load_int (Fixture *fixture, gconstpointer pData) @@ -461,7 +461,7 @@ test_add_gvalue_int_to_slist (Fixture *fixture, gconstpointer pData) }*/ /* load_boolean static void -load_boolean (const GncSqlBackend* be, GncSqlRow* row,// 2 +load_boolean (const GncSqlBackend* be, GncSqlRow& row,// 2 */ /* static void test_load_boolean (Fixture *fixture, gconstpointer pData) @@ -485,7 +485,7 @@ test_add_gvalue_boolean_to_slist (Fixture *fixture, gconstpointer pData) }*/ /* load_int64 static void -load_int64 (const GncSqlBackend* be, GncSqlRow* row,// 2 +load_int64 (const GncSqlBackend* be, GncSqlRow& row,// 2 */ /* static void test_load_int64 (Fixture *fixture, gconstpointer pData) @@ -509,7 +509,7 @@ test_add_gvalue_int64_to_slist (Fixture *fixture, gconstpointer pData) }*/ /* load_double static void -load_double (const GncSqlBackend* be, GncSqlRow* row,// 2 +load_double (const GncSqlBackend* be, GncSqlRow& row,// 2 */ /* static void test_load_double (Fixture *fixture, gconstpointer pData) @@ -533,7 +533,7 @@ test_add_gvalue_double_to_slist (Fixture *fixture, gconstpointer pData) }*/ /* load_guid static void -load_guid (const GncSqlBackend* be, GncSqlRow* row,// 3 +load_guid (const GncSqlBackend* be, GncSqlRow& row,// 3 */ /* static void test_load_guid (Fixture *fixture, gconstpointer pData) @@ -610,7 +610,7 @@ test_gnc_sql_convert_timespec_to_string () } /* load_timespec static void -load_timespec (const GncSqlBackend* be, GncSqlRow* row,// 2 +load_timespec (const GncSqlBackend* be, GncSqlRow& row,// 2 */ /* static void test_load_timespec (Fixture *fixture, gconstpointer pData) @@ -634,7 +634,7 @@ test_add_value_timespec_to_vec (Fixture *fixture, gconstpointer pData) }*/ /* load_date static void -load_date (const GncSqlBackend* be, GncSqlRow* row,// 2 +load_date (const GncSqlBackend* be, GncSqlRow& row,// 2 */ /* static void test_load_date (Fixture *fixture, gconstpointer pData) @@ -658,7 +658,7 @@ test_add_value_date_to_vec (Fixture *fixture, gconstpointer pData) }*/ /* load_numeric static void -load_numeric (const GncSqlBackend* be, GncSqlRow* row,// 2 +load_numeric (const GncSqlBackend* be, GncSqlRow& row,// 2 */ /* static void test_load_numeric (Fixture *fixture, gconstpointer pData) @@ -713,7 +713,7 @@ test__retrieve_guid_ (Fixture *fixture, gconstpointer pData) }*/ /* gnc_sql_load_guid const GncGUID* -gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow* row)// C: 15 in 14 */ +gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow& row)// C: 15 in 14 */ /* static void test_gnc_sql_load_guid (Fixture *fixture, gconstpointer pData) { @@ -721,7 +721,7 @@ test_gnc_sql_load_guid (Fixture *fixture, gconstpointer pData) // Not Used /* gnc_sql_load_tx_guid const GncGUID* -gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow* row)// 1 +gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow& row)// 1 */ /* static void test_gnc_sql_load_tx_guid (Fixture *fixture, gconstpointer pData) @@ -729,7 +729,7 @@ test_gnc_sql_load_tx_guid (Fixture *fixture, gconstpointer pData) }*/ /* gnc_sql_load_object void -gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow* row,// C: 29 in 19 */ +gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow& row,// C: 29 in 19 */ /* static void test_gnc_sql_load_object (Fixture *fixture, gconstpointer pData) { From 0d548da223cdb57d50b06ff88546551e27f8c9e3 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 9 May 2016 11:39:26 -0700 Subject: [PATCH 12/63] Create a new set_parameter template function to reduce repetition. --- src/backend/sql/gnc-account-sql.cpp | 18 +-- src/backend/sql/gnc-address-sql.cpp | 39 ++---- src/backend/sql/gnc-backend-sql.cpp | 166 ++++-------------------- src/backend/sql/gnc-backend-sql.h | 64 +++++++++ src/backend/sql/gnc-bill-term-sql.cpp | 17 +-- src/backend/sql/gnc-budget-sql.cpp | 18 +-- src/backend/sql/gnc-commodity-sql.cpp | 18 +-- src/backend/sql/gnc-invoice-sql.cpp | 17 +-- src/backend/sql/gnc-lots-sql.cpp | 18 +-- src/backend/sql/gnc-order-sql.cpp | 17 +-- src/backend/sql/gnc-owner-sql.cpp | 12 +- src/backend/sql/gnc-slots-sql.cpp | 12 +- src/backend/sql/gnc-tax-table-sql.cpp | 18 +-- src/backend/sql/gnc-transaction-sql.cpp | 16 +-- 14 files changed, 123 insertions(+), 327 deletions(-) diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index e12cb11ff6..56a371cd30 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -403,24 +403,10 @@ load_account_guid (const GncSqlBackend* be, GncSqlRow& row, auto val = row.get_string_at_col (table_row.col_name); (void)string_to_guid (val.c_str(), &guid); account = xaccAccountLookup (&guid, be->book); - if (account != NULL) - { - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, account, NULL); - qof_instance_decrease_editlevel (pObject); - } - else - { - g_return_if_fail (setter != NULL); - (*setter) (pObject, (const gpointer)account); - } - } + if (account != nullptr) + set_parameter (pObject, account, setter, table_row.gobj_param_name); else - { PWARN ("Account ref '%s' not found", val.c_str()); - } } catch (std::invalid_argument) {} } diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index f83964d362..713ea0431f 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -70,7 +70,6 @@ load_address (const GncSqlBackend* be, GncSqlRow& row, QofSetterFunc setter, gpointer pObject, const GncSqlColumnTableEntry& table_row) { - AddressSetterFunc a_setter = (AddressSetterFunc)setter; const gchar* s; @@ -87,40 +86,22 @@ load_address (const GncSqlBackend* be, GncSqlRow& row, { auto val = row.get_string_at_col (buf); g_free (buf); - if (subtable_row.gobj_param_name != NULL) - { - g_object_set (addr, subtable_row.gobj_param_name, - val.c_str(), NULL); - } - else - { - if (subtable_row.qof_param_name != NULL) - { - setter = qof_class_get_parameter_setter (GNC_ID_ADDRESS, - subtable_row.qof_param_name); - } - else - { - setter = subtable_row.setter; - } - (*setter) (addr, (const gpointer)val.c_str()); - } + auto sub_setter = subtable_row.setter; + auto pname = subtable_row.qof_param_name; + if (pname != nullptr) + sub_setter = qof_class_get_parameter_setter (GNC_ID_ADDRESS, + pname); + set_parameter (addr, val.c_str(), sub_setter, + subtable_row.gobj_param_name); } catch (std::invalid_argument) { return; } } - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, addr, NULL); - qof_instance_decrease_editlevel (pObject); - } - else - { - (*a_setter) (pObject, addr); - } + set_parameter (pObject, addr, + reinterpret_cast(setter), + table_row.gobj_param_name); } static void diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 605e3723f4..673034aaa5 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -1181,24 +1181,6 @@ gnc_sql_get_getter (QofIdTypeConst obj_name, return getter; } -template -void set_object_parameter(gpointer pObject, T item, QofSetterFunc setter, - const char* param) -{ - if (param != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, param, item, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - } - else - { - g_return_if_fail (setter != NULL); - (*setter) (pObject, (const gpointer)(item)); - } -} /* ----------------------------------------------------------------- */ static void @@ -1212,20 +1194,7 @@ load_string (const GncSqlBackend* be, GncSqlRow& row, try { auto s = row.get_string_at_col (table_row.col_name); - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, s.c_str(), NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - - } - else - { - g_return_if_fail (setter != NULL); - (*setter) (pObject, (const gpointer)s.c_str()); - } + set_parameter(pObject, s.c_str(), setter, table_row.gobj_param_name); } catch (std::invalid_argument) {} } @@ -1283,20 +1252,9 @@ load_int (const GncSqlBackend* be, GncSqlRow& row, g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); auto val = row.get_int_at_col(table_row.col_name); - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, val, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - } - else - { - g_return_if_fail (setter != NULL); - auto _setter = (IntSetterFunc)setter; - (*_setter) (pObject, val); - } + set_parameter(pObject, val, + reinterpret_cast(setter), + table_row.gobj_param_name); } static void @@ -1331,20 +1289,9 @@ load_boolean (const GncSqlBackend* be, GncSqlRow& row, g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); auto val = row.get_int_at_col (table_row.col_name); - if (table_row.gobj_param_name != nullptr) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, val, nullptr); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - } - else - { - g_return_if_fail (setter != NULL); - auto b_setter = (BooleanSetterFunc)setter; - (*b_setter) (pObject, (val != 0) ? TRUE : FALSE); - } + set_parameter(pObject, val, + reinterpret_cast(setter), + table_row.gobj_param_name); } static void @@ -1379,19 +1326,9 @@ load_int64 (const GncSqlBackend* be, GncSqlRow& row, setter != nullptr); auto val = row.get_int_at_col (table_row.col_name); - if (table_row.gobj_param_name != nullptr) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, val, nullptr); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - } - else - { - auto i64_setter = reinterpret_cast(setter); - (*i64_setter) (pObject, val); - } + set_parameter(pObject, val, + reinterpret_cast(setter), + table_row.gobj_param_name); } static void @@ -1445,19 +1382,7 @@ load_double (const GncSqlBackend* be, GncSqlRow& row, } } } - - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, val, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - } - else - { - (*setter) (pObject, (gpointer)&val); - } + set_parameter(pObject, val, setter, table_row.gobj_param_name); } static void @@ -1503,22 +1428,7 @@ load_guid (const GncSqlBackend* be, GncSqlRow& row, return; } (void)string_to_guid (str.c_str(), &guid); - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, &guid, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - } - else - { - g_return_if_fail (setter != NULL); - /* FIXME: The setter had damn well better dereference and copy its - * arg! - */ - (*setter) (pObject, (const gpointer)(&guid)); - } + set_parameter(pObject, &guid, setter, table_row.gobj_param_name); } static void @@ -1589,7 +1499,7 @@ gnc_sql_add_objectref_guid_col_info_to_list( const GncSqlBackend* be, /* ----------------------------------------------------------------- */ typedef Timespec (*TimespecAccessFunc) (const gpointer); -typedef void (*TimespecSetterFunc) (const gpointer, Timespec); +typedef void (*TimespecSetterFunc) (const gpointer, Timespec*); #define TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" #define TIMESPEC_COL_SIZE (4+2+2+2+2+2) @@ -1625,7 +1535,6 @@ load_timespec (const GncSqlBackend* be, GncSqlRow& row, { Timespec ts = {0, 0}; - TimespecSetterFunc ts_setter; gboolean isOK = FALSE; @@ -1633,7 +1542,6 @@ load_timespec (const GncSqlBackend* be, GncSqlRow& row, g_return_if_fail (table_row.gobj_param_name != nullptr || setter != nullptr); - ts_setter = (TimespecSetterFunc)setter; try { auto val = row.get_time64_at_col(table_row.col_name); @@ -1657,19 +1565,10 @@ load_timespec (const GncSqlBackend* be, GncSqlRow& row, return; } } - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, &ts, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_decrease_editlevel (QOF_INSTANCE (pObject)); - } - else - { - (*ts_setter) (pObject, ts); - } -} + set_parameter(pObject, &ts, + reinterpret_cast(setter), + table_row.gobj_param_name); + } static void add_timespec_col_info_to_list(const GncSqlBackend* be, @@ -1773,18 +1672,7 @@ load_date (const GncSqlBackend* be, GncSqlRow& row, return; } } - if (table_row.gobj_param_name != NULL) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, &date, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - } - else - { - (*setter) (pObject, &date); - } + set_parameter(pObject, &date, setter, table_row.gobj_param_name); } static void @@ -1827,7 +1715,7 @@ static GncSqlColumnTypeHandler date_handler }; /* ----------------------------------------------------------------- */ typedef gnc_numeric (*NumericGetterFunc) (const gpointer); -typedef void (*NumericSetterFunc) (gpointer, gnc_numeric); +typedef void (*NumericSetterFunc) (gpointer, gnc_numeric*); static const EntryVec numeric_col_table = { @@ -1859,19 +1747,9 @@ load_numeric (const GncSqlBackend* be, GncSqlRow& row, { return; } - if (table_row.gobj_param_name != nullptr) - { - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - g_object_set (pObject, table_row.gobj_param_name, &n, NULL); - if (QOF_IS_INSTANCE (pObject)) - qof_instance_increase_editlevel (QOF_INSTANCE (pObject)); - } - else - { - NumericSetterFunc n_setter = (NumericSetterFunc)setter; - (*n_setter) (pObject, n); - } + set_parameter(pObject, &n, + reinterpret_cast(setter), + table_row.gobj_param_name); } static void diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 7f5255b610..1b258748e8 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -491,6 +491,70 @@ typedef void (*GNC_SQL_ADD_VALUE_TO_VEC_FN) (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row, PairVec& vec); +/** + * Set an object property with a setter function. + * @param pObject void* to the object being set. + * @param item the value to be set in the property. + * @param setter The function to set the property. + * The void* is an obvious wart occasioned by the fact that we're using GLists + * to hold objects. As the rewrite progresses we'll replace that with another + * template paramter. + */ +template +void set_parameter(T object, P item, F& setter) +{ + (*setter)(object, item); +} + +template +void set_parameter(T object, P item, QofSetterFunc setter, std::true_type) +{ + (*setter)(object, (void*)item); +} + +template +void set_parameter(T object, P item, QofSetterFunc setter, std::false_type) +{ + (*setter)(object, (void*)(&item)); +} + +template +void set_parameter(T object, P item, QofSetterFunc setter) +{ + set_parameter(object, item, setter, std::is_pointer

()); +} + +/** + * Set an object property with g_object_set. + * @param pObject void* to the object being set. + * @param item the value to set in the property. + * @param property the property name. + * The void* is an obvious wart. So is g_object_set, partly because it's GObject + * but mostly because it works off of string comparisons. + */ +template +void set_parameter(T object, P item, const char* property) +{ + qof_instance_increase_editlevel(object); + g_object_set(object, property, item, nullptr); + qof_instance_decrease_editlevel(object); +}; + +/** + * Set an object property with either a g_object_set or a setter. + * + * See previous templates for the parameter meanings. This is clunky but fits in + * the current architecture for refactoring. + */ +template +void set_parameter(T object, P item, F setter, const char* property) +{ + if (property) + set_parameter(object, item, property); + else + set_parameter(object, item, setter); +} + /** * @struct GncSqlColumnTypeHandler * diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index 8370f41509..1b5cac62dd 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -353,23 +353,10 @@ load_billterm_guid (const GncSqlBackend* be, GncSqlRow& row, auto val = row.get_string_at_col (table_row.col_name); string_to_guid (val.c_str(), &guid); term = gncBillTermLookup (be->book, &guid); - if (term != NULL) - { - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, term, NULL); - qof_instance_decrease_editlevel (pObject); - } - else - { - (*setter) (pObject, (const gpointer)term); - } - } + if (term != nullptr) + set_parameter (pObject, term, setter, table_row.gobj_param_name); else - { PWARN ("Billterm ref '%s' not found", val.c_str()); - } } catch (std::invalid_argument) {} } diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index 18c7c869bd..1042154f2b 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -477,24 +477,10 @@ load_budget_guid (const GncSqlBackend* be, GncSqlRow& row, auto val = row.get_string_at_col (table_row.col_name); (void)string_to_guid (val.c_str(), &guid); budget = gnc_budget_lookup (&guid, be->book); - if (budget != NULL) - { - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, budget, NULL); - qof_instance_decrease_editlevel (pObject); - } - else - { - g_return_if_fail (setter != NULL); - (*setter) (pObject, (const gpointer)budget); - } - } + if (budget != nullptr) + set_parameter(pObject, budget, setter, table_row.gobj_param_name); else - { PWARN ("Budget ref '%s' not found", val.c_str()); - } } catch (std::invalid_argument) {} } diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index 8c3ccb6c99..7b040b1c9d 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -279,23 +279,11 @@ load_commodity_guid (const GncSqlBackend* be, GncSqlRow& row, auto val = row.get_string_at_col (table_row.col_name); (void)string_to_guid (val.c_str(), &guid); commodity = gnc_commodity_find_commodity_by_guid (&guid, be->book); - if (commodity != NULL) - { - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, commodity, NULL); - qof_instance_decrease_editlevel (pObject); - } - else if (setter != NULL) - { - (*setter) (pObject, (const gpointer)commodity); - } - } + if (commodity != nullptr) + set_parameter (pObject, commodity, setter, + table_row.gobj_param_name); else - { PWARN ("Commodity ref '%s' not found", val.c_str()); - } } catch (std::invalid_argument) {} } diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index 2f80683053..b6651b2a6b 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -290,23 +290,10 @@ load_invoice_guid (const GncSqlBackend* be, GncSqlRow& row, auto val = row.get_string_at_col (table_row.col_name); string_to_guid (val.c_str(), &guid); invoice = gncInvoiceLookup (be->book, &guid); - if (invoice != NULL) - { - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, invoice, NULL); - qof_instance_decrease_editlevel (pObject); - } - else - { - (*setter) (pObject, (const gpointer)invoice); - } - } + if (invoice != nullptr) + set_parameter (pObject, invoice, setter, table_row.gobj_param_name); else - { PWARN ("Invoice ref '%s' not found", val.c_str()); - } } catch (std::invalid_argument) {} } diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index 644c28e6d5..4b06c5160e 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -219,24 +219,10 @@ load_lot_guid (const GncSqlBackend* be, GncSqlRow& row, auto val = row.get_string_at_col (table_row.col_name); (void)string_to_guid (val.c_str(), &guid); lot = gnc_lot_lookup (&guid, be->book); - if (lot != NULL) - { - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, lot, NULL); - qof_instance_decrease_editlevel (pObject); - } - else - { - g_return_if_fail (setter != NULL); - (*setter) (pObject, (const gpointer)lot); - } - } + if (lot != nullptr) + set_parameter (pObject, lot, setter, table_row.gobj_param_name); else - { PWARN ("Lot ref '%s' not found", val.c_str()); - } } catch (std::invalid_argument) {} } diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index ad4685e85c..49a9307177 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -204,23 +204,10 @@ load_order_guid (const GncSqlBackend* be, GncSqlRow& row, auto val = row.get_string_at_col (table_row.col_name); string_to_guid (val.c_str(), &guid); order = gncOrderLookup (be->book, &guid); - if (order != NULL) - { - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, order, NULL); - qof_instance_decrease_editlevel (pObject); - } - else - { - (*setter) (pObject, (const gpointer)order); - } - } + if (order != nullptr) + set_parameter (pObject, order, setter, table_row.gobj_param_name); else - { PWARN ("Order ref '%s' not found", val.c_str()); - } } catch (std::invalid_argument) {} } diff --git a/src/backend/sql/gnc-owner-sql.cpp b/src/backend/sql/gnc-owner-sql.cpp index b1764fd5c7..acdb4f0d3f 100644 --- a/src/backend/sql/gnc-owner-sql.cpp +++ b/src/backend/sql/gnc-owner-sql.cpp @@ -151,17 +151,7 @@ load_owner (const GncSqlBackend* be, GncSqlRow& row, default: PWARN ("Invalid owner type: %d\n", type); } - - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, &owner, NULL); - qof_instance_decrease_editlevel (pObject); - } - else - { - (*setter) (pObject, &owner); - } + set_parameter (pObject, &owner, setter, table_row.gobj_param_name); } static void diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index 2f3581b06a..0fb5e5451e 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -83,11 +83,11 @@ static void set_string_val (gpointer pObject, gpointer pValue); static gpointer get_double_val (gpointer pObject); static void set_double_val (gpointer pObject, gpointer pValue); static Timespec get_timespec_val (gpointer pObject); -static void set_timespec_val (gpointer pObject, Timespec ts); +static void set_timespec_val (gpointer pObject, Timespec *ts); static gpointer get_guid_val (gpointer pObject); static void set_guid_val (gpointer pObject, gpointer pValue); static gnc_numeric get_numeric_val (gpointer pObject); -static void set_numeric_val (gpointer pObject, gnc_numeric value); +static void set_numeric_val (gpointer pObject, gnc_numeric *value); static GDate* get_gdate_val (gpointer pObject); static void set_gdate_val (gpointer pObject, GDate* value); static slot_info_t* slot_info_copy (slot_info_t* pInfo, GncGUID* guid); @@ -436,7 +436,7 @@ get_timespec_val (gpointer pObject) } static void -set_timespec_val (gpointer pObject, Timespec ts) +set_timespec_val (gpointer pObject, Timespec *ts) { slot_info_t* pInfo = (slot_info_t*)pObject; KvpValue* value = NULL; @@ -444,7 +444,7 @@ set_timespec_val (gpointer pObject, Timespec ts) g_return_if_fail (pObject != NULL); if (pInfo->value_type != KvpValue::Type::TIMESPEC) return; - value = new KvpValue {ts}; + value = new KvpValue {*ts}; set_slot_from_value (pInfo, value); } @@ -553,7 +553,7 @@ get_numeric_val (gpointer pObject) } static void -set_numeric_val (gpointer pObject, gnc_numeric value) +set_numeric_val (gpointer pObject, gnc_numeric *value) { slot_info_t* pInfo = (slot_info_t*)pObject; KvpValue* pValue = NULL; @@ -561,7 +561,7 @@ set_numeric_val (gpointer pObject, gnc_numeric value) g_return_if_fail (pObject != NULL); if (pInfo->value_type != KvpValue::Type::NUMERIC) return; - set_slot_from_value (pInfo, new KvpValue {value}); + set_slot_from_value (pInfo, new KvpValue {*value}); } static GDate* diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index 3b3dd38b4f..39225cd544 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -497,23 +497,11 @@ load_taxtable_guid (const GncSqlBackend* be, GncSqlRow& row, auto val = row.get_string_at_col (table_row.col_name); string_to_guid (val.c_str(), &guid); taxtable = gncTaxTableLookup (be->book, &guid); - if (taxtable != NULL) - { - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, taxtable, NULL); - qof_instance_decrease_editlevel (pObject); - } - else - { - (*setter) (pObject, (const gpointer)taxtable); - } - } + if (taxtable != nullptr) + set_parameter (pObject, taxtable, setter, + table_row.gobj_param_name); else - { PWARN ("Taxtable ref '%s' not found", val.c_str()); - } } catch (std::invalid_argument) {} } diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index e0fb09cad5..a4d44d1fe4 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -1440,20 +1440,8 @@ load_tx_guid (const GncSqlBackend* be, GncSqlRow& row, tx = xaccTransLookup (&guid, be->book); } - if (tx != NULL) - { - if (table_row.gobj_param_name != NULL) - { - qof_instance_increase_editlevel (pObject); - g_object_set (pObject, table_row.gobj_param_name, tx, NULL); - qof_instance_decrease_editlevel (pObject); - } - else - { - g_return_if_fail (setter != NULL); - (*setter) (pObject, (const gpointer)tx); - } - } + if (tx != nullptr) + set_parameter (pObject, tx, setter, table_row.gobj_param_name); } catch (std::invalid_argument) {} } From a716636e00d7db11eb68bec6b070977f569b92d0 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 9 May 2016 17:40:45 -0700 Subject: [PATCH 13/63] Convert GncSqlStatement to a virtual class. Implemented by GncDbiSqlStatement. Use class function semantics. --- src/backend/dbi/gnc-backend-dbi.cpp | 89 ++++++++---------------- src/backend/sql/gnc-account-sql.cpp | 2 +- src/backend/sql/gnc-backend-sql.cpp | 74 ++++++++++---------- src/backend/sql/gnc-backend-sql.h | 22 ++---- src/backend/sql/gnc-bill-term-sql.cpp | 2 +- src/backend/sql/gnc-book-sql.cpp | 2 +- src/backend/sql/gnc-budget-sql.cpp | 4 +- src/backend/sql/gnc-commodity-sql.cpp | 2 +- src/backend/sql/gnc-customer-sql.cpp | 2 +- src/backend/sql/gnc-employee-sql.cpp | 2 +- src/backend/sql/gnc-entry-sql.cpp | 2 +- src/backend/sql/gnc-invoice-sql.cpp | 2 +- src/backend/sql/gnc-job-sql.cpp | 2 +- src/backend/sql/gnc-lots-sql.cpp | 2 +- src/backend/sql/gnc-order-sql.cpp | 2 +- src/backend/sql/gnc-price-sql.cpp | 2 +- src/backend/sql/gnc-recurrence-sql.cpp | 2 +- src/backend/sql/gnc-schedxaction-sql.cpp | 2 +- src/backend/sql/gnc-slots-sql.cpp | 8 +-- src/backend/sql/gnc-tax-table-sql.cpp | 4 +- src/backend/sql/gnc-transaction-sql.cpp | 8 +-- src/backend/sql/gnc-vendor-sql.cpp | 2 +- 22 files changed, 98 insertions(+), 141 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index b6a3aaafd4..3b6ead6867 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -2304,68 +2304,41 @@ GncDbiSqlResult::size() const noexcept } /* --------------------------------------------------------- */ -typedef struct +class GncDbiSqlStatement : public GncSqlStatement { - GncSqlStatement base; +public: + GncDbiSqlStatement(GncSqlConnection* conn, const std::string&& sql) : + m_conn{conn}, m_sql {sql} {} + ~GncDbiSqlStatement() {} + const char* to_sql() const override; + void add_where_cond(QofIdTypeConst, const PairVec&) override; - GString* sql; - GncSqlConnection* conn; -} GncDbiSqlStatement; +private: + GncSqlConnection* m_conn; + std::string m_sql; +}; -static void -stmt_dispose (GncSqlStatement* stmt) + +const char* +GncDbiSqlStatement::to_sql() const { - GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt; - - if (dbi_stmt->sql != NULL) - { - (void)g_string_free (dbi_stmt->sql, TRUE); - } - g_free (stmt); + return m_sql.c_str(); } -static gchar* -stmt_to_sql (GncSqlStatement* stmt) +void +GncDbiSqlStatement::add_where_cond(QofIdTypeConst type_name, + const PairVec& col_values) { - GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt; - - return dbi_stmt->sql->str; -} - -static void -stmt_add_where_cond(GncSqlStatement* stmt, QofIdTypeConst type_name, - gpointer obj, const PairVec& col_values) -{ - GncDbiSqlStatement* dbi_stmt = reinterpret_cast(stmt); - std::ostringstream sql; - sql << " WHERE "; + m_sql += " WHERE "; for (auto colpair : col_values) { if (colpair != *col_values.begin()) - sql << " AND "; - sql << colpair.first << " = " << - gnc_sql_connection_quote_string (dbi_stmt->conn, - colpair.second.c_str()); + m_sql += " AND "; + m_sql += colpair.first + " = " + + gnc_sql_connection_quote_string (m_conn, colpair.second.c_str()); } - (void)g_string_append (dbi_stmt->sql, sql.str().c_str()); } -static GncSqlStatement* -create_dbi_statement (GncSqlConnection* conn, const gchar* sql) -{ - GncDbiSqlStatement* stmt; - - stmt = g_new0 (GncDbiSqlStatement, 1); - g_assert (stmt != NULL); - - stmt->base.dispose = stmt_dispose; - stmt->base.toSql = stmt_to_sql; - stmt->base.addWhereCond = stmt_add_where_cond; - stmt->sql = g_string_new (sql); - stmt->conn = conn; - - return (GncSqlStatement*)stmt; -} /* --------------------------------------------------------- */ static void conn_dispose (GncSqlConnection* conn) @@ -2379,19 +2352,18 @@ static GncSqlResultPtr conn_execute_select_statement (GncSqlConnection* conn, GncSqlStatement* stmt) { GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt; dbi_result result; - DEBUG ("SQL: %s\n", dbi_stmt->sql->str); + DEBUG ("SQL: %s\n", stmt->to_sql()); gnc_push_locale (LC_NUMERIC, "C"); do { gnc_dbi_init_error (dbi_conn); - result = dbi_conn_query (dbi_conn->conn, dbi_stmt->sql->str); + result = dbi_conn_query (dbi_conn->conn, stmt->to_sql()); } while (dbi_conn->retry); if (result == nullptr) - PERR ("Error executing SQL %s\n", dbi_stmt->sql->str); + PERR ("Error executing SQL %s\n", stmt->to_sql()); gnc_pop_locale (LC_NUMERIC); return GncSqlResultPtr(new GncDbiSqlResult (dbi_conn, result)); } @@ -2401,21 +2373,20 @@ conn_execute_nonselect_statement (GncSqlConnection* conn, GncSqlStatement* stmt) { GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - GncDbiSqlStatement* dbi_stmt = (GncDbiSqlStatement*)stmt; dbi_result result; gint num_rows; gint status; - DEBUG ("SQL: %s\n", dbi_stmt->sql->str); + DEBUG ("SQL: %s\n", stmt->to_sql()); do { gnc_dbi_init_error (dbi_conn); - result = dbi_conn_query (dbi_conn->conn, dbi_stmt->sql->str); + result = dbi_conn_query (dbi_conn->conn, stmt->to_sql()); } while (dbi_conn->retry); if (result == NULL) { - PERR ("Error executing SQL %s\n", dbi_stmt->sql->str); + PERR ("Error executing SQL %s\n", stmt->to_sql()); return -1; } num_rows = (gint)dbi_result_get_numrows_affected (result); @@ -2431,9 +2402,7 @@ conn_execute_nonselect_statement (GncSqlConnection* conn, static GncSqlStatement* conn_create_statement_from_sql (GncSqlConnection* conn, const gchar* sql) { - //GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - - return create_dbi_statement (conn, sql); + return new GncDbiSqlStatement (conn, sql); } static gboolean diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index 56a371cd30..c1079df3ca 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -213,7 +213,7 @@ load_all_accounts (GncSqlBackend* be) return; } auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; for (auto row : *result) load_single_account (be, row, &l_accounts_needing_parents); diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 673034aaa5..a35c845705 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -248,10 +248,10 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) for (auto type : fixed_load_order) { auto entry = std::find_if(backend_registry.begin(), - backend_registry.end(), - [type](const OBEEntry& entry){ + backend_registry.end(), + [type](const OBEEntry& entry){ return type == std::get<0>(entry); - }); + }); auto obe = std::get<1>(*entry); if (entry != backend_registry.end() && obe->initial_load != nullptr) @@ -263,10 +263,10 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) for (auto type : other_load_order) { auto entry = std::find_if(backend_registry.begin(), - backend_registry.end(), - [type](const OBEEntry& entry){ + backend_registry.end(), + [type](const OBEEntry& entry){ return type == std::get<0>(entry); - }); + }); if (entry == backend_registry.end()) continue; auto obe = std::get<1>(*entry); @@ -522,7 +522,7 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) be->is_pristine_db = FALSE; /* Mark the session as clean -- though it shouldn't ever get - * marked dirty with this backend + * marked dirty with this backend */ qof_book_mark_session_saved (book); } @@ -601,7 +601,7 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) return; } /* During initial load where objects are being created, don't commit - anything, but do mark the object as clean. */ + anything, but do mark the object as clean. */ if (be->loading) { qof_instance_mark_clean (inst); @@ -868,7 +868,7 @@ gnc_sql_compile_query (QofBackend* pBEnd, QofQuery* pQuery) searchObj = qof_query_get_search_for (pQuery); pQueryInfo = static_cast ( - g_malloc (sizeof (gnc_sql_query_info))); + g_malloc (sizeof (gnc_sql_query_info))); g_assert (pQueryInfo != NULL); pQueryInfo->pCompiledQuery = NULL; pQueryInfo->searchObj = searchObj; @@ -1229,7 +1229,7 @@ add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, stream.str())); return; } - } +} static GncSqlColumnTypeHandler string_handler = @@ -1477,7 +1477,7 @@ gnc_sql_add_objectref_guid_to_vec (const GncSqlBackend* be, PairVec& vec) { auto inst = get_row_value_from_object(obj_name, pObject, - table_row); + table_row); const GncGUID* guid = nullptr; if (inst != nullptr) guid = qof_instance_get_guid (inst); @@ -1491,8 +1491,8 @@ gnc_sql_add_objectref_guid_to_vec (const GncSqlBackend* be, void gnc_sql_add_objectref_guid_col_info_to_list( const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& info_vec) + const GncSqlColumnTableEntry& table_row, + ColVec& info_vec) { add_guid_col_info_to_list(be, table_row, info_vec); } @@ -1568,7 +1568,7 @@ load_timespec (const GncSqlBackend* be, GncSqlRow& row, set_parameter(pObject, &ts, reinterpret_cast(setter), table_row.gobj_param_name); - } +} static void add_timespec_col_info_to_list(const GncSqlBackend* be, @@ -1693,7 +1693,7 @@ add_date_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, PairVec& vec) { GDate *date = get_row_value_from_object(obj_name, pObject, - table_row); + table_row); if (date && g_date_valid (date)) { std::ostringstream buf; @@ -1764,8 +1764,8 @@ add_numeric_col_info_to_list(const GncSqlBackend* be, gchar* buf = g_strdup_printf("%s_%s", table_row.col_name, subtable_row.col_name); GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false, - table_row.flags & COL_PKEY, - table_row.flags & COL_NNUL); + table_row.flags & COL_PKEY, + table_row.flags & COL_NNUL); vec.emplace_back(std::move(info)); } } @@ -1819,7 +1819,7 @@ static GncSqlColumnTypeHandler numeric_handler = { load_numeric, add_numeric_col_info_to_list, add_numeric_to_vec - }; +}; /* ================================================================= */ static GHashTable* g_columnTypeHash = NULL; @@ -1893,7 +1893,7 @@ _retrieve_guid_ (gpointer pObject, gpointer pValue) static EntryVec guid_table { { "guid", CT_GUID, 0, 0, NULL, NULL, NULL, _retrieve_guid_ }, -}; + }; const GncGUID* gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow& row) @@ -1910,8 +1910,8 @@ gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow& row) // Table to retrieve just the guid static EntryVec tx_guid_table { - { "tx_guid", CT_GUID, 0, 0, NULL, NULL, NULL, _retrieve_guid_ }, - }; + { "tx_guid", CT_GUID, 0, 0, NULL, NULL, NULL, _retrieve_guid_ }, + }; const GncGUID* @@ -2004,7 +2004,7 @@ gnc_sql_execute_select_statement (GncSqlBackend* be, GncSqlStatement* stmt) auto result = gnc_sql_connection_execute_select_statement (be->conn, stmt); if (result == NULL) { - PERR ("SQL error: %s\n", gnc_sql_statement_to_sql (stmt)); + PERR ("SQL error: %s\n", stmt->to_sql()); if (!qof_backend_check_error(&be->be)) qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); } @@ -2045,7 +2045,7 @@ gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) return NULL; } auto result = gnc_sql_connection_execute_select_statement (be->conn, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; if (result == NULL) { PERR ("SQL error: %s\n", sql); @@ -2071,7 +2071,7 @@ gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql) return -1; } result = gnc_sql_connection_execute_nonselect_statement (be->conn, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; return result; } @@ -2127,11 +2127,9 @@ gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, pHandler = get_handler (table[0]); g_assert (pHandler != NULL); pHandler->add_value_to_vec_fn (be, obj_name, pObject, table[0], values); - PairVec col_values {values[0]}; - gnc_sql_statement_add_where_cond (stmt, obj_name, pObject, col_values); - + stmt->add_where_cond(obj_name, values); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; if (result != NULL) { auto retval = result->size() > 0; @@ -2179,7 +2177,7 @@ gnc_sql_do_db_operation (GncSqlBackend* be, result = gnc_sql_connection_execute_nonselect_statement (be->conn, stmt); if (result == -1) { - PERR ("SQL error: %s\n", gnc_sql_statement_to_sql (stmt)); + PERR ("SQL error: %s\n", stmt->to_sql()); if (!qof_backend_check_error(&be->be)) qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); } @@ -2187,7 +2185,7 @@ gnc_sql_do_db_operation (GncSqlBackend* be, { ok = TRUE; } - gnc_sql_statement_dispose (stmt); + delete stmt; } return ok; @@ -2285,7 +2283,7 @@ build_update_statement (GncSqlBackend* be, * value, i.e. the guid of the object. */ values.erase(values.begin() + 1, values.end()); - gnc_sql_statement_add_where_cond(stmt, obj_name, pObject, values); + stmt->add_where_cond(obj_name, values); return stmt; } @@ -2314,7 +2312,7 @@ build_delete_statement (GncSqlBackend* be, PairVec values; pHandler->add_value_to_vec_fn (be, obj_name, pObject, table[0], values); PairVec col_values{values[0]}; - gnc_sql_statement_add_where_cond (stmt, obj_name, pObject, col_values); + stmt->add_where_cond (obj_name, col_values); return stmt; } @@ -2508,7 +2506,7 @@ static EntryVec version_table { { TABLE_COL_NAME, CT_STRING, MAX_TABLE_NAME_LEN, COL_PKEY | COL_NNUL }, { VERSION_COL_NAME, CT_INT, 0, COL_NNUL }, -}; + }; /** * Sees if the version table exists, and if it does, loads the info into @@ -2686,10 +2684,10 @@ GncSqlRow::operator++() } /* -GncSqlResult* -GncSqlRow::operator*() -{ - return m_iter->operator*(); -} + GncSqlResult* + GncSqlRow::operator*() + { + return m_iter->operator*(); + } */ /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 1b258748e8..b8d2ac30fe 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -138,30 +138,20 @@ void gnc_sql_commit_edit (GncSqlBackend* qbe, QofInstance* inst); /** */ -typedef struct GncSqlStatement GncSqlStatement; class GncSqlResult; //using GncSqlResultPtr = std::unique_ptr; using GncSqlResultPtr = GncSqlResult*; /** - *@struct GncSqlStatement - * - * Struct which represents an SQL statement. SQL backends must provide a - * structure which implements all of the functions. + * SQL statement provider. */ -struct GncSqlStatement +class GncSqlStatement { - void (*dispose) (GncSqlStatement*); - gchar* (*toSql) (GncSqlStatement*); - void (*addWhereCond) (GncSqlStatement*, QofIdTypeConst, gpointer, - const PairVec&); +public: + virtual ~GncSqlStatement() {} + virtual const char* to_sql() const = 0; + virtual void add_where_cond (QofIdTypeConst, const PairVec&) = 0; }; -#define gnc_sql_statement_dispose(STMT) \ - (STMT)->dispose(STMT) -#define gnc_sql_statement_to_sql(STMT) \ - (STMT)->toSql(STMT) -#define gnc_sql_statement_add_where_cond(STMT,TYPENAME,OBJ,COL_VAL_PAIR) \ - (STMT)->addWhereCond(STMT, TYPENAME, OBJ, COL_VAL_PAIR) /** * @struct GncSqlConnection diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index 1b5cac62dd..44dcb4173e 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -225,7 +225,7 @@ load_all_billterms (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; GList* list = NULL; GList* l_billterms_needing_parents = NULL; diff --git a/src/backend/sql/gnc-book-sql.cpp b/src/backend/sql/gnc-book-sql.cpp index 627651d5b8..0dabb429d5 100644 --- a/src/backend/sql/gnc-book-sql.cpp +++ b/src/backend/sql/gnc-book-sql.cpp @@ -169,7 +169,7 @@ load_all_books (GncSqlBackend* be) if (stmt != NULL) { auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; auto row = result->begin(); /* If there are no rows, try committing the book; unset diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index 1042154f2b..dad49c2133 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -206,7 +206,7 @@ load_budget_amounts (GncSqlBackend* be, GncBudget* budget) if (stmt != NULL) { auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; budget_amount_info_t info = { budget, NULL, 0 }; for (auto row : *result) @@ -329,7 +329,7 @@ load_all_budgets (GncSqlBackend* be) if (stmt != NULL) { auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; for (auto row : *result) { auto b = load_single_budget (be, row); diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index 7b040b1c9d..331ffddc34 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -135,7 +135,7 @@ load_all_commodities (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, COMMODITIES_TABLE); if (stmt == NULL) return; auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; for (auto row : *result) { diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index 86db2ac715..631917d57d 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -115,7 +115,7 @@ load_all_customers (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; GList* list = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index d71030c85c..c0ed579951 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -102,7 +102,7 @@ load_all_employees (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; GList* list = NULL; diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index a44057cf66..fbf84a2691 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -178,7 +178,7 @@ load_all_entries (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; GList* list = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index b6651b2a6b..819538c7a2 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -122,7 +122,7 @@ load_all_invoices (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; GList* list = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index 0f4b9c7c7c..932f51cba4 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -98,7 +98,7 @@ load_all_jobs (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; GList* list = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index 4b06c5160e..59fd24116d 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -122,7 +122,7 @@ load_all_lots (GncSqlBackend* be) if (stmt != NULL) { auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; if (result->begin () == nullptr) return; for (auto row : *result) diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index 49a9307177..8367797e74 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -94,7 +94,7 @@ load_all_orders (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; GList* list = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-price-sql.cpp b/src/backend/sql/gnc-price-sql.cpp index 41c6c68258..39aa55303a 100644 --- a/src/backend/sql/gnc-price-sql.cpp +++ b/src/backend/sql/gnc-price-sql.cpp @@ -97,7 +97,7 @@ load_all_prices (GncSqlBackend* be) if (stmt != NULL) { auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; if (result->begin() == result->end()) return; diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index 8cd1a4711d..d1ecc76272 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -313,7 +313,7 @@ gnc_sql_set_recurrences_from_db (GncSqlBackend* be, const GncGUID* guid) stmt = gnc_sql_connection_create_statement_from_sql (be->conn, buf); g_free (buf); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; return result; } diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index 722744b25a..cbabe60ed9 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -110,7 +110,7 @@ load_all_sxes (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, SCHEDXACTION_TABLE); if (stmt == NULL) return; auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; SchedXactions* sxes; GList* list = NULL; sxes = gnc_book_get_schedxactions (be->book); diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index 0fb5e5451e..4d0bb693f4 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -740,7 +740,7 @@ gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid) if (stmt != NULL) { auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; for (auto row : *result) { try @@ -837,7 +837,7 @@ slots_load_info (slot_info_t* pInfo) if (stmt != NULL) { auto result = gnc_sql_execute_select_statement (pInfo->be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; for (auto row : *result) load_slot (pInfo, row); } @@ -928,7 +928,7 @@ gnc_sql_slots_load_for_list (GncSqlBackend* be, GList* list) } (void)g_string_free (sql, TRUE); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; for (auto row : *result) load_slot_for_list_item (be, row, coll); } @@ -996,7 +996,7 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be, } g_free (sql); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; for (auto row : *result) load_slot_for_book_object (be, row, lookup_fn); } diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index 39225cd544..4cf03ad4d2 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -231,7 +231,7 @@ load_taxtable_entries (GncSqlBackend* be, GncTaxTable* tt) stmt = gnc_sql_connection_create_statement_from_sql (be->conn, buf); g_free (buf); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; for (auto row : *result) load_single_ttentry (be, row, tt); } @@ -290,7 +290,7 @@ load_all_taxtables (GncSqlBackend* be) /* First time, create the query */ stmt = gnc_sql_create_select_statement (be, TT_TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; GList* tt_needing_parents = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index a4d44d1fe4..055561554f 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -810,7 +810,7 @@ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* be, if (stmt != NULL) { query_transactions (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; } } @@ -833,7 +833,7 @@ void gnc_sql_transaction_load_all_tx (GncSqlBackend* be) if (stmt != NULL) { query_transactions (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; } } @@ -1242,7 +1242,7 @@ run_split_query (GncSqlBackend* be, gpointer pQuery) { query_transactions (be, query_info->stmt); query_info->has_been_run = TRUE; - gnc_sql_statement_dispose (query_info->stmt); + delete query_info->stmt; query_info->stmt = NULL; } } @@ -1338,7 +1338,7 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be) g_assert (stmt != NULL); g_free (buf); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; acct_balances_t* bal = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index 4e3563870a..f4625894d6 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -105,7 +105,7 @@ load_all_vendors (GncSqlBackend* be) stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - gnc_sql_statement_dispose (stmt); + delete stmt; GList* list = NULL; for (auto row : *result) From e20c17b6425b086f4a1bf33aca9bad0729193c77 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 31 May 2016 17:41:39 -0700 Subject: [PATCH 14/63] Change the object type string defines to an enum. Because doing unnecessary string compares is dumb. --- src/backend/sql/gnc-address-sql.h | 2 -- src/backend/sql/gnc-backend-sql.cpp | 13 +++----- src/backend/sql/gnc-backend-sql.h | 50 +++++++++++++++++------------ src/backend/sql/gnc-bill-term-sql.h | 2 -- src/backend/sql/gnc-invoice-sql.h | 2 -- src/backend/sql/gnc-order-sql.h | 2 -- src/backend/sql/gnc-owner-sql.h | 2 -- src/backend/sql/gnc-tax-table-sql.h | 2 -- 8 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/backend/sql/gnc-address-sql.h b/src/backend/sql/gnc-address-sql.h index 51e60343f9..fcc4d47c8b 100644 --- a/src/backend/sql/gnc-address-sql.h +++ b/src/backend/sql/gnc-address-sql.h @@ -29,8 +29,6 @@ #ifndef GNC_ADDRESS_SQL_H #define GNC_ADDRESS_SQL_H -#define CT_ADDRESS "address" - void gnc_address_sql_initialize (void); #endif /* GNC_ADDRESS_SQL_H */ diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index a35c845705..cdd5d53d44 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -1825,20 +1825,19 @@ static GncSqlColumnTypeHandler numeric_handler static GHashTable* g_columnTypeHash = NULL; void -gnc_sql_register_col_type_handler (const gchar* colType, +gnc_sql_register_col_type_handler (const GncSqlObjectType colType, const GncSqlColumnTypeHandler* handler) { - g_return_if_fail (colType != NULL); g_return_if_fail (handler != NULL); if (g_columnTypeHash == NULL) { - g_columnTypeHash = g_hash_table_new (g_str_hash, g_str_equal); + g_columnTypeHash = g_hash_table_new (g_direct_hash, g_direct_equal); g_assert (g_columnTypeHash != NULL); } - DEBUG ("Col type %s registered\n", colType); - g_hash_table_insert (g_columnTypeHash, (gpointer)colType, (gpointer)handler); + DEBUG ("Col type %d registered\n", colType); + g_hash_table_insert (g_columnTypeHash, GINT_TO_POINTER(colType), (gpointer)handler); } static GncSqlColumnTypeHandler* @@ -1846,12 +1845,10 @@ get_handler (const GncSqlColumnTableEntry& table_row) { GncSqlColumnTypeHandler* pHandler; - g_return_val_if_fail (table_row.col_type != NULL, NULL); - if (g_columnTypeHash != NULL) { pHandler = static_cast( - g_hash_table_lookup (g_columnTypeHash, table_row.col_type)); + g_hash_table_lookup (g_columnTypeHash, GINT_TO_POINTER(table_row.col_type))); g_assert (pHandler != NULL); } else diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index b8d2ac30fe..817ee00545 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -341,20 +341,29 @@ typedef enum // Type for conversion of db row to object. -#define CT_STRING "ct_string" -#define CT_GUID "ct_guid" -#define CT_INT "ct_int" -#define CT_INT64 "ct_int64" -#define CT_TIMESPEC "ct_timespec" -#define CT_GDATE "ct_gdate" -#define CT_NUMERIC "ct_numeric" -#define CT_DOUBLE "ct_double" -#define CT_BOOLEAN "ct_boolean" -#define CT_ACCOUNTREF "ct_accountref" -#define CT_BUDGETREF "ct_budgetref" -#define CT_COMMODITYREF "ct_commodityref" -#define CT_LOTREF "ct_lotref" -#define CT_TXREF "ct_txref" +enum GncSqlObjectType +{ + CT_STRING, + CT_GUID, + CT_INT, + CT_INT64, + CT_TIMESPEC, + CT_GDATE, + CT_NUMERIC, + CT_DOUBLE, + CT_BOOLEAN, + CT_ACCOUNTREF, + CT_BUDGETREF, + CT_COMMODITYREF, + CT_LOTREF, + CT_TXREF, + CT_ADDRESS, + CT_BILLTERMREF, + CT_INVOICEREF, + CT_ORDERREF, + CT_OWNERREF, + CT_TAXTABLEREF +}; enum ColumnFlags : int { @@ -382,7 +391,8 @@ enum ColumnFlags : int */ struct GncSqlColumnTableEntry { - GncSqlColumnTableEntry (const char* name, const char*type, unsigned int s, + GncSqlColumnTableEntry (const char* name, const GncSqlObjectType type, + unsigned int s, ColumnFlags f, const char* gobj_name = nullptr, const char* qof_name = nullptr, QofAccessFunc get = nullptr, @@ -390,7 +400,8 @@ struct GncSqlColumnTableEntry col_name{name}, col_type{type}, size{s}, flags{f}, gobj_param_name{gobj_name}, qof_param_name{qof_name}, getter{get}, setter{set} {} - GncSqlColumnTableEntry (const char* name, const char*type, unsigned int s, + GncSqlColumnTableEntry (const char* name, const GncSqlObjectType type, + unsigned int s, int f, const char* gobj_name = nullptr, const char* qof_name = nullptr, QofAccessFunc get = nullptr, @@ -400,7 +411,7 @@ struct GncSqlColumnTableEntry gobj_param_name{gobj_name}, qof_param_name{qof_name}, getter{get}, setter{set} {} const char* col_name; /**< Column name */ - const char* col_type; /**< Column type */ + const GncSqlObjectType col_type; /**< Column type */ unsigned int size; /**< Column size in bytes, for string columns */ ColumnFlags flags; /**< Column flags */ const char* gobj_param_name; /**< If non-null, g_object param name */ @@ -412,8 +423,7 @@ struct GncSqlColumnTableEntry inline bool operator==(const GncSqlColumnTableEntry& l, const GncSqlColumnTableEntry& r) { - return strcmp(l.col_name, r.col_name) == 0 && - strcmp(l.col_type, r.col_type) == 0; + return strcmp(l.col_name, r.col_name) == 0 && l.col_type == r.col_type; } inline bool operator!=(const GncSqlColumnTableEntry& l, @@ -764,7 +774,7 @@ GncSqlStatement* gnc_sql_create_select_statement (GncSqlBackend* be, * @param colType Column type * @param handler Column handler */ -void gnc_sql_register_col_type_handler (const gchar* colType, +void gnc_sql_register_col_type_handler (const GncSqlObjectType colType, const GncSqlColumnTypeHandler* handler); /** diff --git a/src/backend/sql/gnc-bill-term-sql.h b/src/backend/sql/gnc-bill-term-sql.h index 86722f832c..442e1cf1ea 100644 --- a/src/backend/sql/gnc-bill-term-sql.h +++ b/src/backend/sql/gnc-bill-term-sql.h @@ -35,8 +35,6 @@ extern "C" { #include "qof.h" } -#define CT_BILLTERMREF "billterm" - void gnc_billterm_sql_initialize (void); gboolean gnc_sql_save_billterm (GncSqlBackend* be, QofInstance* inst); diff --git a/src/backend/sql/gnc-invoice-sql.h b/src/backend/sql/gnc-invoice-sql.h index 1329bdf8a8..1e29e55fb8 100644 --- a/src/backend/sql/gnc-invoice-sql.h +++ b/src/backend/sql/gnc-invoice-sql.h @@ -30,8 +30,6 @@ #ifndef GNC_INVOICE_SQL_H #define GNC_INVOICE_SQL_H -#define CT_INVOICEREF "invoice" - void gnc_invoice_sql_initialize (void); #endif /* GNC_INVOICE_SQL_H */ diff --git a/src/backend/sql/gnc-order-sql.h b/src/backend/sql/gnc-order-sql.h index 110643060d..1ce2bd0e35 100644 --- a/src/backend/sql/gnc-order-sql.h +++ b/src/backend/sql/gnc-order-sql.h @@ -30,8 +30,6 @@ #ifndef GNC_ORDER_SQL_H #define GNC_ORDER_SQL_H -#define CT_ORDERREF "order" - void gnc_order_sql_initialize (void); #endif /* GNC_ORDER_SQL_H */ diff --git a/src/backend/sql/gnc-owner-sql.h b/src/backend/sql/gnc-owner-sql.h index 52bbd90981..2c50115089 100644 --- a/src/backend/sql/gnc-owner-sql.h +++ b/src/backend/sql/gnc-owner-sql.h @@ -29,8 +29,6 @@ #ifndef GNC_OWNER_SQL_H #define GNC_OWNER_SQL_H -#define CT_OWNERREF "owner" - void gnc_owner_sql_initialize (void); #endif /* GNC_OWNER_SQL_H */ diff --git a/src/backend/sql/gnc-tax-table-sql.h b/src/backend/sql/gnc-tax-table-sql.h index c99afba470..c6ea13a7b5 100644 --- a/src/backend/sql/gnc-tax-table-sql.h +++ b/src/backend/sql/gnc-tax-table-sql.h @@ -30,8 +30,6 @@ #ifndef GNC_TAXTABLE_SQL_H #define GNC_TAXTABLE_SQL_H -#define CT_TAXTABLEREF "tax-table" - void gnc_taxtable_sql_initialize (void); #endif /* GNC_TAXTABLE_SQL_H */ From 6e84ccac75f7009e2864c56d165cfcd29a39aa2e Mon Sep 17 00:00:00 2001 From: John Ralls Date: Thu, 9 Jun 2016 14:23:42 -0700 Subject: [PATCH 15/63] Move GncSqlColumnTypeHandler functions into GncSqlColumnTableEntry. Unfortunately a rather massive change. Gets rid of GncSqlColumnTypeHandler and its hideous run-time registry by making the handler functions members of GncSqlColumnTableEntry. GncSqlColumnTableEntry becomes an abstract super- class with a templatized subclass GncSqlColumnTableEntryImpl whose template parameter is the GncSqlObjectType that's also the GncSqlColumnTableEntryImpl's m_col_type member. That member is a candidate for future removal as it's not necessary. An explicit specialization is provided for each GncSqlObjectType and that's a candidate for future code-shrinkage as there's still a fair amount of duplication in spite of adding several helper template functions to absorb most of the meat. The abstract GncSqlColumnTableEntry class is motivated by the need to have an iterable container which in turn requires runtime polymorphism. This can probably be replaced with a variadic-template pseudo-container. The two major benefits of this change are that it gets rid of one more set of macro functions and provides vtable dispatch that has only one level of indirection instead of the cumbersome string-hash-table-lookup to find the handler followed by invoking the handler's function. The two header files are removed because they exposed only the initialization function which in turn only registered the respective GncSqlColumnTypeHandler. --- src/backend/dbi/gnc-backend-dbi.cpp | 4 +- src/backend/sql/CMakeLists.txt | 2 - src/backend/sql/Makefile.am | 2 - src/backend/sql/gnc-account-sql.cpp | 91 +-- src/backend/sql/gnc-address-sql.cpp | 113 ++-- src/backend/sql/gnc-address-sql.h | 34 -- src/backend/sql/gnc-backend-sql.cpp | 693 ++++++++++------------- src/backend/sql/gnc-backend-sql.h | 366 +++++++----- src/backend/sql/gnc-bill-term-sql.cpp | 99 ++-- src/backend/sql/gnc-book-sql.cpp | 17 +- src/backend/sql/gnc-budget-sql.cpp | 95 ++-- src/backend/sql/gnc-commodity-sql.cpp | 90 +-- src/backend/sql/gnc-customer-sql.cpp | 53 +- src/backend/sql/gnc-employee-sql.cpp | 28 +- src/backend/sql/gnc-entry-sql.cpp | 105 ++-- src/backend/sql/gnc-invoice-sql.cpp | 117 ++-- src/backend/sql/gnc-job-sql.cpp | 25 +- src/backend/sql/gnc-lots-sql.cpp | 62 +- src/backend/sql/gnc-order-sql.cpp | 73 +-- src/backend/sql/gnc-owner-sql.cpp | 84 +-- src/backend/sql/gnc-owner-sql.h | 34 -- src/backend/sql/gnc-price-sql.cpp | 17 +- src/backend/sql/gnc-recurrence-sql.cpp | 55 +- src/backend/sql/gnc-schedxaction-sql.cpp | 36 +- src/backend/sql/gnc-slots-sql.cpp | 86 ++- src/backend/sql/gnc-tax-table-sql.cpp | 107 ++-- src/backend/sql/gnc-transaction-sql.cpp | 119 ++-- src/backend/sql/gnc-vendor-sql.cpp | 27 +- 28 files changed, 1238 insertions(+), 1396 deletions(-) delete mode 100644 src/backend/sql/gnc-address-sql.h delete mode 100644 src/backend/sql/gnc-owner-sql.h diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 3b6ead6867..2d70f7a9fe 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -2544,13 +2544,13 @@ create_index_ddl (GncSqlConnection* conn, const char* index_name, ddl = g_string_new (""); g_string_printf (ddl, "CREATE INDEX %s ON %s (", index_name, table_name); - for (auto const& table_row : col_table) + for (auto const table_row : col_table) { if (table_row != *col_table.begin()) { (void)g_string_append (ddl, ", "); } - g_string_append_printf (ddl, "%s", table_row.col_name); + g_string_append_printf (ddl, "%s", table_row->name()); } (void)g_string_append (ddl, ")"); diff --git a/src/backend/sql/CMakeLists.txt b/src/backend/sql/CMakeLists.txt index b50d7fe93e..6c4ece55ea 100644 --- a/src/backend/sql/CMakeLists.txt +++ b/src/backend/sql/CMakeLists.txt @@ -29,7 +29,6 @@ SET (backend_sql_SOURCES ) SET (backend_sql_noinst_HEADERS gnc-account-sql.h - gnc-address-sql.h gnc-backend-sql.h gnc-bill-term-sql.h gnc-book-sql.h @@ -42,7 +41,6 @@ SET (backend_sql_noinst_HEADERS gnc-job-sql.h gnc-lots-sql.h gnc-order-sql.h - gnc-owner-sql.h gnc-price-sql.h gnc-recurrence-sql.h gnc-schedxaction-sql.h diff --git a/src/backend/sql/Makefile.am b/src/backend/sql/Makefile.am index 20463e2a2f..6f0dabee14 100644 --- a/src/backend/sql/Makefile.am +++ b/src/backend/sql/Makefile.am @@ -47,7 +47,6 @@ libgnc_backend_sql_la_SOURCES = \ noinst_HEADERS = \ gnc-account-sql.h \ - gnc-address-sql.h \ gnc-backend-sql.h \ gnc-bill-term-sql.h \ gnc-book-sql.h \ @@ -60,7 +59,6 @@ noinst_HEADERS = \ gnc-job-sql.h \ gnc-lots-sql.h \ gnc-order-sql.h \ - gnc-owner-sql.h \ gnc-price-sql.h \ gnc-recurrence-sql.h \ gnc-schedxaction-sql.h \ diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index c1079df3ca..a9f3149dc6 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -64,24 +64,31 @@ static void set_parent_guid (gpointer pObject, gpointer pValue); static const EntryVec col_table { - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "name", CT_STRING, ACCOUNT_MAX_NAME_LEN, COL_NNUL, "name" }, - { "account_type", CT_STRING, ACCOUNT_MAX_TYPE_LEN, COL_NNUL, NULL, ACCOUNT_TYPE_ }, - { "commodity_guid", CT_COMMODITYREF, 0, 0, "commodity" }, - { "commodity_scu", CT_INT, 0, COL_NNUL, "commodity-scu" }, - { "non_std_scu", CT_BOOLEAN, 0, COL_NNUL, "non-std-scu" }, - { - "parent_guid", CT_GUID, 0, 0, NULL, NULL, - (QofAccessFunc)get_parent, set_parent - }, - { "code", CT_STRING, ACCOUNT_MAX_CODE_LEN, 0, "code" }, - { "description", CT_STRING, ACCOUNT_MAX_DESCRIPTION_LEN, 0, "description" }, - { "hidden", CT_BOOLEAN, 0, 0, "hidden" }, - { "placeholder", CT_BOOLEAN, 0, 0, "placeholder" }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid" ), + gnc_sql_make_table_entry( + "name", ACCOUNT_MAX_NAME_LEN, COL_NNUL, "name"), + gnc_sql_make_table_entry("account_type", ACCOUNT_MAX_TYPE_LEN, + COL_NNUL, ACCOUNT_TYPE_, true), + gnc_sql_make_table_entry( + "commodity_guid", 0, 0, "commodity"), + gnc_sql_make_table_entry( + "commodity_scu", 0, COL_NNUL, "commodity-scu"), + gnc_sql_make_table_entry( + "non_std_scu", 0, COL_NNUL, "non-std-scu"), + gnc_sql_make_table_entry("parent_guid", 0, 0, + (QofAccessFunc)get_parent, + (QofSetterFunc)set_parent), + gnc_sql_make_table_entry( + "code", ACCOUNT_MAX_CODE_LEN, 0, "code"), + gnc_sql_make_table_entry( + "description", ACCOUNT_MAX_DESCRIPTION_LEN, 0, "description"), + gnc_sql_make_table_entry("hidden", 0, 0, "hidden"), + gnc_sql_make_table_entry("placeholder", 0, 0, "placeholder"), }; static EntryVec parent_col_table ({ - { "parent_guid", CT_GUID, 0, 0, NULL, NULL, NULL, set_parent_guid }, + gnc_sql_make_table_entry( + "parent_guid", 0, 0, nullptr, (QofSetterFunc)set_parent_guid), }); typedef struct @@ -386,36 +393,34 @@ gnc_sql_save_account (GncSqlBackend* be, QofInstance* inst) } /* ================================================================= */ -static void -load_account_guid (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) + +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { - const GValue* val; - GncGUID guid; - Account* account = NULL; - - g_return_if_fail (be != NULL); - g_return_if_fail (pObject != NULL); - - try - { - auto val = row.get_string_at_col (table_row.col_name); - (void)string_to_guid (val.c_str(), &guid); - account = xaccAccountLookup (&guid, be->book); - if (account != nullptr) - set_parameter (pObject, account, setter, table_row.gobj_param_name); - else - PWARN ("Account ref '%s' not found", val.c_str()); - } - catch (std::invalid_argument) {} + load_from_guid_ref(row, obj_name, pObject, + [be](GncGUID* g){ + return xaccAccountLookup(g, be->book); + }); } -static GncSqlColumnTypeHandler account_guid_handler -= { load_account_guid, - gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_objectref_guid_to_vec - }; +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept +{ + add_objectref_guid_to_table(be, vec); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept +{ + add_objectref_guid_to_query(be, obj_name, pObject, vec); +} /* ================================================================= */ void gnc_sql_init_account_handler (void) @@ -434,7 +439,5 @@ gnc_sql_init_account_handler (void) }; gnc_sql_register_backend(&be_data); - - gnc_sql_register_col_type_handler (CT_ACCOUNTREF, &account_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index 713ea0431f..c60ff7223d 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -40,7 +40,6 @@ extern "C" #include "gncAddress.h" } #include "gnc-backend-sql.h" -#include "gnc-address-sql.h" G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN; @@ -52,23 +51,32 @@ G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN; static EntryVec col_table ({ - { "name", CT_STRING, ADDRESS_MAX_NAME_LEN, COL_NNUL, "name" }, - { "addr1", CT_STRING, ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr1" }, - { "addr2", CT_STRING, ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr2" }, - { "addr3", CT_STRING, ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr3" }, - { "addr4", CT_STRING, ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr4" }, - { "phone", CT_STRING, ADDRESS_MAX_PHONE_LEN, COL_NNUL, "phone" }, - { "fax", CT_STRING, ADDRESS_MAX_FAX_LEN, COL_NNUL, "fax" }, - { "email", CT_STRING, ADDRESS_MAX_EMAIL_LEN, COL_NNUL, "email" }, + std::make_shared>( + "name", CT_STRING, ADDRESS_MAX_NAME_LEN, COL_NNUL, "name"), + gnc_sql_make_table_entry( + "addr1", ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr1"), + gnc_sql_make_table_entry( + "addr2", ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr2"), + gnc_sql_make_table_entry( + "addr3", ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr3"), + gnc_sql_make_table_entry( + "addr4", ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr4"), + gnc_sql_make_table_entry( + "phone", ADDRESS_MAX_PHONE_LEN, COL_NNUL, "phone"), + gnc_sql_make_table_entry( + "fax", ADDRESS_MAX_FAX_LEN, COL_NNUL, "fax" ), + gnc_sql_make_table_entry( + "email", ADDRESS_MAX_EMAIL_LEN, COL_NNUL, "email"), }); typedef void (*AddressSetterFunc) (gpointer, GncAddress*); typedef GncAddress* (*AddressGetterFunc) (const gpointer); -static void -load_address (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { const gchar* s; @@ -80,19 +88,13 @@ load_address (const GncSqlBackend* be, GncSqlRow& row, for (auto const& subtable_row : col_table) { - auto buf = g_strdup_printf ("%s_%s", table_row.col_name, - subtable_row.col_name); + auto buf = std::string{m_col_name} + "_" + subtable_row->m_col_name; try { - auto val = row.get_string_at_col (buf); - g_free (buf); - auto sub_setter = subtable_row.setter; - auto pname = subtable_row.qof_param_name; - if (pname != nullptr) - sub_setter = qof_class_get_parameter_setter (GNC_ID_ADDRESS, - pname); + auto val = row.get_string_at_col (buf.c_str()); + auto sub_setter = subtable_row->get_setter(GNC_ID_ADDRESS); set_parameter (addr, val.c_str(), sub_setter, - subtable_row.gobj_param_name); + subtable_row->m_gobj_param_name); } catch (std::invalid_argument) { @@ -100,65 +102,44 @@ load_address (const GncSqlBackend* be, GncSqlRow& row, } } set_parameter (pObject, addr, - reinterpret_cast(setter), - table_row.gobj_param_name); + reinterpret_cast(get_setter(obj_name)), + m_gobj_param_name); } -static void -add_address_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { - GncSqlColumnInfo* info; - gchar* buf; - g_return_if_fail (be != NULL); - for (auto const& subtable_row : col_table) { - buf = g_strdup_printf ("%s_%s", table_row.col_name, subtable_row.col_name); - - GncSqlColumnInfo info(buf, BCT_STRING, subtable_row.size, true, false, - table_row.flags & COL_PKEY, - table_row.flags & COL_NNUL); + auto buf = std::string{m_col_name} + "_" + subtable_row->m_col_name; + GncSqlColumnInfo info(buf.c_str(), BCT_STRING, subtable_row->m_size, + true, false, m_flags & COL_PKEY, m_flags & COL_NNUL); vec.emplace_back(std::move(info)); } } -static void -add_value_address_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec) +/* char is unusual in that we get a pointer but don't deref it to pass + * it to operator<<(). + */ +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { - auto addr = get_row_value_from_object(obj_name, pObject, - table_row); + auto addr{get_row_value_from_object(obj_name, pObject)}; + if (addr == nullptr) return; - - if (addr == nullptr) - return; for (auto const& subtable_row : col_table) { - auto s = get_row_value_from_object(GNC_ID_ADDRESS, addr, - subtable_row); + auto s = subtable_row->get_row_value_from_object(GNC_ID_ADDRESS, + addr); if (s == nullptr) continue; - std::ostringstream buf; - buf << table_row.col_name << "_" << subtable_row.col_name; - vec.emplace_back(make_pair(buf.str(), std::string{s})); + auto buf = std::string{m_col_name} + "_" + subtable_row->m_col_name; + vec.emplace_back(make_pair(buf, std::string{s})); } } - -static GncSqlColumnTypeHandler address_handler -= { load_address, - add_address_col_info_to_list, - add_value_address_to_vec - }; - -/* ================================================================= */ -void -gnc_address_sql_initialize (void) -{ - gnc_sql_register_col_type_handler (CT_ADDRESS, &address_handler); -} /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-address-sql.h b/src/backend/sql/gnc-address-sql.h deleted file mode 100644 index fcc4d47c8b..0000000000 --- a/src/backend/sql/gnc-address-sql.h +++ /dev/null @@ -1,34 +0,0 @@ -/* gnc-address-sql.h -- Address SQL header - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, contact: - * - * Free Software Foundation Voice: +1-617-542-5942 - * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 - * Boston, MA 02110-1301, USA gnu@gnu.org - */ - -/** @file gnc-address-sql.h - * @brief load and save address data to SQL - * @author Copyright (c) 2007-2008 Phil Longstaff - * - * This file implements the top-level QofBackend API for saving/ - * restoring data to/from an SQL database - */ - -#ifndef GNC_ADDRESS_SQL_H -#define GNC_ADDRESS_SQL_H - -void gnc_address_sql_initialize (void); - -#endif /* GNC_ADDRESS_SQL_H */ diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index cdd5d53d44..d03ca2983c 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -72,7 +72,6 @@ extern "C" #include "gnc-slots-sql.h" #include "gnc-transaction-sql.h" -#include "gnc-address-sql.h" #include "gnc-bill-term-sql.h" #include "gnc-customer-sql.h" #include "gnc-employee-sql.h" @@ -80,14 +79,12 @@ extern "C" #include "gnc-invoice-sql.h" #include "gnc-job-sql.h" #include "gnc-order-sql.h" -#include "gnc-owner-sql.h" #include "gnc-tax-table-sql.h" #include "gnc-vendor-sql.h" static void gnc_sql_init_object_handlers (void); static void update_progress (GncSqlBackend* be); static void finish_progress (GncSqlBackend* be); -static void register_standard_col_type_handlers (void); static gboolean reset_version_info (GncSqlBackend* be); static GncSqlStatement* build_insert_statement (GncSqlBackend* be, const gchar* table_name, @@ -154,7 +151,6 @@ gnc_sql_init(GncSqlBackend* be) if (!initialized) { - register_standard_col_type_handlers (); gnc_sql_init_object_handlers (); initialized = TRUE; } @@ -1066,7 +1062,6 @@ static void business_core_sql_init (void) { /* Initialize our pointers into the backend subsystem */ - gnc_address_sql_initialize (); gnc_billterm_sql_initialize (); gnc_customer_sql_initialize (); gnc_employee_sql_initialize (); @@ -1074,7 +1069,6 @@ business_core_sql_init (void) gnc_invoice_sql_initialize (); gnc_job_sql_initialize (); gnc_order_sql_initialize (); - gnc_owner_sql_initialize (); gnc_taxtable_sql_initialize (); gnc_vendor_sql_initialize (); @@ -1157,224 +1151,261 @@ set_autoinc_id (void* object, void* item) } QofAccessFunc -gnc_sql_get_getter (QofIdTypeConst obj_name, - const GncSqlColumnTableEntry& table_row) +GncSqlColumnTableEntry::get_getter (QofIdTypeConst obj_name) const noexcept { QofAccessFunc getter; g_return_val_if_fail (obj_name != NULL, NULL); - if (table_row.flags & COL_AUTOINC) + if (m_flags & COL_AUTOINC) { getter = get_autoinc_id; } - else if (table_row.qof_param_name != NULL) + else if (m_qof_param_name != NULL) { - getter = qof_class_get_parameter_getter (obj_name, - table_row.qof_param_name); + getter = qof_class_get_parameter_getter (obj_name, m_qof_param_name); } else { - getter = table_row.getter; + getter = m_getter; } return getter; } +QofSetterFunc +GncSqlColumnTableEntry::get_setter(QofIdTypeConst obj_name) const noexcept +{ + QofSetterFunc setter = nullptr; + if (m_flags & COL_AUTOINC) + { + setter = set_autoinc_id; + } + else if (m_qof_param_name != nullptr) + { + g_assert (obj_name != NULL); + setter = qof_class_get_parameter_setter (obj_name, m_qof_param_name); + } + else + { + setter = m_setter; + } + return setter; +} + +void +GncSqlColumnTableEntry::add_objectref_guid_to_query (const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept +{ + auto inst = get_row_value_from_object(obj_name, pObject); + if (inst == nullptr) return; + auto guid = qof_instance_get_guid (inst); + if (guid != nullptr) + vec.emplace_back (std::make_pair (std::string{m_col_name}, + std::string{guid_to_string(guid)})); +} + +void +GncSqlColumnTableEntry::add_objectref_guid_to_table (const GncSqlBackend* be, + ColVec& vec) const noexcept +{ + g_return_if_fail (be != NULL); + + GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE}; + vec.emplace_back(std::move(info)); +} + /* ----------------------------------------------------------------- */ -static void -load_string (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); + g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL); try { - auto s = row.get_string_at_col (table_row.col_name); - set_parameter(pObject, s.c_str(), setter, table_row.gobj_param_name); + auto s = row.get_string_at_col (m_col_name); + set_parameter(pObject, s.c_str(), get_setter(obj_name), m_gobj_param_name); } catch (std::invalid_argument) {} } -static void -add_string_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { g_return_if_fail (be != NULL); - GncSqlColumnInfo info{table_row, BCT_STRING, table_row.size, TRUE}; + GncSqlColumnInfo info{*this, BCT_STRING, m_size, TRUE}; vec.emplace_back(std::move(info)); } /* char is unusual in that we get a pointer but don't deref it to pass * it to operator<<(). */ -template <> void -add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { - auto s = get_row_value_from_object(obj_name, pObject, table_row); + auto s = get_row_value_from_object(obj_name, pObject); if (s != nullptr) { std::ostringstream stream; stream << s; - vec.emplace_back (std::make_pair (std::string{table_row.col_name}, - stream.str())); + vec.emplace_back (std::make_pair (std::string{m_col_name}, stream.str())); return; } } -static GncSqlColumnTypeHandler string_handler -= -{ - load_string, - add_string_col_info_to_list, - add_value_to_vec -}; /* ----------------------------------------------------------------- */ typedef gint (*IntAccessFunc) (const gpointer); typedef void (*IntSetterFunc) (const gpointer, gint); -static void -load_int (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); + g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL); - auto val = row.get_int_at_col(table_row.col_name); + auto val = row.get_int_at_col(m_col_name); set_parameter(pObject, val, - reinterpret_cast(setter), - table_row.gobj_param_name); + reinterpret_cast(get_setter(obj_name)), m_gobj_param_name); } -static void -add_int_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { g_return_if_fail (be != NULL); - GncSqlColumnInfo info{table_row, BCT_INT, 0, FALSE}; + GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE}; vec.emplace_back(std::move(info)); } -static GncSqlColumnTypeHandler int_handler -= +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { - load_int, - add_int_col_info_to_list, - add_value_to_vec -}; + add_value_to_vec(be, obj_name, pObject, vec); +} /* ----------------------------------------------------------------- */ typedef gboolean (*BooleanAccessFunc) (const gpointer); typedef void (*BooleanSetterFunc) (const gpointer, gboolean); -static void -load_boolean (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) + const noexcept { g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row.gobj_param_name != NULL || setter != NULL); + g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL); - auto val = row.get_int_at_col (table_row.col_name); + auto val = row.get_int_at_col (m_col_name); set_parameter(pObject, val, - reinterpret_cast(setter), - table_row.gobj_param_name); + reinterpret_cast(get_setter(obj_name)), + m_gobj_param_name); } -static void -add_boolean_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { g_return_if_fail (be != NULL); - GncSqlColumnInfo info{table_row, BCT_INT, 0, FALSE}; + GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE}; vec.emplace_back(std::move(info)); } -static GncSqlColumnTypeHandler boolean_handler -= +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { - load_boolean, - add_boolean_col_info_to_list, - add_value_to_vec -}; + add_value_to_vec(be, obj_name, pObject, vec); +} /* ----------------------------------------------------------------- */ typedef gint64 (*Int64AccessFunc) (const gpointer); typedef void (*Int64SetterFunc) (const gpointer, gint64); -static void -load_int64 (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) + const noexcept { - g_return_if_fail (table_row.gobj_param_name != nullptr || - setter != nullptr); + g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr); - auto val = row.get_int_at_col (table_row.col_name); + auto val = row.get_int_at_col (m_col_name); set_parameter(pObject, val, - reinterpret_cast(setter), - table_row.gobj_param_name); + reinterpret_cast(get_setter(obj_name)), + m_gobj_param_name); } -static void -add_int64_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { g_return_if_fail (be != NULL); - GncSqlColumnInfo info{table_row, BCT_INT64, 0, FALSE}; + GncSqlColumnInfo info{*this, BCT_INT64, 0, FALSE}; vec.emplace_back(std::move(info)); } -static GncSqlColumnTypeHandler int64_handler -= +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { - load_int64, - add_int64_col_info_to_list, - add_value_to_vec -}; + add_value_to_vec(be, obj_name, pObject, vec); +} /* ----------------------------------------------------------------- */ -static void -load_double (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) + const noexcept { g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row.gobj_param_name != nullptr || - setter != nullptr); + g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr); double val; try { - val = static_cast(row.get_int_at_col(table_row.col_name)); + val = static_cast(row.get_int_at_col(m_col_name)); } catch (std::invalid_argument) { try { - val = static_cast(row.get_float_at_col(table_row.col_name)); + val = static_cast(row.get_float_at_col(m_col_name)); } catch (std::invalid_argument) { try { - val = row.get_double_at_col(table_row.col_name); + val = row.get_double_at_col(m_col_name); } catch (std::invalid_argument) { @@ -1382,121 +1413,83 @@ load_double (const GncSqlBackend* be, GncSqlRow& row, } } } - set_parameter(pObject, val, setter, table_row.gobj_param_name); + set_parameter(pObject, val, get_setter(obj_name), m_gobj_param_name); } -static void -add_double_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { g_return_if_fail (be != NULL); - GncSqlColumnInfo info{table_row, BCT_DOUBLE, 0, FALSE}; + GncSqlColumnInfo info{*this, BCT_DOUBLE, 0, FALSE}; vec.emplace_back(std::move(info)); } -static GncSqlColumnTypeHandler double_handler -= +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { - load_double, - add_double_col_info_to_list, - add_value_to_vec -}; + add_value_to_vec(be, obj_name, pObject, vec); +} + /* ----------------------------------------------------------------- */ -static void -load_guid (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) + const noexcept { GncGUID guid; const GncGUID* pGuid; g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row.gobj_param_name != nullptr || - setter != nullptr); + g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr); std::string str; try { - str = row.get_string_at_col(table_row.col_name); + str = row.get_string_at_col(m_col_name); } catch (std::invalid_argument) { return; } (void)string_to_guid (str.c_str(), &guid); - set_parameter(pObject, &guid, setter, table_row.gobj_param_name); + set_parameter(pObject, &guid, get_setter(obj_name), m_gobj_param_name); } -static void -add_guid_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { g_return_if_fail (be != NULL); - GncSqlColumnInfo info{table_row, BCT_STRING, GUID_ENCODING_LENGTH, FALSE}; + GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE}; vec.emplace_back(std::move(info)); } -template <> void -add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { - auto s = get_row_value_from_object(obj_name, pObject, table_row); + auto s = get_row_value_from_object(obj_name, pObject); if (s != nullptr) { - std::ostringstream stream; - stream << guid_to_string(s); - vec.emplace_back (std::make_pair (std::string{table_row.col_name}, - stream.str())); + + vec.emplace_back (std::make_pair (std::string{m_col_name}, + std::string{guid_to_string(s)})); return; } } - -static GncSqlColumnTypeHandler guid_handler -= -{ - load_guid, - add_guid_col_info_to_list, - add_value_to_vec -}; -/* ----------------------------------------------------------------- */ - -void -gnc_sql_add_objectref_guid_to_vec (const GncSqlBackend* be, - QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec) -{ - auto inst = get_row_value_from_object(obj_name, pObject, - table_row); - const GncGUID* guid = nullptr; - if (inst != nullptr) - guid = qof_instance_get_guid (inst); - if (guid != nullptr) - { - vec.emplace_back (std::make_pair (std::string{table_row.col_name}, - std::string{guid_to_string(guid)})); - return; - } -} - -void -gnc_sql_add_objectref_guid_col_info_to_list( const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& info_vec) -{ - add_guid_col_info_to_list(be, table_row, info_vec); -} - /* ----------------------------------------------------------------- */ typedef Timespec (*TimespecAccessFunc) (const gpointer); typedef void (*TimespecSetterFunc) (const gpointer, Timespec*); @@ -1528,10 +1521,11 @@ gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, Timespec ts) } #pragma GCC diagnostic warning "-Wformat-nonliteral" -static void -load_timespec (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { Timespec ts = {0, 0}; @@ -1539,19 +1533,18 @@ load_timespec (const GncSqlBackend* be, GncSqlRow& row, g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row.gobj_param_name != nullptr || - setter != nullptr); + g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr); try { - auto val = row.get_time64_at_col(table_row.col_name); + auto val = row.get_time64_at_col(m_col_name); timespecFromTime64 (&ts, val); } catch (std::invalid_argument) { try { - auto val = row.get_string_at_col(table_row.col_name); + auto val = row.get_string_at_col(m_col_name); auto s = val.c_str(); auto buf = g_strdup_printf ("%c%c%c%c-%c%c-%c%c %c%c:%c%c:%c%c", s[0], s[1], s[2], s[3], s[4], s[5], @@ -1566,26 +1559,25 @@ load_timespec (const GncSqlBackend* be, GncSqlRow& row, } } set_parameter(pObject, &ts, - reinterpret_cast(setter), - table_row.gobj_param_name); -} + reinterpret_cast(get_setter(obj_name)), + m_gobj_param_name); + } -static void -add_timespec_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { - g_return_if_fail (be != NULL); + g_return_if_fail (be != nullptr); - GncSqlColumnInfo info{table_row, BCT_DATETIME, TIMESPEC_COL_SIZE, FALSE}; + GncSqlColumnInfo info{*this, BCT_DATETIME, TIMESPEC_COL_SIZE, FALSE}; vec.emplace_back(std::move(info)); } -static void -add_timespec_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { TimespecAccessFunc ts_getter; Timespec ts; @@ -1597,15 +1589,15 @@ add_timespec_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - if (table_row.gobj_param_name != NULL) + if (m_gobj_param_name != NULL) { Timespec* pts; - g_object_get (pObject, table_row.gobj_param_name, &pts, NULL); + g_object_get (pObject, m_gobj_param_name, &pts, NULL); ts = *pts; } else { - ts_getter = (TimespecAccessFunc)gnc_sql_get_getter (obj_name, table_row); + ts_getter = (TimespecAccessFunc)get_getter (obj_name); g_return_if_fail (ts_getter != NULL); ts = (*ts_getter) (pObject); } @@ -1613,31 +1605,24 @@ add_timespec_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, if (ts.tv_sec != 0 || ts.tv_nsec != 0) { char* datebuf = gnc_sql_convert_timespec_to_string (be, ts); - vec.emplace_back (std::make_pair (std::string{table_row.col_name}, + vec.emplace_back (std::make_pair (std::string{m_col_name}, std::string{datebuf})); return; } } -static GncSqlColumnTypeHandler timespec_handler -= -{ - load_timespec, - add_timespec_col_info_to_list, - add_timespec_to_vec -}; /* ----------------------------------------------------------------- */ #define DATE_COL_SIZE 8 -static void -load_date (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row.gobj_param_name != nullptr || - setter != nullptr); - if (row.is_col_null(table_row.col_name)) + g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr); + if (row.is_col_null(m_col_name)) return; GDate date; g_date_clear (&date, 1); @@ -1646,7 +1631,7 @@ load_date (const GncSqlBackend* be, GncSqlRow& row, /* timespec_to_gdate applies the tz, and gdates are saved * as ymd, so we don't want that. */ - auto time = row.get_time64_at_col(table_row.col_name); + auto time = row.get_time64_at_col(m_col_name); auto tm = gnc_gmtime(&time); g_date_set_dmy(&date, tm->tm_mday, static_cast(tm->tm_mon + 1), @@ -1657,7 +1642,7 @@ load_date (const GncSqlBackend* be, GncSqlRow& row, { try { - std::string str = row.get_string_at_col(table_row.col_name); + std::string str = row.get_string_at_col(m_col_name); if (str.empty()) return; auto year = static_cast(stoi (str.substr (0,4))); auto month = static_cast(stoi (str.substr (4,2))); @@ -1672,74 +1657,65 @@ load_date (const GncSqlBackend* be, GncSqlRow& row, return; } } - set_parameter(pObject, &date, setter, table_row.gobj_param_name); + set_parameter(pObject, &date, get_setter(obj_name), m_gobj_param_name); } -static void -add_date_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { g_return_if_fail (be != NULL); - GncSqlColumnInfo info{table_row, BCT_DATE, DATE_COL_SIZE, FALSE}; + GncSqlColumnInfo info{*this, BCT_DATE, DATE_COL_SIZE, FALSE}; vec.emplace_back(std::move(info)); } -static void -add_date_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { - GDate *date = get_row_value_from_object(obj_name, pObject, - table_row); + GDate *date = get_row_value_from_object(obj_name, pObject); + if (date && g_date_valid (date)) { std::ostringstream buf; buf << std::setfill ('0') << std::setw (4) << g_date_get_year (date) << std::setw (2) << g_date_get_month (date) << std::setw (2) << static_cast(g_date_get_day (date)); - vec.emplace_back (std::make_pair (std::string{table_row.col_name}, - buf.str())); + vec.emplace_back (std::make_pair (std::string{m_col_name}, buf.str())); return; } } -static GncSqlColumnTypeHandler date_handler -= -{ - load_date, - add_date_col_info_to_list, - add_date_to_vec -}; /* ----------------------------------------------------------------- */ typedef gnc_numeric (*NumericGetterFunc) (const gpointer); typedef void (*NumericSetterFunc) (gpointer, gnc_numeric*); static const EntryVec numeric_col_table = { - { "num", CT_INT64, 0, COL_NNUL, "guid" }, - { "denom", CT_INT64, 0, COL_NNUL, "guid" }, + gnc_sql_make_table_entry("num", 0, COL_NNUL, "guid"), + gnc_sql_make_table_entry("denom", 0, COL_NNUL, "guid") }; -static void -load_numeric (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { g_return_if_fail (pObject != NULL); - g_return_if_fail (table_row.gobj_param_name != nullptr || - setter != nullptr); + g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr); gnc_numeric n; try { - auto buf = g_strdup_printf ("%s_num", table_row.col_name); + auto buf = g_strdup_printf ("%s_num", m_col_name); auto num = row.get_int_at_col (buf); g_free (buf); - buf = g_strdup_printf ("%s_denom", table_row.col_name); + buf = g_strdup_printf ("%s_denom", m_col_name); auto denom = row.get_int_at_col (buf); n = gnc_numeric_create (num, denom); } @@ -1748,33 +1724,31 @@ load_numeric (const GncSqlBackend* be, GncSqlRow& row, return; } set_parameter(pObject, &n, - reinterpret_cast(setter), - table_row.gobj_param_name); + reinterpret_cast(get_setter(obj_name)), + m_gobj_param_name); } -static void -add_numeric_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { g_return_if_fail (be != NULL); for (auto const& subtable_row : numeric_col_table) { - gchar* buf = g_strdup_printf("%s_%s", table_row.col_name, - subtable_row.col_name); + gchar* buf = g_strdup_printf("%s_%s", m_col_name, + subtable_row->m_col_name); GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false, - table_row.flags & COL_PKEY, - table_row.flags & COL_NNUL); + m_flags & COL_PKEY, m_flags & COL_NNUL); vec.emplace_back(std::move(info)); } } -static void -add_numeric_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { /* We can't use get_row_value_from_object for the same reason as Timespec. */ NumericGetterFunc getter; @@ -1784,15 +1758,15 @@ add_numeric_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - if (table_row.gobj_param_name != nullptr) + if (m_gobj_param_name != nullptr) { gnc_numeric* s; - g_object_get (pObject, table_row.gobj_param_name, &s, NULL); + g_object_get (pObject, m_gobj_param_name, &s, NULL); n = *s; } else { - getter = (NumericGetterFunc)gnc_sql_get_getter (obj_name, table_row); + getter = reinterpret_cast(get_getter (obj_name)); if (getter != NULL) { n = (*getter) (pObject); @@ -1804,8 +1778,8 @@ add_numeric_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, } std::ostringstream buf; - std::string num_col{table_row.col_name}; - std::string denom_col{table_row.col_name}; + std::string num_col{m_col_name}; + std::string denom_col{m_col_name}; num_col += "_num"; denom_col += "_denom"; buf << gnc_numeric_num (n); @@ -1815,64 +1789,8 @@ add_numeric_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, vec.emplace_back (denom_col, buf.str ()); } -static GncSqlColumnTypeHandler numeric_handler -= { load_numeric, - add_numeric_col_info_to_list, - add_numeric_to_vec -}; /* ================================================================= */ -static GHashTable* g_columnTypeHash = NULL; - -void -gnc_sql_register_col_type_handler (const GncSqlObjectType colType, - const GncSqlColumnTypeHandler* handler) -{ - g_return_if_fail (handler != NULL); - - if (g_columnTypeHash == NULL) - { - g_columnTypeHash = g_hash_table_new (g_direct_hash, g_direct_equal); - g_assert (g_columnTypeHash != NULL); - } - - DEBUG ("Col type %d registered\n", colType); - g_hash_table_insert (g_columnTypeHash, GINT_TO_POINTER(colType), (gpointer)handler); -} - -static GncSqlColumnTypeHandler* -get_handler (const GncSqlColumnTableEntry& table_row) -{ - GncSqlColumnTypeHandler* pHandler; - - if (g_columnTypeHash != NULL) - { - pHandler = static_cast( - g_hash_table_lookup (g_columnTypeHash, GINT_TO_POINTER(table_row.col_type))); - g_assert (pHandler != NULL); - } - else - { - pHandler = NULL; - } - - return pHandler; -} - -static void -register_standard_col_type_handlers (void) -{ - gnc_sql_register_col_type_handler (CT_STRING, &string_handler); - gnc_sql_register_col_type_handler (CT_BOOLEAN, &boolean_handler); - gnc_sql_register_col_type_handler (CT_INT, &int_handler); - gnc_sql_register_col_type_handler (CT_INT64, &int64_handler); - gnc_sql_register_col_type_handler (CT_DOUBLE, &double_handler); - gnc_sql_register_col_type_handler (CT_GUID, &guid_handler); - gnc_sql_register_col_type_handler (CT_TIMESPEC, ×pec_handler); - gnc_sql_register_col_type_handler (CT_GDATE, &date_handler); - gnc_sql_register_col_type_handler (CT_NUMERIC, &numeric_handler); -} - void _retrieve_guid_ (gpointer pObject, gpointer pValue) { @@ -1889,8 +1807,8 @@ _retrieve_guid_ (gpointer pObject, gpointer pValue) // Table to retrieve just the guid static EntryVec guid_table { - { "guid", CT_GUID, 0, 0, NULL, NULL, NULL, _retrieve_guid_ }, - }; + gnc_sql_make_table_entry("guid", 0, 0, nullptr, _retrieve_guid_) +}; const GncGUID* gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow& row) @@ -1907,8 +1825,8 @@ gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow& row) // Table to retrieve just the guid static EntryVec tx_guid_table { - { "tx_guid", CT_GUID, 0, 0, NULL, NULL, NULL, _retrieve_guid_ }, - }; + gnc_sql_make_table_entry("tx_guid", 0, 0, nullptr, _retrieve_guid_) + }; const GncGUID* @@ -1929,30 +1847,13 @@ gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow& row, const EntryVec& table) { QofSetterFunc setter; - GncSqlColumnTypeHandler* pHandler; g_return_if_fail (be != NULL); g_return_if_fail (pObject != NULL); for (auto const& table_row : table) { - if (table_row.flags & COL_AUTOINC) - { - setter = set_autoinc_id; - } - else if (table_row.qof_param_name != nullptr) - { - g_assert (obj_name != NULL); - setter = qof_class_get_parameter_setter (obj_name, - table_row.qof_param_name); - } - else - { - setter = table_row.setter; - } - pHandler = get_handler (table_row); - g_assert (pHandler != NULL); - pHandler->load_fn (be, row, setter, pObject, table_row); + table_row->load (be, row, obj_name, pObject); } } @@ -1975,18 +1876,13 @@ gnc_sql_create_select_statement (GncSqlBackend* be, const gchar* table_name) static GncSqlStatement* create_single_col_select_statement (GncSqlBackend* be, const gchar* table_name, - const GncSqlColumnTableEntry& table_row) + const GncSqlColumnTableEntryPtr table_row) { - gchar* sql; - GncSqlStatement* stmt; - g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); - sql = g_strdup_printf ("SELECT %s FROM %s", table_row.col_name, table_name); - stmt = gnc_sql_create_statement_from_sql (be, sql); - g_free (sql); - return stmt; + auto sql = std::string{"SELECT "} + table_row->name() + " FROM " + table_name; + return gnc_sql_create_statement_from_sql (be, sql.c_str()); } /* ================================================================= */ @@ -2101,6 +1997,22 @@ gnc_sql_append_guid_list_to_sql (GString* sql, GList* list, guint maxCount) return count; } /* ================================================================= */ +static PairVec +get_object_values (GncSqlBackend* be, QofIdTypeConst obj_name, + gpointer pObject, const EntryVec& table) +{ + PairVec vec; + + for (auto const& table_row : table) + { + if (!(table_row->is_autoincr())) + { + table_row->add_to_query (be, obj_name, pObject, vec); + } + } + return vec; +} + gboolean gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, @@ -2108,9 +2020,6 @@ gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, const EntryVec& table) { guint count; - GncSqlColumnTypeHandler* pHandler; - PairVec values; - g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); g_return_val_if_fail (obj_name != NULL, FALSE); @@ -2121,9 +2030,7 @@ gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, g_assert (stmt != NULL); /* WHERE */ - pHandler = get_handler (table[0]); - g_assert (pHandler != NULL); - pHandler->add_value_to_vec_fn (be, obj_name, pObject, table[0], values); + PairVec values{get_object_values(be, obj_name, pObject, table)}; stmt->add_where_cond(obj_name, values); auto result = gnc_sql_execute_select_statement (be, stmt); delete stmt; @@ -2188,26 +2095,6 @@ gnc_sql_do_db_operation (GncSqlBackend* be, return ok; } -static PairVec -get_object_values (GncSqlBackend* be, QofIdTypeConst obj_name, - gpointer pObject, const EntryVec& table) -{ - PairVec vec; - GncSqlColumnTypeHandler* pHandler; - - for (auto const& table_row : table) - { - if (!(table_row.flags & COL_AUTOINC)) - { - pHandler = get_handler (table_row); - g_assert (pHandler != NULL); - pHandler->add_value_to_vec_fn (be, obj_name, pObject, - table_row, vec); - } - } - return vec; -} - static GncSqlStatement* build_insert_statement (GncSqlBackend* be, const gchar* table_name, @@ -2291,7 +2178,6 @@ build_delete_statement (GncSqlBackend* be, const EntryVec& table) { GncSqlStatement* stmt; - GncSqlColumnTypeHandler* pHandler; std::ostringstream sql; g_return_val_if_fail (be != NULL, NULL); @@ -2304,10 +2190,8 @@ build_delete_statement (GncSqlBackend* be, sql.str().c_str()); /* WHERE */ - pHandler = get_handler (table[0]); - g_assert (pHandler != NULL); PairVec values; - pHandler->add_value_to_vec_fn (be, obj_name, pObject, table[0], values); + table[0]->add_to_query (be, obj_name, pObject, values); PairVec col_values{values[0]}; stmt->add_where_cond (obj_name, col_values); @@ -2371,9 +2255,7 @@ do_create_table (const GncSqlBackend* be, const gchar* table_name, for (auto const& table_row : col_table) { - GncSqlColumnTypeHandler* pHandler = get_handler (table_row); - g_assert (pHandler != NULL); - pHandler->add_col_info_to_list_fn (be, table_row, info_vec); + table_row->add_to_table (be, info_vec); } ok = gnc_sql_connection_create_table (be->conn, table_name, info_vec); return ok; @@ -2483,11 +2365,7 @@ gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const gchar* table_nam for (auto const& table_row : new_col_table) { - GncSqlColumnTypeHandler* pHandler; - - pHandler = get_handler (table_row); - g_assert (pHandler != NULL); - pHandler->add_col_info_to_list_fn (be, table_row, info_vec); + table_row->add_to_table (be, info_vec); } ok = gnc_sql_connection_add_columns_to_table(be->conn, table_name, info_vec); return ok; @@ -2501,9 +2379,10 @@ gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const gchar* table_nam static EntryVec version_table { - { TABLE_COL_NAME, CT_STRING, MAX_TABLE_NAME_LEN, COL_PKEY | COL_NNUL }, - { VERSION_COL_NAME, CT_INT, 0, COL_NNUL }, - }; + gnc_sql_make_table_entry( + TABLE_COL_NAME, MAX_TABLE_NAME_LEN, COL_PKEY | COL_NNUL), + gnc_sql_make_table_entry(VERSION_COL_NAME, 0, COL_NNUL) +}; /** * Sees if the version table exists, and if it does, loads the info into @@ -2649,17 +2528,17 @@ gnc_sql_set_table_version (GncSqlBackend* be, const gchar* table_name, */ #ifdef __LP64__ template <> int -get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - std::false_type) +GncSqlColumnTableEntry::get_row_value_from_object(QofIdTypeConst obj_name, + const gpointer pObject, + std::false_type) const { g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, 0); int result = 0; - if (table_row.gobj_param_name != nullptr) - g_object_get(pObject, table_row.gobj_param_name, &result, NULL ); + if (m_gobj_param_name != nullptr) + g_object_get(pObject, m_gobj_param_name, &result, NULL ); else { - QofAccessFunc getter = gnc_sql_get_getter(obj_name, table_row); + QofAccessFunc getter = get_getter(obj_name); if (getter != nullptr) { auto value = ((getter)(pObject, nullptr)); diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 817ee00545..5cb0279ab8 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -49,10 +49,12 @@ extern "C" #include #include #include +#include struct GncSqlColumnInfo; -struct GncSqlColumnTableEntry; -using EntryVec = std::vector; +class GncSqlColumnTableEntry; +using GncSqlColumnTableEntryPtr = std::shared_ptr; +using EntryVec = std::vector; using ColVec = std::vector; using StrVec = std::vector; using PairVec = std::vector>; @@ -389,47 +391,188 @@ enum ColumnFlags : int * The database description for an object consists of an array of * GncSqlColumnTableEntry objects, with a final member having col_name == NULL. */ -struct GncSqlColumnTableEntry + +class GncSqlColumnTableEntry { - GncSqlColumnTableEntry (const char* name, const GncSqlObjectType type, - unsigned int s, - ColumnFlags f, const char* gobj_name = nullptr, - const char* qof_name = nullptr, - QofAccessFunc get = nullptr, - QofSetterFunc set = nullptr) : - col_name{name}, col_type{type}, size{s}, flags{f}, - gobj_param_name{gobj_name}, qof_param_name{qof_name}, getter{get}, - setter{set} {} +public: GncSqlColumnTableEntry (const char* name, const GncSqlObjectType type, unsigned int s, int f, const char* gobj_name = nullptr, const char* qof_name = nullptr, QofAccessFunc get = nullptr, QofSetterFunc set = nullptr) : - col_name{name}, col_type{type}, size{s}, - flags{static_cast(f)}, - gobj_param_name{gobj_name}, qof_param_name{qof_name}, getter{get}, - setter{set} {} - const char* col_name; /**< Column name */ - const GncSqlObjectType col_type; /**< Column type */ - unsigned int size; /**< Column size in bytes, for string columns */ - ColumnFlags flags; /**< Column flags */ - const char* gobj_param_name; /**< If non-null, g_object param name */ - const char* qof_param_name; /**< If non-null, qof parameter name */ - QofAccessFunc getter; /**< General access function */ - QofSetterFunc setter; /**< General setter function */ + m_col_name{name}, m_col_type{type}, m_size{s}, + m_flags{static_cast(f)}, + m_gobj_param_name{gobj_name}, m_qof_param_name{qof_name}, m_getter{get}, + m_setter{set} {} + + /** + * Load a value into an object from the database row. + */ + virtual void load(const GncSqlBackend* be, GncSqlRow& row, + QofIdTypeConst obj_name, gpointer pObject) const noexcept = 0; + /** + * Add a GncSqlColumnInfo structure for the column type to a + * ColVec. + */ + virtual void add_to_table(const GncSqlBackend* be, ColVec& vec) const noexcept = 0; + /** + * Add a pair of the table column heading and object's value's string + * representation to a PairVec; used for constructing WHERE clauses and + * UPDATE statements. + */ + virtual void add_to_query(const GncSqlBackend* be, QofIdTypeConst obj_name, + gpointer pObject, PairVec& vec) const noexcept = 0; + /** + * Retrieve the getter function depending on whether it's an auto-increment + * field, a QofClass getter, or a function passed to the constructor. + */ + QofAccessFunc get_getter(QofIdTypeConst obj_name) const noexcept; + /** + * Retrieve the setter function depending on whether it's an auto-increment + * field, a QofClass getter, or a function passed to the constructor. + */ + QofSetterFunc get_setter(QofIdTypeConst obj_name) const noexcept; + /** + * Retrieve the field name so that we don't need to make + * create_single_col_select_statement and friend. + */ + const char* name() const noexcept { return m_col_name; } + /** + * Report if the entry is an auto-increment field. + */ + bool is_autoincr() const noexcept { return m_flags & COL_AUTOINC; } + /* On the other hand, our implementation class and GncSqlColumnInfo need to + * be able to read our member variables. + */ + template friend class GncSqlColumnTableEntryImpl; + friend struct GncSqlColumnInfo; + template void load_from_guid_ref(GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject, T get_ref) + const noexcept + { + g_return_if_fail (pObject != NULL); + + try + { + GncGUID guid; + auto val = row.get_string_at_col (m_col_name); + (void)string_to_guid (val.c_str(), &guid); + auto target = get_ref(&guid); + if (target != nullptr) + set_parameter (pObject, target, get_setter(obj_name), + m_gobj_param_name); + } + catch (std::invalid_argument) {} + } + +protected: + template T + get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject) const; + template void + add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, + const gpointer pObject, PairVec& vec) const; +/** + * Adds a name/guid std::pair to a PairVec for creating a query. + * + * @param be SQL backend struct + * @param obj_name QOF object type name + * @param pObject Object + * @param pList List + */ + void add_objectref_guid_to_query (const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept; +/** + * Adds a column info structure for an object reference GncGUID to a ColVec. + * + * @param be SQL backend struct + * @param pList List + */ + void add_objectref_guid_to_table (const GncSqlBackend* be, + ColVec& vec) const noexcept; +private: + const char* m_col_name; /**< Column name */ + const GncSqlObjectType m_col_type; /**< Column type */ + unsigned int m_size; /**< Column size in bytes, for string columns */ + ColumnFlags m_flags; /**< Column flags */ + const char* m_gobj_param_name; /**< If non-null, g_object param name */ + const char* m_qof_param_name; /**< If non-null, qof parameter name */ + QofAccessFunc m_getter; /**< General access function */ + QofSetterFunc m_setter; /**< General setter function */ + template T get_row_value_from_object(QofIdTypeConst obj_name, + const gpointer pObject, + std::true_type) const; + template T get_row_value_from_object(QofIdTypeConst obj_name, + const gpointer pObject, + std::false_type) const; + template void add_value_to_vec(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec, std::true_type) const; + template void add_value_to_vec(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec, std::false_type) const; + }; -inline bool operator==(const GncSqlColumnTableEntry& l, - const GncSqlColumnTableEntry& r) +template +class GncSqlColumnTableEntryImpl : public GncSqlColumnTableEntry { - return strcmp(l.col_name, r.col_name) == 0 && l.col_type == r.col_type; +public: + GncSqlColumnTableEntryImpl (const char* name, const GncSqlObjectType type, + unsigned int s, + int f, const char* gobj_name = nullptr, + const char* qof_name = nullptr, + QofAccessFunc get = nullptr, + QofSetterFunc set = nullptr) : + GncSqlColumnTableEntry (name, type, s, f, gobj_name,qof_name, get, set) + {} + void load(const GncSqlBackend* be, GncSqlRow& row, QofIdTypeConst obj_name, + gpointer pObject) const noexcept override; + void add_to_table(const GncSqlBackend* be, ColVec& vec) const noexcept override; + void add_to_query(const GncSqlBackend* be, QofIdTypeConst obj_name, + gpointer pObject, PairVec& vec) const noexcept override; +}; + +template +std::shared_ptr> +gnc_sql_make_table_entry(const char* name, unsigned int s, int f) +{ + return std::make_shared>(name, Type, s, f); } -inline bool operator!=(const GncSqlColumnTableEntry& l, - const GncSqlColumnTableEntry& r) +template +std::shared_ptr> +gnc_sql_make_table_entry(const char* name, unsigned int s, int f, + const char* param) { - return !(l == r); + return std::make_shared>(name, Type, s, + f, param); +} + +class is_qof : public std::true_type {}; + +template +std::shared_ptr> +gnc_sql_make_table_entry(const char* name, unsigned int s, int f, + const char* param, bool qofp) +{ + return std::make_shared>(name, Type, s, + f, nullptr, + param); +} + +template +std::shared_ptr> +gnc_sql_make_table_entry(const char* name, unsigned int s, int f, + QofAccessFunc get, QofSetterFunc set) +{ + return std::make_shared>( + name, Type, s, f, nullptr, nullptr, get, set); } /** @@ -446,10 +589,10 @@ struct GncSqlColumnInfo {} GncSqlColumnInfo(const GncSqlColumnTableEntry& e, GncSqlBasicColumnType t, unsigned int size = 0, bool unicode = true) : - m_name{e.col_name}, m_type{t}, m_size{size}, m_unicode{unicode}, - m_autoinc(e.flags & COL_AUTOINC), - m_primary_key(e.flags & COL_PKEY), - m_not_null(e.flags & COL_NNUL) {} + m_name{e.m_col_name}, m_type{t}, m_size{size}, m_unicode{unicode}, + m_autoinc(e.m_flags & COL_AUTOINC), + m_primary_key(e.m_flags & COL_PKEY), + m_not_null(e.m_flags & COL_NNUL) {} std::string m_name; /**< Column name */ GncSqlBasicColumnType m_type; /**< Column basic type */ unsigned int m_size; /**< Column size (string types) */ @@ -478,18 +621,6 @@ typedef enum OP_DB_DELETE } E_DB_OPERATION; -typedef void (*GNC_SQL_LOAD_FN) (const GncSqlBackend* be, - GncSqlRow& row, QofSetterFunc setter, - gpointer pObject, - const GncSqlColumnTableEntry& table_row); -typedef void (*GNC_SQL_ADD_COL_INFO_TO_LIST_FN) (const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec); -typedef void (*GNC_SQL_ADD_VALUE_TO_VEC_FN) (const GncSqlBackend* be, - QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec); /** * Set an object property with a setter function. @@ -555,45 +686,6 @@ void set_parameter(T object, P item, F setter, const char* property) set_parameter(object, item, setter); } -/** - * @struct GncSqlColumnTypeHandler - * - * The GncSqlColumnTypeHandler struct contains pointers to routines to handle - * different options for a specific column type. - * - * A column type maps a property value to one or more columns in the database. - */ -typedef struct -{ - /** - * Routine to load a value into an object from the database row. - */ - GNC_SQL_LOAD_FN load_fn; - - /** - * Routine to add a GncSqlColumnInfo structure for the column type to a - * GList. - */ - GNC_SQL_ADD_COL_INFO_TO_LIST_FN add_col_info_to_list_fn; - - /** - * Add a pair of the table column heading and object's value's string - * representation to a PairVec; used for constructing WHERE clauses and - * UPDATE statements. - */ - GNC_SQL_ADD_VALUE_TO_VEC_FN add_value_to_vec_fn; -} GncSqlColumnTypeHandler; - -/** - * Returns the QOF access function for a column. - * - * @param obj_name QOF object type name - * @param table_row DB table column - * @return Access function - */ -QofAccessFunc gnc_sql_get_getter (QofIdTypeConst obj_name, - const GncSqlColumnTableEntry& table_row); - /** * Performs an operation on the database. * @@ -768,42 +860,6 @@ const GncGUID* gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow& row); GncSqlStatement* gnc_sql_create_select_statement (GncSqlBackend* be, const gchar* table_name); -/** - * Registers a column handler for a new column type. - * - * @param colType Column type - * @param handler Column handler - */ -void gnc_sql_register_col_type_handler (const GncSqlObjectType colType, - const GncSqlColumnTypeHandler* handler); - -/** - * Adds a GValue for an object reference GncGUID to the end of a GSList. - * - * @param be SQL backend struct - * @param obj_name QOF object type name - * @param pObject Object - * @param table_row DB table column description - * @param pList List - */ -void gnc_sql_add_objectref_guid_to_vec (const GncSqlBackend* be, - QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec); - -/** - * Adds a column info structure for an object reference GncGUID to the end of a - * GList. - * - * @param be SQL backend struct - * @param table_row DB table column description - * @param pList List - */ -void gnc_sql_add_objectref_guid_col_info_to_list (const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec); - /** * Appends the ascii strings for a list of GUIDs to the end of an SQL string. * @@ -910,25 +966,25 @@ typedef struct } write_objects_t; template T -get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry& table_row) +GncSqlColumnTableEntry::get_row_value_from_object(QofIdTypeConst obj_name, + const gpointer pObject) const { - return get_row_value_from_object(obj_name, pObject, table_row, + return get_row_value_from_object(obj_name, pObject, std::is_pointer()); } template T -get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - std::true_type) +GncSqlColumnTableEntry::get_row_value_from_object(QofIdTypeConst obj_name, + const gpointer pObject, + std::true_type) const { g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, nullptr); T result = nullptr; - if (table_row.gobj_param_name != nullptr) - g_object_get(pObject, table_row.gobj_param_name, &result, NULL ); + if (m_gobj_param_name != nullptr) + g_object_get(pObject, m_gobj_param_name, &result, NULL ); else { - QofAccessFunc getter = gnc_sql_get_getter(obj_name, table_row); + QofAccessFunc getter = get_getter(obj_name); if (getter != nullptr) result = reinterpret_cast((getter)(pObject, nullptr)); } @@ -936,18 +992,18 @@ get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, } template T -get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - std::false_type) +GncSqlColumnTableEntry::get_row_value_from_object(QofIdTypeConst obj_name, + const gpointer pObject, + std::false_type) const { g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, static_cast(0)); T result = static_cast(0); - if (table_row.gobj_param_name != nullptr) - g_object_get(pObject, table_row.gobj_param_name, &result, NULL ); + if (m_gobj_param_name != nullptr) + g_object_get(pObject, m_gobj_param_name, &result, NULL ); else { - QofAccessFunc getter = gnc_sql_get_getter(obj_name, table_row); + QofAccessFunc getter = get_getter(obj_name); if (getter != nullptr) result = reinterpret_cast((getter)(pObject, nullptr)); } @@ -955,49 +1011,45 @@ get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject, } template void -add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec) +GncSqlColumnTableEntry::add_value_to_vec(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const { - add_value_to_vec(be, obj_name, pObject, table_row, vec, - std::is_pointer()); + add_value_to_vec(be, obj_name, pObject, vec, std::is_pointer()); } template void -add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec, std::true_type) +GncSqlColumnTableEntry::add_value_to_vec(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec, std::true_type) const { - T s = get_row_value_from_object(obj_name, pObject, table_row); + T s = get_row_value_from_object(obj_name, pObject); if (s != nullptr) { std::ostringstream stream; stream << *s; - vec.emplace_back(std::make_pair(std::string{table_row.col_name}, - stream.str())); + vec.emplace_back(std::make_pair(std::string{m_col_name}, stream.str())); return; } } template void -add_value_to_vec(const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec, std::false_type) +GncSqlColumnTableEntry::add_value_to_vec(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec, std::false_type) const { - T s = get_row_value_from_object(obj_name, pObject, table_row); + T s = get_row_value_from_object(obj_name, pObject); std::ostringstream stream; stream << s; - vec.emplace_back(std::make_pair(std::string{table_row.col_name}, - stream.str())); + vec.emplace_back(std::make_pair(std::string{m_col_name}, stream.str())); return; } - #endif /* GNC_BACKEND_SQL_H */ /** diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index 44dcb4173e..718fec1803 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -63,31 +63,36 @@ static void bt_set_parent_guid (gpointer data, gpointer value); static EntryVec col_table { - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" }, - { "description", CT_STRING, MAX_DESCRIPTION_LEN, COL_NNUL, NULL, GNC_BILLTERM_DESC }, - { - "refcount", CT_INT, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)gncBillTermGetRefcount, (QofSetterFunc)gncBillTermSetRefcount - }, - { - "invisible", CT_BOOLEAN, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)gncBillTermGetInvisible, (QofSetterFunc)set_invisible - }, - { - "parent", CT_GUID, 0, 0, NULL, NULL, - (QofAccessFunc)bt_get_parent, (QofSetterFunc)bt_set_parent - }, - { "type", CT_STRING, MAX_TYPE_LEN, COL_NNUL, NULL, GNC_BILLTERM_TYPE }, - { "duedays", CT_INT, 0, 0, 0, GNC_BILLTERM_DUEDAYS }, - { "discountdays", CT_INT, 0, 0, 0, GNC_BILLTERM_DISCDAYS }, - { "discount", CT_NUMERIC, 0, 0, 0, GNC_BILLTERM_DISCOUNT }, - { "cutoff", CT_INT, 0, 0, 0, GNC_BILLTERM_CUTOFF }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("name", MAX_NAME_LEN, COL_NNUL, "name"), + gnc_sql_make_table_entry("description", MAX_DESCRIPTION_LEN, + COL_NNUL, GNC_BILLTERM_DESC, + true), + gnc_sql_make_table_entry("refcount", 0, COL_NNUL, + (QofAccessFunc)gncBillTermGetRefcount, + (QofSetterFunc)gncBillTermSetRefcount), + gnc_sql_make_table_entry("invisible", 0, COL_NNUL, + (QofAccessFunc)gncBillTermGetInvisible, + (QofSetterFunc)set_invisible), + gnc_sql_make_table_entry("parent", 0, 0, + (QofAccessFunc)bt_get_parent, + (QofSetterFunc)bt_set_parent), + gnc_sql_make_table_entry("type", MAX_TYPE_LEN, COL_NNUL, + GNC_BILLTERM_TYPE, true), + gnc_sql_make_table_entry("duedays", 0, 0, GNC_BILLTERM_DUEDAYS, + true), + gnc_sql_make_table_entry("discountdays", 0, 0, + GNC_BILLTERM_DISCDAYS, true), + gnc_sql_make_table_entry("discount", 0, 0, + GNC_BILLTERM_DISCOUNT, true), + gnc_sql_make_table_entry("cutoff", 0, 0, GNC_BILLTERM_CUTOFF, + true), }; static EntryVec billterm_parent_col_table { - { "parent", CT_GUID, 0, 0, NULL, NULL, NULL, (QofSetterFunc)bt_set_parent_guid }, + gnc_sql_make_table_entry("parent", 0, 0, nullptr, + bt_set_parent_guid), }; typedef struct @@ -337,35 +342,34 @@ gnc_sql_save_billterm (GncSqlBackend* be, QofInstance* inst) } /* ================================================================= */ -static void -load_billterm_guid (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) + +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { - GncGUID guid; - GncBillTerm* term = NULL; - - g_return_if_fail (be != NULL); - g_return_if_fail (pObject != NULL); - - try - { - auto val = row.get_string_at_col (table_row.col_name); - string_to_guid (val.c_str(), &guid); - term = gncBillTermLookup (be->book, &guid); - if (term != nullptr) - set_parameter (pObject, term, setter, table_row.gobj_param_name); - else - PWARN ("Billterm ref '%s' not found", val.c_str()); - } - catch (std::invalid_argument) {} + load_from_guid_ref(row, obj_name, pObject, + [be](GncGUID* g){ + return gncBillTermLookup(be->book, g); + }); } -static GncSqlColumnTypeHandler billterm_guid_handler -= { load_billterm_guid, - gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_objectref_guid_to_vec - }; +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept +{ + add_objectref_guid_to_table(be, vec); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept +{ + add_objectref_guid_to_query(be, obj_name, pObject, vec); +} /* ================================================================= */ void gnc_billterm_sql_initialize (void) @@ -382,6 +386,5 @@ gnc_billterm_sql_initialize (void) }; gnc_sql_register_backend(&be_data); - gnc_sql_register_col_type_handler (CT_BILLTERMREF, &billterm_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-book-sql.cpp b/src/backend/sql/gnc-book-sql.cpp index 0dabb429d5..ea30076fdf 100644 --- a/src/backend/sql/gnc-book-sql.cpp +++ b/src/backend/sql/gnc-book-sql.cpp @@ -58,15 +58,14 @@ static void set_root_template_guid (gpointer pObject, gpointer pValue); static const EntryVec col_table { - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { - "root_account_guid", CT_GUID, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_root_account_guid, set_root_account_guid - }, - { - "root_template_guid", CT_GUID, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_root_template_guid, set_root_template_guid - }, + gnc_sql_make_table_entry( + "guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("root_account_guid", 0, COL_NNUL, + (QofAccessFunc)get_root_account_guid, + set_root_account_guid), + gnc_sql_make_table_entry("root_template_guid", 0, COL_NNUL, + (QofAccessFunc)get_root_template_guid, + set_root_template_guid) }; /* ================================================================= */ diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index dad49c2133..231851305e 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -57,10 +57,14 @@ static QofLogModule log_module = G_LOG_DOMAIN; static const EntryVec col_table { - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "name", CT_STRING, BUDGET_MAX_NAME_LEN, COL_NNUL, "name" }, - { "description", CT_STRING, BUDGET_MAX_DESCRIPTION_LEN, 0, "description" }, - { "num_periods", CT_INT, 0, COL_NNUL, "num_periods" }, + gnc_sql_make_table_entry( + "guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry( + "name", BUDGET_MAX_NAME_LEN, COL_NNUL, "name"), + gnc_sql_make_table_entry( + "description", BUDGET_MAX_DESCRIPTION_LEN, 0, "description"), + gnc_sql_make_table_entry( + "num_periods", 0, COL_NNUL, "num_periods"), }; static QofInstance* get_budget (gpointer pObj); @@ -81,23 +85,20 @@ typedef struct static const EntryVec budget_amounts_col_table { - { "id", CT_INT, 0, COL_NNUL | COL_PKEY | COL_AUTOINC }, - { - "budget_guid", CT_BUDGETREF, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_budget, (QofSetterFunc)set_budget - }, - { - "account_guid", CT_ACCOUNTREF, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_account, (QofSetterFunc)set_account - }, - { - "period_num", CT_INT, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_period_num, (QofSetterFunc)set_period_num - }, - { - "amount", CT_NUMERIC, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_amount, (QofSetterFunc)set_amount - }, + gnc_sql_make_table_entry( + "id", 0, COL_NNUL | COL_PKEY | COL_AUTOINC), + gnc_sql_make_table_entry("budget_guid", 0, COL_NNUL, + (QofAccessFunc)get_budget, + (QofSetterFunc)set_budget), + gnc_sql_make_table_entry("account_guid", 0, COL_NNUL, + (QofAccessFunc)get_account, + (QofSetterFunc)set_account), + gnc_sql_make_table_entry("period_num", 0, COL_NNUL, + (QofAccessFunc)get_period_num, + (QofSetterFunc)set_period_num), + gnc_sql_make_table_entry("amount", 0, COL_NNUL, + (QofAccessFunc)get_amount, + (QofSetterFunc)set_amount), }; /* ================================================================= */ @@ -460,36 +461,33 @@ write_budgets (GncSqlBackend* be) } /* ================================================================= */ -static void -load_budget_guid (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { - const GValue* val; - GncGUID guid; - GncBudget* budget = NULL; - - g_return_if_fail (be != NULL); - g_return_if_fail (pObject != NULL); - - try - { - auto val = row.get_string_at_col (table_row.col_name); - (void)string_to_guid (val.c_str(), &guid); - budget = gnc_budget_lookup (&guid, be->book); - if (budget != nullptr) - set_parameter(pObject, budget, setter, table_row.gobj_param_name); - else - PWARN ("Budget ref '%s' not found", val.c_str()); - } - catch (std::invalid_argument) {} + load_from_guid_ref(row, obj_name, pObject, + [be](GncGUID* g){ + return gnc_budget_lookup (g, be->book); + }); } -static GncSqlColumnTypeHandler budget_guid_handler -= { load_budget_guid, - gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_objectref_guid_to_vec - }; +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept +{ + add_objectref_guid_to_table(be, vec); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept +{ + add_objectref_guid_to_query(be, obj_name, pObject, vec); +} /* ================================================================= */ void gnc_sql_init_budget_handler (void) @@ -508,6 +506,5 @@ gnc_sql_init_budget_handler (void) }; gnc_sql_register_backend(&be_data); - gnc_sql_register_col_type_handler (CT_BUDGETREF, &budget_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index 331ffddc34..82c2972c69 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -61,22 +61,27 @@ static void set_quote_source_name (gpointer pObject, gpointer pValue); static const EntryVec col_table { - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { - "namespace", CT_STRING, COMMODITY_MAX_NAMESPACE_LEN, COL_NNUL, NULL, NULL, - (QofAccessFunc)gnc_commodity_get_namespace, - (QofSetterFunc)gnc_commodity_set_namespace - }, - { "mnemonic", CT_STRING, COMMODITY_MAX_MNEMONIC_LEN, COL_NNUL, "mnemonic" }, - { "fullname", CT_STRING, COMMODITY_MAX_FULLNAME_LEN, 0, "fullname" }, - { "cusip", CT_STRING, COMMODITY_MAX_CUSIP_LEN, 0, "cusip" }, - { "fraction", CT_INT, 0, COL_NNUL, "fraction" }, - { "quote_flag", CT_BOOLEAN, 0, COL_NNUL, "quote_flag" }, - { - "quote_source", CT_STRING, COMMODITY_MAX_QUOTESOURCE_LEN, 0, NULL, NULL, - (QofAccessFunc)get_quote_source_name, set_quote_source_name - }, - { "quote_tz", CT_STRING, COMMODITY_MAX_QUOTE_TZ_LEN, 0, "quote-tz" }, + gnc_sql_make_table_entry( + "guid", 0, COL_NNUL | COL_PKEY | COL_UNIQUE, "guid"), + gnc_sql_make_table_entry("namespace", + COMMODITY_MAX_NAMESPACE_LEN, COL_NNUL, + (QofAccessFunc)gnc_commodity_get_namespace, + (QofSetterFunc)gnc_commodity_set_namespace), + gnc_sql_make_table_entry( + "mnemonic", COMMODITY_MAX_MNEMONIC_LEN, COL_NNUL, "mnemonic"), + gnc_sql_make_table_entry( + "fullname", COMMODITY_MAX_FULLNAME_LEN, 0, "fullname"), + gnc_sql_make_table_entry( + "cusip", COMMODITY_MAX_CUSIP_LEN, 0, "cusip"), + gnc_sql_make_table_entry("fraction", 0, COL_NNUL, "fraction"), + gnc_sql_make_table_entry( + "quote_flag", 0, COL_NNUL, "quote_flag"), + gnc_sql_make_table_entry("quote_source", + COMMODITY_MAX_QUOTESOURCE_LEN, 0, + (QofAccessFunc)get_quote_source_name, + set_quote_source_name), + gnc_sql_make_table_entry( + "quote_tz", COMMODITY_MAX_QUOTE_TZ_LEN, 0, "quote-tz"), }; /* ================================================================= */ @@ -262,37 +267,33 @@ gnc_sql_commit_commodity (gnc_commodity* pCommodity) } /* ----------------------------------------------------------------- */ - -static void -load_commodity_guid (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { - GncGUID guid; - gnc_commodity* commodity = NULL; - - g_return_if_fail (be != NULL); - g_return_if_fail (pObject != NULL); - - try - { - auto val = row.get_string_at_col (table_row.col_name); - (void)string_to_guid (val.c_str(), &guid); - commodity = gnc_commodity_find_commodity_by_guid (&guid, be->book); - if (commodity != nullptr) - set_parameter (pObject, commodity, setter, - table_row.gobj_param_name); - else - PWARN ("Commodity ref '%s' not found", val.c_str()); - } - catch (std::invalid_argument) {} + load_from_guid_ref(row, obj_name, pObject, + [be](GncGUID* g){ + return gnc_commodity_find_commodity_by_guid(g, be->book); + }); } -static GncSqlColumnTypeHandler commodity_guid_handler -= { load_commodity_guid, - gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_objectref_guid_to_vec - }; +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept +{ + add_objectref_guid_to_table(be, vec); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept +{ + add_objectref_guid_to_query(be, obj_name, pObject, vec); +} /* ================================================================= */ void gnc_sql_init_commodity_handler (void) @@ -311,6 +312,5 @@ gnc_sql_init_commodity_handler (void) }; gnc_sql_register_backend(&be_data); - gnc_sql_register_col_type_handler (CT_COMMODITYREF, &commodity_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index 631917d57d..583629fe23 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -43,7 +43,6 @@ extern "C" #include "gnc-backend-sql.h" #include "gnc-slots-sql.h" #include "gnc-customer-sql.h" -#include "gnc-address-sql.h" #include "gnc-bill-term-sql.h" #include "gnc-tax-table-sql.h" @@ -60,29 +59,35 @@ static QofLogModule log_module = G_LOG_DOMAIN; static EntryVec col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" }, - { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, NULL, CUSTOMER_ID }, - { "notes", CT_STRING, MAX_NOTES_LEN, COL_NNUL, NULL, CUSTOMER_NOTES }, - { "active", CT_BOOLEAN, 0, COL_NNUL, NULL, QOF_PARAM_ACTIVE }, - { "discount", CT_NUMERIC, 0, COL_NNUL, NULL, CUSTOMER_DISCOUNT }, - { "credit", CT_NUMERIC, 0, COL_NNUL, NULL, CUSTOMER_CREDIT }, - { - "currency", CT_COMMODITYREF, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)gncCustomerGetCurrency, (QofSetterFunc)gncCustomerSetCurrency - }, - { "tax_override", CT_BOOLEAN, 0, COL_NNUL, NULL, CUSTOMER_TT_OVER }, - { "addr", CT_ADDRESS, 0, 0, NULL, CUSTOMER_ADDR }, - { "shipaddr", CT_ADDRESS, 0, 0, NULL, CUSTOMER_SHIPADDR }, - { "terms", CT_BILLTERMREF, 0, 0, NULL, CUSTOMER_TERMS }, - { - "tax_included", CT_INT, 0, 0, NULL, NULL, - (QofAccessFunc)gncCustomerGetTaxIncluded, (QofSetterFunc)gncCustomerSetTaxIncluded - }, - { - "taxtable", CT_TAXTABLEREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncCustomerGetTaxTable, (QofSetterFunc)gncCustomerSetTaxTable - }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid" ), + gnc_sql_make_table_entry("name", MAX_NAME_LEN, COL_NNUL, "name"), + gnc_sql_make_table_entry("id", MAX_ID_LEN, COL_NNUL, + CUSTOMER_ID, true), + gnc_sql_make_table_entry("notes", MAX_NOTES_LEN, COL_NNUL, + CUSTOMER_NOTES, true), + gnc_sql_make_table_entry("active", 0, COL_NNUL, + QOF_PARAM_ACTIVE, true), + gnc_sql_make_table_entry("discount", 0, COL_NNUL, + CUSTOMER_DISCOUNT, true), + gnc_sql_make_table_entry("credit", 0, COL_NNUL, + CUSTOMER_CREDIT, true), + gnc_sql_make_table_entry("currency", 0, COL_NNUL, + (QofAccessFunc)gncCustomerGetCurrency, + (QofSetterFunc)gncCustomerSetCurrency), + gnc_sql_make_table_entry("tax_override", 0, COL_NNUL, + CUSTOMER_TT_OVER, true), + gnc_sql_make_table_entry("addr", 0, 0, CUSTOMER_ADDR, + true), + gnc_sql_make_table_entry("shipaddr", 0, 0, CUSTOMER_SHIPADDR, + true), + gnc_sql_make_table_entry("terms", 0, 0, CUSTOMER_TERMS, + true), + gnc_sql_make_table_entry("tax_included", 0, 0, + (QofAccessFunc)gncCustomerGetTaxIncluded, + (QofSetterFunc)gncCustomerSetTaxIncluded), + gnc_sql_make_table_entry("taxtable", 0, 0, + (QofAccessFunc)gncCustomerGetTaxTable, + (QofSetterFunc)gncCustomerSetTaxTable), }); static GncCustomer* diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index c0ed579951..20e2df7ed3 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -43,8 +43,6 @@ extern "C" #include "gnc-slots-sql.h" #include "gnc-commodity-sql.h" #include "gnc-employee-sql.h" -#include "gnc-address-sql.h" - #define _GNC_MOD_NAME GNC_ID_EMPLOYEE @@ -60,17 +58,21 @@ static QofLogModule log_module = G_LOG_DOMAIN; static EntryVec col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "username", CT_STRING, MAX_USERNAME_LEN, COL_NNUL, "username" }, - { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, "id" }, - { "language", CT_STRING, MAX_LANGUAGE_LEN, COL_NNUL, "language" }, - { "acl", CT_STRING, MAX_ACL_LEN, COL_NNUL, "acl" }, - { "active", CT_BOOLEAN, 0, COL_NNUL, "active" }, - { "currency", CT_COMMODITYREF, 0, COL_NNUL, "currency" }, - { "ccard_guid", CT_ACCOUNTREF, 0, 0, "credit-card-account" }, - { "workday", CT_NUMERIC, 0, COL_NNUL, "workday" }, - { "rate", CT_NUMERIC, 0, COL_NNUL, "rate" }, - { "addr", CT_ADDRESS, 0, 0, "address" }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry( + "username", MAX_USERNAME_LEN, COL_NNUL, "username"), + gnc_sql_make_table_entry("id", MAX_ID_LEN, COL_NNUL, "id"), + gnc_sql_make_table_entry( + "language", MAX_LANGUAGE_LEN, COL_NNUL, "language"), + gnc_sql_make_table_entry("acl", MAX_ACL_LEN, COL_NNUL, "acl"), + gnc_sql_make_table_entry("active", 0, COL_NNUL, "active"), + gnc_sql_make_table_entry( + "currency", 0, COL_NNUL, "currency"), + gnc_sql_make_table_entry( + "ccard_guid", 0, 0, "credit-card-account"), + gnc_sql_make_table_entry("workday", 0, COL_NNUL, "workday"), + gnc_sql_make_table_entry("rate", 0, COL_NNUL, "rate"), + gnc_sql_make_table_entry("addr", 0, 0, "address"), }); static GncEmployee* diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index fbf84a2691..59b6bf891a 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -46,7 +46,6 @@ extern "C" #include "gnc-entry-sql.h" #include "gnc-invoice-sql.h" #include "gnc-order-sql.h" -#include "gnc-owner-sql.h" #include "gnc-tax-table-sql.h" #define _GNC_MOD_NAME GNC_ID_ENTRY @@ -66,53 +65,63 @@ static void entry_set_bill (gpointer pObject, gpointer val); static EntryVec col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "date", CT_TIMESPEC, 0, COL_NNUL, NULL, ENTRY_DATE }, - { "date_entered", CT_TIMESPEC, 0, 0, NULL, ENTRY_DATE_ENTERED }, - { "description", CT_STRING, MAX_DESCRIPTION_LEN, 0, "description" }, - { "action", CT_STRING, MAX_ACTION_LEN, 0, NULL, ENTRY_ACTION }, - { "notes", CT_STRING, MAX_NOTES_LEN, 0, NULL, ENTRY_NOTES }, - { "quantity", CT_NUMERIC, 0, 0, NULL, ENTRY_QTY }, - { "i_acct", CT_ACCOUNTREF, 0, 0, NULL, ENTRY_IACCT }, - { "i_price", CT_NUMERIC, 0, 0, NULL, ENTRY_IPRICE }, - { - "i_discount", CT_NUMERIC, 0, 0, NULL, NULL, - (QofAccessFunc)gncEntryGetInvDiscount, (QofSetterFunc)gncEntrySetInvDiscount - }, - { - "invoice", CT_INVOICEREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncEntryGetInvoice, (QofSetterFunc)entry_set_invoice - }, - { "i_disc_type", CT_STRING, MAX_DISCTYPE_LEN, 0, NULL, ENTRY_INV_DISC_TYPE }, - { "i_disc_how", CT_STRING, MAX_DISCHOW_LEN, 0, NULL, ENTRY_INV_DISC_HOW }, - { "i_taxable", CT_BOOLEAN, 0, 0, NULL, ENTRY_INV_TAXABLE }, - { "i_taxincluded", CT_BOOLEAN, 0, 0, NULL, ENTRY_INV_TAX_INC }, - { - "i_taxtable", CT_TAXTABLEREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncEntryGetInvTaxTable, (QofSetterFunc)gncEntrySetInvTaxTable - }, - { "b_acct", CT_ACCOUNTREF, 0, 0, NULL, ENTRY_BACCT }, - { "b_price", CT_NUMERIC, 0, 0, NULL, ENTRY_BPRICE }, - { - "bill", CT_INVOICEREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncEntryGetBill, (QofSetterFunc)entry_set_bill - }, - { "b_taxable", CT_BOOLEAN, 0, 0, NULL, ENTRY_BILL_TAXABLE }, - { "b_taxincluded", CT_BOOLEAN, 0, 0, NULL, ENTRY_BILL_TAX_INC }, - { - "b_taxtable", CT_TAXTABLEREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncEntryGetBillTaxTable, (QofSetterFunc)gncEntrySetBillTaxTable - }, - { - "b_paytype", CT_INT, 0, 0, NULL, NULL, - (QofAccessFunc)gncEntryGetBillPayment, (QofSetterFunc)gncEntrySetBillPayment - }, - { "billable", CT_BOOLEAN, 0, 0, NULL, ENTRY_BILLABLE }, - { "billto", CT_OWNERREF, 0, 0, NULL, ENTRY_BILLTO }, - { - "order_guid", CT_ORDERREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncEntryGetOrder, (QofSetterFunc)gncEntrySetOrder - }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("date", 0, COL_NNUL, ENTRY_DATE, + true), + gnc_sql_make_table_entry("date_entered", 0, 0, + ENTRY_DATE_ENTERED, true), + gnc_sql_make_table_entry( + "description", MAX_DESCRIPTION_LEN, 0, "description"), + gnc_sql_make_table_entry("action", MAX_ACTION_LEN, 0, + ENTRY_ACTION, true), + gnc_sql_make_table_entry("notes", MAX_NOTES_LEN, 0, ENTRY_NOTES, + true), + gnc_sql_make_table_entry("quantity", 0, 0, ENTRY_QTY, + true), + gnc_sql_make_table_entry("i_acct", 0, 0, ENTRY_IACCT, + true), + gnc_sql_make_table_entry("i_price", 0, 0, ENTRY_IPRICE, + true), + gnc_sql_make_table_entry("i_discount", 0, 0, + (QofAccessFunc)gncEntryGetInvDiscount, + (QofSetterFunc)gncEntrySetInvDiscount), + gnc_sql_make_table_entry("invoice", 0, 0, + (QofAccessFunc)gncEntryGetInvoice, + (QofSetterFunc)entry_set_invoice), + gnc_sql_make_table_entry("i_disc_type", MAX_DISCTYPE_LEN, 0, + ENTRY_INV_DISC_TYPE, true), + gnc_sql_make_table_entry("i_disc_how", MAX_DISCHOW_LEN, 0, + ENTRY_INV_DISC_HOW, true), + gnc_sql_make_table_entry("i_taxable", 0, 0, ENTRY_INV_TAXABLE, + true), + gnc_sql_make_table_entry("i_taxincluded", 0, 0, + ENTRY_INV_TAX_INC, true), + gnc_sql_make_table_entry("i_taxtable", 0, 0, + (QofAccessFunc)gncEntryGetInvTaxTable, + (QofSetterFunc)gncEntrySetInvTaxTable), + gnc_sql_make_table_entry("b_acct", 0, 0, ENTRY_BACCT, + true), + gnc_sql_make_table_entry("b_price", 0, 0, ENTRY_BPRICE, + true), + gnc_sql_make_table_entry("bill", 0, 0, + (QofAccessFunc)gncEntryGetBill, + (QofSetterFunc)entry_set_bill), + gnc_sql_make_table_entry("b_taxable", 0, 0, ENTRY_BILL_TAXABLE, + true), + gnc_sql_make_table_entry("b_taxincluded", 0, 0, + ENTRY_BILL_TAX_INC, true), + gnc_sql_make_table_entry("b_taxtable", 0, 0, + (QofAccessFunc)gncEntryGetBillTaxTable, + (QofSetterFunc)gncEntrySetBillTaxTable), + gnc_sql_make_table_entry("b_paytype", 0, 0, + (QofAccessFunc)gncEntryGetBillPayment, + (QofSetterFunc)gncEntrySetBillPayment), + gnc_sql_make_table_entry("billable", 0, 0, ENTRY_BILLABLE, + true), + gnc_sql_make_table_entry("billto", 0, 0, ENTRY_BILLTO, true), + gnc_sql_make_table_entry("order_guid", 0, 0, + (QofAccessFunc)gncEntryGetOrder, + (QofSetterFunc)gncEntrySetOrder), }); static void diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index 819538c7a2..fd8450dbce 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -45,7 +45,6 @@ extern "C" #include "gnc-commodity-sql.h" #include "gnc-slots-sql.h" #include "gnc-invoice-sql.h" -#include "gnc-owner-sql.h" #include "gnc-bill-term-sql.h" #define _GNC_MOD_NAME GNC_ID_INVOICE @@ -61,36 +60,40 @@ static QofLogModule log_module = G_LOG_DOMAIN; static EntryVec col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, NULL, INVOICE_ID }, - { "date_opened", CT_TIMESPEC, 0, 0, NULL, INVOICE_OPENED }, - { "date_posted", CT_TIMESPEC, 0, 0, NULL, INVOICE_POSTED }, - { "notes", CT_STRING, MAX_NOTES_LEN, COL_NNUL, "notes" }, - { "active", CT_BOOLEAN, 0, COL_NNUL, NULL, QOF_PARAM_ACTIVE }, - { - "currency", CT_COMMODITYREF, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)gncInvoiceGetCurrency, (QofSetterFunc)gncInvoiceSetCurrency - }, - { - "owner", CT_OWNERREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncInvoiceGetOwner, (QofSetterFunc)gncInvoiceSetOwner - }, - { "terms", CT_BILLTERMREF, 0, 0, NULL, INVOICE_TERMS }, - { "billing_id", CT_STRING, MAX_BILLING_ID_LEN, 0, NULL, INVOICE_BILLINGID }, - { "post_txn", CT_TXREF, 0, 0, NULL, INVOICE_POST_TXN }, - { - "post_lot", CT_LOTREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncInvoiceGetPostedLot, (QofSetterFunc)gncInvoiceSetPostedLot - }, - { "post_acc", CT_ACCOUNTREF, 0, 0, NULL, INVOICE_ACC }, - { - "billto", CT_OWNERREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncInvoiceGetBillTo, (QofSetterFunc)gncInvoiceSetBillTo - }, - { - "charge_amt", CT_NUMERIC, 0, 0, NULL, NULL, - (QofAccessFunc)gncInvoiceGetToChargeAmount, (QofSetterFunc)gncInvoiceSetToChargeAmount - }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("id", MAX_ID_LEN, COL_NNUL, INVOICE_ID, + true), + gnc_sql_make_table_entry("date_opened", 0, 0, INVOICE_OPENED, + true), + gnc_sql_make_table_entry("date_posted", 0, 0, INVOICE_POSTED, + true), + gnc_sql_make_table_entry("notes", MAX_NOTES_LEN, COL_NNUL, + "notes"), + gnc_sql_make_table_entry("active", 0, COL_NNUL, + QOF_PARAM_ACTIVE, true), + gnc_sql_make_table_entry("currency", 0, COL_NNUL, + (QofAccessFunc)gncInvoiceGetCurrency, + (QofSetterFunc)gncInvoiceSetCurrency), + gnc_sql_make_table_entry("owner", 0, 0, + (QofAccessFunc)gncInvoiceGetOwner, + (QofSetterFunc)gncInvoiceSetOwner), + gnc_sql_make_table_entry("terms", 0, 0, INVOICE_TERMS, + true), + gnc_sql_make_table_entry("billing_id", MAX_BILLING_ID_LEN, 0, + INVOICE_BILLINGID, true), + gnc_sql_make_table_entry("post_txn", 0, 0, INVOICE_POST_TXN, + true), + gnc_sql_make_table_entry("post_lot", 0, 0, + (QofAccessFunc)gncInvoiceGetPostedLot, + (QofSetterFunc)gncInvoiceSetPostedLot), + gnc_sql_make_table_entry("post_acc", 0, 0, INVOICE_ACC, + true), + gnc_sql_make_table_entry("billto", 0, 0, + (QofAccessFunc)gncInvoiceGetBillTo, + (QofSetterFunc)gncInvoiceSetBillTo), + gnc_sql_make_table_entry("charge_amt", 0, 0, + (QofAccessFunc)gncInvoiceGetToChargeAmount, + (QofSetterFunc)gncInvoiceSetToChargeAmount), }); static GncInvoice* @@ -274,35 +277,34 @@ write_invoices (GncSqlBackend* be) } /* ================================================================= */ -static void -load_invoice_guid (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { - GncGUID guid; - GncInvoice* invoice = NULL; - - g_return_if_fail (be != NULL); - g_return_if_fail (pObject != NULL); - - try - { - auto val = row.get_string_at_col (table_row.col_name); - string_to_guid (val.c_str(), &guid); - invoice = gncInvoiceLookup (be->book, &guid); - if (invoice != nullptr) - set_parameter (pObject, invoice, setter, table_row.gobj_param_name); - else - PWARN ("Invoice ref '%s' not found", val.c_str()); - } - catch (std::invalid_argument) {} + load_from_guid_ref(row, obj_name, pObject, + [be](GncGUID* g){ + return gncInvoiceLookup (be->book, g); + }); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept +{ + add_objectref_guid_to_table(be, vec); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept +{ + add_objectref_guid_to_query(be, obj_name, pObject, vec); } -static GncSqlColumnTypeHandler invoice_guid_handler -= { load_invoice_guid, - gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_objectref_guid_to_vec - }; /* ================================================================= */ void gnc_invoice_sql_initialize (void) @@ -319,6 +321,5 @@ gnc_invoice_sql_initialize (void) }; gnc_sql_register_backend(&be_data); - gnc_sql_register_col_type_handler (CT_INVOICEREF, &invoice_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index 932f51cba4..b57a867b7e 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -41,7 +41,6 @@ extern "C" #include "gnc-backend-sql.h" #include "gnc-slots-sql.h" #include "gnc-job-sql.h" -#include "gnc-owner-sql.h" #define _GNC_MOD_NAME GNC_ID_JOB @@ -56,18 +55,18 @@ G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN; static EntryVec col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, NULL, JOB_ID }, - { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" }, - { "reference", CT_STRING, MAX_REFERENCE_LEN, COL_NNUL, NULL, JOB_REFERENCE }, - { - "active", CT_BOOLEAN, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)gncJobGetActive, (QofSetterFunc)gncJobSetActive - }, - { - "owner", CT_OWNERREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncJobGetOwner, (QofSetterFunc)gncJobSetOwner - }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("id", MAX_ID_LEN, COL_NNUL, + JOB_ID, true), + gnc_sql_make_table_entry("name", MAX_NAME_LEN, COL_NNUL, "name"), + gnc_sql_make_table_entry("reference", MAX_REFERENCE_LEN, + COL_NNUL, JOB_REFERENCE, true), + gnc_sql_make_table_entry("active", 0, COL_NNUL, + (QofAccessFunc)gncJobGetActive, + (QofSetterFunc)gncJobSetActive), + gnc_sql_make_table_entry("owner", 0, 0, + (QofAccessFunc)gncJobGetOwner, + (QofSetterFunc)gncJobSetOwner), }); static GncJob* diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index 59fd24116d..42dfd9ec6e 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -56,12 +56,11 @@ static void set_lot_account (gpointer pObject, gpointer pValue); static const EntryVec col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { - "account_guid", CT_ACCOUNTREF, 0, 0, NULL, NULL, - (QofAccessFunc)get_lot_account, set_lot_account - }, - { "is_closed", CT_BOOLEAN, 0, COL_NNUL, "is-closed" } + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("account_guid", 0, 0, + (QofAccessFunc)get_lot_account, + set_lot_account), + gnc_sql_make_table_entry("is_closed", 0, COL_NNUL, "is-closed") }); /* ================================================================= */ @@ -203,35 +202,33 @@ write_lots (GncSqlBackend* be) } /* ================================================================= */ -static void -load_lot_guid (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { - GncGUID guid; - GNCLot* lot; - - g_return_if_fail (be != NULL); - g_return_if_fail (pObject != NULL); - - try - { - auto val = row.get_string_at_col (table_row.col_name); - (void)string_to_guid (val.c_str(), &guid); - lot = gnc_lot_lookup (&guid, be->book); - if (lot != nullptr) - set_parameter (pObject, lot, setter, table_row.gobj_param_name); - else - PWARN ("Lot ref '%s' not found", val.c_str()); - } - catch (std::invalid_argument) {} + load_from_guid_ref(row, obj_name, pObject, + [be](GncGUID* g){ + return gnc_lot_lookup(g, be->book); + }); } -static GncSqlColumnTypeHandler lot_guid_handler -= { load_lot_guid, - gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_objectref_guid_to_vec - }; +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept +{ + add_objectref_guid_to_table(be, vec); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept +{ + add_objectref_guid_to_query(be, obj_name, pObject, vec); +} /* ================================================================= */ void gnc_sql_init_lot_handler (void) @@ -248,7 +245,6 @@ gnc_sql_init_lot_handler (void) }; gnc_sql_register_backend(&be_data); - gnc_sql_register_col_type_handler (CT_LOTREF, &lot_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index 8367797e74..d931eb7ce1 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -41,7 +41,6 @@ extern "C" #include "gnc-backend-sql.h" #include "gnc-slots-sql.h" #include "gnc-order-sql.h" -#include "gnc-owner-sql.h" #define _GNC_MOD_NAME GNC_ID_ORDER @@ -56,14 +55,19 @@ static QofLogModule log_module = G_LOG_DOMAIN; static EntryVec col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, "id" }, - { "notes", CT_STRING, MAX_NOTES_LEN, COL_NNUL, "notes" }, - { "reference", CT_STRING, MAX_REFERENCE_LEN, COL_NNUL, "reference" }, - { "active", CT_BOOLEAN, 0, COL_NNUL, "order" }, - { "date_opened", CT_TIMESPEC, 0, COL_NNUL, "date-opened" }, - { "date_closed", CT_TIMESPEC, 0, COL_NNUL, "date-closed" }, - { "owner", CT_OWNERREF, 0, COL_NNUL, NULL, ORDER_OWNER }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("id", MAX_ID_LEN, COL_NNUL, "id"), + gnc_sql_make_table_entry("notes", MAX_NOTES_LEN, COL_NNUL, + "notes"), + gnc_sql_make_table_entry( + "reference", MAX_REFERENCE_LEN, COL_NNUL, "reference"), + gnc_sql_make_table_entry("active", 0, COL_NNUL, "order"), + gnc_sql_make_table_entry("date_opened", 0, COL_NNUL, + "date-opened"), + gnc_sql_make_table_entry("date_closed", 0, COL_NNUL, + "date-closed"), + gnc_sql_make_table_entry("owner", 0, COL_NNUL, + ORDER_OWNER, true), }); static GncOrder* @@ -188,35 +192,33 @@ write_orders (GncSqlBackend* be) } /* ================================================================= */ -static void -load_order_guid (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { - GncGUID guid; - GncOrder* order = NULL; - - g_return_if_fail (be != NULL); - g_return_if_fail (pObject != NULL); - - try - { - auto val = row.get_string_at_col (table_row.col_name); - string_to_guid (val.c_str(), &guid); - order = gncOrderLookup (be->book, &guid); - if (order != nullptr) - set_parameter (pObject, order, setter, table_row.gobj_param_name); - else - PWARN ("Order ref '%s' not found", val.c_str()); - } - catch (std::invalid_argument) {} + load_from_guid_ref(row, obj_name, pObject, + [be](GncGUID* g){ + return gncOrderLookup(be->book, g); + }); } -static GncSqlColumnTypeHandler order_guid_handler -= { load_order_guid, - gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_objectref_guid_to_vec - }; +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept +{ + add_objectref_guid_to_table(be, vec); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept +{ + add_objectref_guid_to_query(be, obj_name, pObject, vec); +} /* ================================================================= */ void gnc_order_sql_initialize (void) @@ -233,6 +235,5 @@ gnc_order_sql_initialize (void) }; gnc_sql_register_backend(&be_data); - gnc_sql_register_col_type_handler (CT_ORDERREF, &order_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-owner-sql.cpp b/src/backend/sql/gnc-owner-sql.cpp index acdb4f0d3f..0e354f9282 100644 --- a/src/backend/sql/gnc-owner-sql.cpp +++ b/src/backend/sql/gnc-owner-sql.cpp @@ -41,17 +41,17 @@ extern "C" #include "gncVendorP.h" } #include "gnc-backend-sql.h" -#include "gnc-owner-sql.h" static QofLogModule log_module = G_LOG_DOMAIN; typedef void (*OwnerSetterFunc) (gpointer, GncOwner*); typedef GncOwner* (*OwnerGetterFunc) (const gpointer); -static void -load_owner (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { GncOwnerType type; GncGUID guid; @@ -62,14 +62,12 @@ load_owner (const GncSqlBackend* be, GncSqlRow& row, g_return_if_fail (pObject != NULL); auto book = be->book; - auto buf = g_strdup_printf ("%s_type", table_row.col_name); + auto buf = std::string{m_col_name} + "_type"; try { - type = static_cast(row.get_int_at_col (buf)); - g_free (buf); - buf = g_strdup_printf ("%s_guid", table_row.col_name); - auto val = row.get_string_at_col (buf); - g_free (buf); + type = static_cast(row.get_int_at_col (buf.c_str())); + buf = std::string{m_col_name} + "_guid"; + auto val = row.get_string_at_col (buf.c_str()); string_to_guid (val.c_str(), &guid); pGuid = &guid; } @@ -151,56 +149,44 @@ load_owner (const GncSqlBackend* be, GncSqlRow& row, default: PWARN ("Invalid owner type: %d\n", type); } - set_parameter (pObject, &owner, setter, table_row.gobj_param_name); + set_parameter (pObject, &owner, get_setter(obj_name), m_gobj_param_name); } -static void -add_owner_col_info_to_list(const GncSqlBackend* be, - const GncSqlColumnTableEntry& table_row, - ColVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept { - gchar* buf; - g_return_if_fail (be != NULL); - buf = g_strdup_printf ("%s_type", table_row.col_name); + auto buf = g_strdup_printf ("%s_type", m_col_name); GncSqlColumnInfo info(buf, BCT_INT, 0, false, false, - table_row.flags & COL_PKEY, - table_row.flags & COL_NNUL); + m_flags & COL_PKEY, m_flags & COL_NNUL); vec.emplace_back(std::move(info)); - - buf = g_strdup_printf ("%s_guid", table_row.col_name); - GncSqlColumnInfo info2(buf, BCT_STRING, GUID_ENCODING_LENGTH, - false, false, - table_row.flags & COL_PKEY, - table_row.flags & COL_NNUL); +/* Buf isn't leaking, it belongs to ColVec now. */ + buf = g_strdup_printf ("%s_guid", m_col_name); + GncSqlColumnInfo info2(buf, BCT_STRING, GUID_ENCODING_LENGTH, false, false, + m_flags & COL_PKEY, m_flags & COL_NNUL); vec.emplace_back(std::move(info2)); } -static void -add_value_owner_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, - const gpointer pObject, - const GncSqlColumnTableEntry& table_row, - PairVec& vec) +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept { g_return_if_fail (be != NULL); g_return_if_fail (obj_name != NULL); g_return_if_fail (pObject != NULL); - auto getter = (OwnerGetterFunc)gnc_sql_get_getter (obj_name, table_row); + auto getter = (OwnerGetterFunc)get_getter (obj_name); auto owner = (*getter) (pObject); QofInstance* inst = nullptr; GncOwnerType type; - std::ostringstream buf; - - buf << table_row.col_name << "_type"; - std::string type_hdr{buf.str()}; - buf.str(""); - buf << table_row.col_name << "_guid"; - std::string guid_hdr{buf.str()}; - buf.str(""); + auto type_hdr = std::string{m_col_name} + "_type"; + auto guid_hdr = std::string{m_col_name} + "_guid"; if (owner != nullptr) { @@ -236,6 +222,8 @@ add_value_owner_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, return; } + std::ostringstream buf; + buf << type; vec.emplace_back(std::make_pair(type_hdr, buf.str())); buf.str(""); @@ -246,17 +234,3 @@ add_value_owner_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name, buf << "NULL"; vec.emplace_back(std::make_pair(guid_hdr, buf.str())); } - -static GncSqlColumnTypeHandler owner_handler -= { load_owner, - add_owner_col_info_to_list, - add_value_owner_to_vec - }; - -/* ================================================================= */ -void -gnc_owner_sql_initialize (void) -{ - gnc_sql_register_col_type_handler (CT_OWNERREF, &owner_handler); -} -/* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-owner-sql.h b/src/backend/sql/gnc-owner-sql.h deleted file mode 100644 index 2c50115089..0000000000 --- a/src/backend/sql/gnc-owner-sql.h +++ /dev/null @@ -1,34 +0,0 @@ -/* gnc-owner-sql.h -- Owner SQL header - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, contact: - * - * Free Software Foundation Voice: +1-617-542-5942 - * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 - * Boston, MA 02110-1301, USA gnu@gnu.org - */ - -/** @file gnc-owner-sql.h - * @brief load and save owner data to SQL - * @author Copyright (c) 2007-2008 Phil Longstaff - * - * This file implements the top-level QofBackend API for saving/ - * restoring data to/from an SQL database - */ - -#ifndef GNC_OWNER_SQL_H -#define GNC_OWNER_SQL_H - -void gnc_owner_sql_initialize (void); - -#endif /* GNC_OWNER_SQL_H */ diff --git a/src/backend/sql/gnc-price-sql.cpp b/src/backend/sql/gnc-price-sql.cpp index 39aa55303a..bea1c510da 100644 --- a/src/backend/sql/gnc-price-sql.cpp +++ b/src/backend/sql/gnc-price-sql.cpp @@ -55,13 +55,16 @@ static QofLogModule log_module = G_LOG_DOMAIN; static const EntryVec col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "commodity_guid", CT_COMMODITYREF, 0, COL_NNUL, "commodity" }, - { "currency_guid", CT_COMMODITYREF, 0, COL_NNUL, "currency" }, - { "date", CT_TIMESPEC, 0, COL_NNUL, "date" }, - { "source", CT_STRING, PRICE_MAX_SOURCE_LEN, 0, "source" }, - { "type", CT_STRING, PRICE_MAX_TYPE_LEN, 0, "type" }, - { "value", CT_NUMERIC, 0, COL_NNUL, "value" } + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("commodity_guid", 0, COL_NNUL, + "commodity"), + gnc_sql_make_table_entry("currency_guid", 0, COL_NNUL, + "currency"), + gnc_sql_make_table_entry("date", 0, COL_NNUL, "date"), + gnc_sql_make_table_entry("source", PRICE_MAX_SOURCE_LEN, 0, + "source"), + gnc_sql_make_table_entry("type", PRICE_MAX_TYPE_LEN, 0, "type"), + gnc_sql_make_table_entry("value", 0, COL_NNUL, "value") }); /* ================================================================= */ diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index d1ecc76272..c56f560a27 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -71,45 +71,42 @@ static void set_recurrence_period_start (gpointer pObject, gpointer pValue); static const EntryVec col_table ({ - { "id", CT_INT, 0, COL_PKEY | COL_NNUL | COL_AUTOINC }, - { - "obj_guid", CT_GUID, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_obj_guid, (QofSetterFunc)set_obj_guid - }, - { - "recurrence_mult", CT_INT, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_recurrence_mult, (QofSetterFunc)set_recurrence_mult - }, - { - "recurrence_period_type", CT_STRING, BUDGET_MAX_RECURRENCE_PERIOD_TYPE_LEN, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_recurrence_period_type, set_recurrence_period_type - }, - { - "recurrence_period_start", CT_GDATE, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_recurrence_period_start, set_recurrence_period_start - }, - { - "recurrence_weekend_adjust", CT_STRING, BUDGET_MAX_RECURRENCE_WEEKEND_ADJUST_LEN, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_recurrence_weekend_adjust, set_recurrence_weekend_adjust - } + gnc_sql_make_table_entry( + "id", 0, COL_PKEY | COL_NNUL | COL_AUTOINC), + gnc_sql_make_table_entry("obj_guid", 0, COL_NNUL, + (QofAccessFunc)get_obj_guid, (QofSetterFunc)set_obj_guid), + gnc_sql_make_table_entry( + "recurrence_mult", 0, COL_NNUL, + (QofAccessFunc)get_recurrence_mult, (QofSetterFunc)set_recurrence_mult), + gnc_sql_make_table_entry( + "recurrence_period_type", BUDGET_MAX_RECURRENCE_PERIOD_TYPE_LEN, + COL_NNUL, + (QofAccessFunc)get_recurrence_period_type, set_recurrence_period_type), + gnc_sql_make_table_entry( + "recurrence_period_start", 0, COL_NNUL, + (QofAccessFunc)get_recurrence_period_start, + set_recurrence_period_start), + gnc_sql_make_table_entry( + "recurrence_weekend_adjust", BUDGET_MAX_RECURRENCE_WEEKEND_ADJUST_LEN, + COL_NNUL, + (QofAccessFunc)get_recurrence_weekend_adjust, + set_recurrence_weekend_adjust) }); /* Special column table because we need to be able to access the table by a column other than the primary key */ static const EntryVec guid_col_table ({ - { - "obj_guid", CT_GUID, 0, 0, NULL, NULL, - (QofAccessFunc)get_obj_guid, (QofSetterFunc)set_obj_guid - } + gnc_sql_make_table_entry("obj_guid", 0, 0, + (QofAccessFunc)get_obj_guid, + (QofSetterFunc)set_obj_guid) }); /* Special column table used to upgrade table from version 1 to 2 */ static const EntryVec weekend_adjust_col_table ({ - { - "recurrence_weekend_adjust", CT_STRING, BUDGET_MAX_RECURRENCE_WEEKEND_ADJUST_LEN, 0, - } + gnc_sql_make_table_entry( + "recurrence_weekend_adjust", BUDGET_MAX_RECURRENCE_WEEKEND_ADJUST_LEN, 0) }); /* ================================================================= */ @@ -380,7 +377,7 @@ upgrade_recurrence_table_1_2 (GncSqlBackend* be) gchar* weekend_adj_str = recurrenceWeekendAdjustToString (WEEKEND_ADJ_NONE); gchar* update_query = g_strdup_printf ("UPDATE %s SET %s = '%s';", TABLE_NAME, - weekend_adjust_col_table[0].col_name, + weekend_adjust_col_table[0]->name(), weekend_adj_str); (void)gnc_sql_execute_nonselect_sql (be, update_query); g_free (weekend_adj_str); diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index cbabe60ed9..0f2fe6f4be 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -57,20 +57,28 @@ G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN; static const EntryVec col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "name", CT_STRING, SX_MAX_NAME_LEN, 0, "name" }, - { "enabled", CT_BOOLEAN, 0, COL_NNUL, "enabled" }, - { "start_date", CT_GDATE, 0, 0, "start-date" }, - { "end_date", CT_GDATE, 0, 0, "end-date" }, - { "last_occur", CT_GDATE, 0, 0, "last-occurance-date" }, - { "num_occur", CT_INT, 0, COL_NNUL, "num-occurance" }, - { "rem_occur", CT_INT, 0, COL_NNUL, "rem-occurance" }, - { "auto_create", CT_BOOLEAN, 0, COL_NNUL, "auto-create" }, - { "auto_notify", CT_BOOLEAN, 0, COL_NNUL, "auto-create-notify" }, - { "adv_creation", CT_INT, 0, COL_NNUL, "advance-creation-days" }, - { "adv_notify", CT_INT, 0, COL_NNUL, "advance-reminder-days" }, - { "instance_count", CT_INT, 0, COL_NNUL, "instance-count" }, - { "template_act_guid", CT_ACCOUNTREF, 0, COL_NNUL, "template-account" }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("name", SX_MAX_NAME_LEN, 0, "name"), + gnc_sql_make_table_entry("enabled", 0, COL_NNUL, "enabled"), + gnc_sql_make_table_entry("start_date", 0, 0, "start-date"), + gnc_sql_make_table_entry("end_date", 0, 0, "end-date"), + gnc_sql_make_table_entry( + "last_occur", 0, 0, "last-occurance-date"), + gnc_sql_make_table_entry( + "num_occur", 0, COL_NNUL, "num-occurance"), + gnc_sql_make_table_entry("rem_occur", 0, COL_NNUL, "rem-occurance"), + gnc_sql_make_table_entry( + "auto_create", 0, COL_NNUL, "auto-create"), + gnc_sql_make_table_entry( + "auto_notify", 0, COL_NNUL, "auto-create-notify"), + gnc_sql_make_table_entry( + "adv_creation", 0, COL_NNUL, "advance-creation-days"), + gnc_sql_make_table_entry( + "adv_notify", 0, COL_NNUL, "advance-reminder-days"), + gnc_sql_make_table_entry( + "instance_count", 0, COL_NNUL, "instance-count"), + gnc_sql_make_table_entry( + "template_act_guid", 0, COL_NNUL, "template-account"), }); /* ================================================================= */ diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index 4d0bb693f4..e6b159ec11 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -113,59 +113,51 @@ enum static const EntryVec col_table { /* col_name, col_type, size, flags, g0bj_param_name, qof_param_name, getter, setter */ - { "id", CT_INT, 0, COL_PKEY | COL_NNUL | COL_AUTOINC }, - { - "obj_guid", CT_GUID, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_obj_guid, (QofSetterFunc)set_obj_guid - }, - { - "name", CT_STRING, SLOT_MAX_PATHNAME_LEN, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_path, set_path - }, - { - "slot_type", CT_INT, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_slot_type, set_slot_type, - }, - { - "int64_val", CT_INT64, 0, 0, NULL, NULL, - (QofAccessFunc)get_int64_val, (QofSetterFunc)set_int64_val - }, - { - "string_val", CT_STRING, SLOT_MAX_PATHNAME_LEN, 0, NULL, NULL, - (QofAccessFunc)get_string_val, set_string_val - }, - { - "double_val", CT_DOUBLE, 0, 0, NULL, NULL, - (QofAccessFunc)get_double_val, set_double_val - }, - { - "timespec_val", CT_TIMESPEC, 0, 0, NULL, NULL, - (QofAccessFunc)get_timespec_val, (QofSetterFunc)set_timespec_val - }, - { - "guid_val", CT_GUID, 0, 0, NULL, NULL, - (QofAccessFunc)get_guid_val, set_guid_val - }, - { - "numeric_val", CT_NUMERIC, 0, 0, NULL, NULL, - (QofAccessFunc)get_numeric_val, (QofSetterFunc)set_numeric_val - }, - { - "gdate_val", CT_GDATE, 0, 0, NULL, NULL, - (QofAccessFunc)get_gdate_val, (QofSetterFunc)set_gdate_val - }, + gnc_sql_make_table_entry( + "id", 0, COL_PKEY | COL_NNUL | COL_AUTOINC), + gnc_sql_make_table_entry("obj_guid", 0, COL_NNUL, + (QofAccessFunc)get_obj_guid, + (QofSetterFunc)set_obj_guid), + gnc_sql_make_table_entry("name", SLOT_MAX_PATHNAME_LEN, COL_NNUL, + (QofAccessFunc)get_path, set_path), + gnc_sql_make_table_entry("slot_type", 0, COL_NNUL, + (QofAccessFunc)get_slot_type, + set_slot_type), + gnc_sql_make_table_entry("int64_val", 0, 0, + (QofAccessFunc)get_int64_val, + (QofSetterFunc)set_int64_val), + gnc_sql_make_table_entry("string_val", SLOT_MAX_PATHNAME_LEN, 0, + (QofAccessFunc)get_string_val, + set_string_val), + gnc_sql_make_table_entry("double_val", 0, 0, + (QofAccessFunc)get_double_val, + set_double_val), + gnc_sql_make_table_entry("timespec_val", 0, 0, + (QofAccessFunc)get_timespec_val, + (QofSetterFunc)set_timespec_val), + gnc_sql_make_table_entry("guid_val", 0, 0, + (QofAccessFunc)get_guid_val, + set_guid_val), + gnc_sql_make_table_entry("numeric_val", 0, 0, + (QofAccessFunc)get_numeric_val, + (QofSetterFunc)set_numeric_val), + gnc_sql_make_table_entry("gdate_val", 0, 0, + (QofAccessFunc)get_gdate_val, + (QofSetterFunc)set_gdate_val), }; /* Special column table because we need to be able to access the table by a column other than the primary key */ static const EntryVec obj_guid_col_table { - { "obj_guid", CT_GUID, 0, 0, NULL, NULL, (QofAccessFunc)get_obj_guid, _retrieve_guid_ }, + gnc_sql_make_table_entry("obj_guid", 0, 0, + (QofAccessFunc)get_obj_guid, + _retrieve_guid_), }; static const EntryVec gdate_col_table { - { "gdate_val", CT_GDATE, 0, 0, }, + gnc_sql_make_table_entry("gdate_val", 0, 0), }; /* ================================================================= */ @@ -745,10 +737,10 @@ gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid) { try { - const GncSqlColumnTableEntry& table_row = + const GncSqlColumnTableEntryPtr table_row = col_table[guid_val_col]; GncGUID child_guid; - auto val = row.get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (table_row->name()); (void)string_to_guid (val.c_str(), &child_guid); gnc_sql_slots_delete (be, &child_guid); } @@ -901,7 +893,7 @@ gnc_sql_slots_load_for_list (GncSqlBackend* be, GList* list) sql = g_string_sized_new (40 + (GUID_ENCODING_LENGTH + 3) * g_list_length ( list)); g_string_append_printf (sql, "SELECT * FROM %s WHERE %s ", TABLE_NAME, - obj_guid_col_table[0].col_name); + obj_guid_col_table[0]->name()); if (g_list_length (list) != 1) { (void)g_string_append (sql, "IN ("); @@ -983,7 +975,7 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be, if (subquery == NULL) return; sql = g_strdup_printf ("SELECT * FROM %s WHERE %s IN (%s)", - TABLE_NAME, obj_guid_col_table[0].col_name, + TABLE_NAME, obj_guid_col_table[0]->name(), subquery); // Execute the query and load the slots diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index 4cf03ad4d2..577eef06a3 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -67,21 +67,21 @@ static void tt_set_parent_guid (gpointer pObject, gpointer pValue); static EntryVec tt_col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" }, - { "refcount", CT_INT64, 0, COL_NNUL, "ref-count" }, - { "invisible", CT_BOOLEAN, 0, COL_NNUL, "invisible" }, - /* { "child", CT_TAXTABLEREF, 0, 0, NULL, NULL, - get_child, (QofSetterFunc)gncTaxTableSetChild }, */ - { - "parent", CT_GUID, 0, 0, NULL, NULL, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid" ), + gnc_sql_make_table_entry("name", MAX_NAME_LEN, COL_NNUL, "name" ), + gnc_sql_make_table_entry("refcount", 0, COL_NNUL, "ref-count" ), + gnc_sql_make_table_entry("invisible", 0, COL_NNUL, "invisible" ), + /* gnc_sql_make_table_entry("child", 0, 0, + get_child, (QofSetterFunc)gncTaxTableSetChild ), */ + gnc_sql_make_table_entry("parent", 0, 0, (QofAccessFunc)bt_get_parent, tt_set_parent - }, + ), }); static EntryVec tt_parent_col_table ({ - { "parent", CT_GUID, 0, 0, NULL, NULL, NULL, tt_set_parent_guid }, + gnc_sql_make_table_entry("parent", 0, 0, nullptr, + tt_set_parent_guid ), }); #define TTENTRIES_TABLE_NAME "taxtable_entries" @@ -89,30 +89,28 @@ static EntryVec tt_parent_col_table static EntryVec ttentries_col_table ({ - { "id", CT_INT, 0, COL_PKEY | COL_NNUL | COL_AUTOINC }, - { - "taxtable", CT_TAXTABLEREF, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)gncTaxTableEntryGetTable, set_obj_guid - }, - { - "account", CT_ACCOUNTREF, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)gncTaxTableEntryGetAccount, (QofSetterFunc)gncTaxTableEntrySetAccount - }, - { - "amount", CT_NUMERIC, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)gncTaxTableEntryGetAmount, (QofSetterFunc)gncTaxTableEntrySetAmount - }, - { - "type", CT_INT, 0, COL_NNUL, NULL, NULL, - (QofAccessFunc)gncTaxTableEntryGetType, (QofSetterFunc)gncTaxTableEntrySetType - }, + gnc_sql_make_table_entry( + "id", 0, COL_PKEY | COL_NNUL | COL_AUTOINC), + gnc_sql_make_table_entry("taxtable", 0, COL_NNUL, + (QofAccessFunc)gncTaxTableEntryGetTable, + set_obj_guid), + gnc_sql_make_table_entry("account", 0, COL_NNUL, + (QofAccessFunc)gncTaxTableEntryGetAccount, + (QofSetterFunc)gncTaxTableEntrySetAccount), + gnc_sql_make_table_entry("amount", 0, COL_NNUL, + (QofAccessFunc)gncTaxTableEntryGetAmount, + (QofSetterFunc)gncTaxTableEntrySetAmount), + gnc_sql_make_table_entry("type", 0, COL_NNUL, + (QofAccessFunc)gncTaxTableEntryGetType, + (QofSetterFunc)gncTaxTableEntrySetType), }); /* Special column table because we need to be able to access the table by a column other than the primary key */ static EntryVec guid_col_table ({ - { "taxtable", CT_GUID, 0, 0, NULL, NULL, get_obj_guid, set_obj_guid }, + gnc_sql_make_table_entry("taxtable", 0, 0, + get_obj_guid, set_obj_guid), }); typedef struct @@ -481,36 +479,34 @@ write_taxtables (GncSqlBackend* be) } /* ================================================================= */ -static void -load_taxtable_guid (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { - GncGUID guid; - GncTaxTable* taxtable = NULL; - - g_return_if_fail (be != NULL); - g_return_if_fail (pObject != NULL); - - try - { - auto val = row.get_string_at_col (table_row.col_name); - string_to_guid (val.c_str(), &guid); - taxtable = gncTaxTableLookup (be->book, &guid); - if (taxtable != nullptr) - set_parameter (pObject, taxtable, setter, - table_row.gobj_param_name); - else - PWARN ("Taxtable ref '%s' not found", val.c_str()); - } - catch (std::invalid_argument) {} + load_from_guid_ref(row, obj_name, pObject, + [be](GncGUID* g){ + return gncTaxTableLookup(be->book, g); + }); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept +{ + add_objectref_guid_to_table(be, vec); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept +{ + add_objectref_guid_to_query(be, obj_name, pObject, vec); } -static GncSqlColumnTypeHandler taxtable_guid_handler -= { load_taxtable_guid, - gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_objectref_guid_to_vec - }; /* ================================================================= */ void gnc_taxtable_sql_initialize (void) @@ -527,6 +523,5 @@ gnc_taxtable_sql_initialize (void) }; gnc_sql_register_backend(&be_data); - gnc_sql_register_col_type_handler (CT_TAXTABLEREF, &taxtable_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index 055561554f..5baedef493 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -78,12 +78,14 @@ typedef struct static const EntryVec tx_col_table { - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "currency_guid", CT_COMMODITYREF, 0, COL_NNUL, "currency" }, - { "num", CT_STRING, TX_MAX_NUM_LEN, COL_NNUL, "num" }, - { "post_date", CT_TIMESPEC, 0, 0, "post-date" }, - { "enter_date", CT_TIMESPEC, 0, 0, "enter-date" }, - { "description", CT_STRING, TX_MAX_DESCRIPTION_LEN, 0, "description" }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("currency_guid", 0, COL_NNUL, + "currency"), + gnc_sql_make_table_entry("num", TX_MAX_NUM_LEN, COL_NNUL, "num"), + gnc_sql_make_table_entry("post_date", 0, 0, "post-date"), + gnc_sql_make_table_entry("enter_date", 0, 0, "enter-date"), + gnc_sql_make_table_entry("description", TX_MAX_DESCRIPTION_LEN, + 0, "description"), }; static gpointer get_split_reconcile_state (gpointer pObject); @@ -95,37 +97,40 @@ static void set_split_lot (gpointer pObject, gpointer pLot); static const EntryVec split_col_table { - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "tx_guid", CT_TXREF, 0, COL_NNUL, "transaction" }, - { "account_guid", CT_ACCOUNTREF, 0, COL_NNUL, "account" }, - { "memo", CT_STRING, SPLIT_MAX_MEMO_LEN, COL_NNUL, "memo" }, - { "action", CT_STRING, SPLIT_MAX_ACTION_LEN, COL_NNUL, "action" }, - { - "reconcile_state", CT_STRING, 1, COL_NNUL, NULL, NULL, - (QofAccessFunc)get_split_reconcile_state, set_split_reconcile_state - }, - { "reconcile_date", CT_TIMESPEC, 0, 0, "reconcile-date" }, - { "value", CT_NUMERIC, 0, COL_NNUL, "value" }, - { "quantity", CT_NUMERIC, 0, COL_NNUL, "amount" }, - { - "lot_guid", CT_LOTREF, 0, 0, NULL, NULL, - (QofAccessFunc)xaccSplitGetLot, set_split_lot - }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("tx_guid", 0, COL_NNUL, "transaction"), + gnc_sql_make_table_entry("account_guid", 0, COL_NNUL, + "account"), + gnc_sql_make_table_entry("memo", SPLIT_MAX_MEMO_LEN, COL_NNUL, + "memo"), + gnc_sql_make_table_entry("action", SPLIT_MAX_ACTION_LEN, + COL_NNUL, "action"), + gnc_sql_make_table_entry("reconcile_state", 1, COL_NNUL, + (QofAccessFunc)get_split_reconcile_state, + set_split_reconcile_state), + gnc_sql_make_table_entry("reconcile_date", 0, 0, + "reconcile-date"), + gnc_sql_make_table_entry("value", 0, COL_NNUL, "value"), + gnc_sql_make_table_entry("quantity", 0, COL_NNUL, "amount"), + gnc_sql_make_table_entry("lot_guid", 0, 0, + (QofAccessFunc)xaccSplitGetLot, + set_split_lot), }; static const EntryVec post_date_col_table { - { "post_date", CT_TIMESPEC, 0, 0, "post-date" }, + gnc_sql_make_table_entry("post_date", 0, 0, "post-date"), }; static const EntryVec account_guid_col_table { - { "account_guid", CT_ACCOUNTREF, 0, COL_NNUL, "account" }, + gnc_sql_make_table_entry("account_guid", 0, COL_NNUL, + "account"), }; static const EntryVec tx_guid_col_table { - { "tx_guid", CT_GUID, 0, 0, "guid" }, + gnc_sql_make_table_entry("tx_guid", 0, 0, "guid"), }; /* ================================================================= */ @@ -232,7 +237,7 @@ load_splits_for_tx_list (GncSqlBackend* be, GList* list) sql = g_string_sized_new (40 + (GUID_ENCODING_LENGTH + 3) * g_list_length ( list)); g_string_append_printf (sql, "SELECT * FROM %s WHERE %s IN (", SPLIT_TABLE, - tx_guid_col_table[0].col_name); + tx_guid_col_table[0]->name()); (void)gnc_sql_append_guid_list_to_sql (sql, list, G_MAXUINT); (void)g_string_append (sql, ")"); @@ -1301,9 +1306,12 @@ set_acct_bal_balance (gpointer pObject, gnc_numeric value) static const EntryVec acct_balances_col_table { - { "account_guid", CT_GUID, 0, 0, NULL, NULL, NULL, (QofSetterFunc)set_acct_bal_account_from_guid }, - { "reconcile_state", CT_STRING, 1, 0, NULL, NULL, NULL, (QofSetterFunc)set_acct_bal_reconcile_state }, - { "quantity", CT_NUMERIC, 0, 0, NULL, NULL, NULL, (QofSetterFunc)set_acct_bal_balance }, + gnc_sql_make_table_entry("account_guid", 0, 0, nullptr, + (QofSetterFunc)set_acct_bal_account_from_guid), + gnc_sql_make_table_entry("reconcile_state", 1, 0, nullptr, + (QofSetterFunc)set_acct_bal_reconcile_state), + gnc_sql_make_table_entry("quantity", 0, 0, nullptr, + (QofSetterFunc)set_acct_bal_balance), }; G_GNUC_UNUSED static single_acct_balance_t* @@ -1408,13 +1416,12 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be) } /* ----------------------------------------------------------------- */ -static void -load_tx_guid (const GncSqlBackend* be, GncSqlRow& row, - QofSetterFunc setter, gpointer pObject, - const GncSqlColumnTableEntry& table_row) +template<> void +GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, + GncSqlRow& row, + QofIdTypeConst obj_name, + gpointer pObject) const noexcept { - GncGUID guid; - Transaction* tx; const gchar* guid_str; g_return_if_fail (be != NULL); @@ -1422,35 +1429,44 @@ load_tx_guid (const GncSqlBackend* be, GncSqlRow& row, try { - auto val = row.get_string_at_col (table_row.col_name); + auto val = row.get_string_at_col (m_col_name); + GncGUID guid; (void)string_to_guid (val.c_str(), &guid); - tx = xaccTransLookup (&guid, be->book); + auto tx = xaccTransLookup (&guid, be->book); // If the transaction is not found, try loading it - if (tx == NULL) + if (tx == nullptr) { - gchar* buf; - GncSqlStatement* stmt; - - buf = g_strdup_printf ("SELECT * FROM %s WHERE guid='%s'", - TRANSACTION_TABLE, val.c_str()); - stmt = gnc_sql_create_statement_from_sql ((GncSqlBackend*)be, buf); - g_free (buf); + auto buf = std::string{"SELECT * FROM "} + TRANSACTION_TABLE + + " WHERE guid='" + val + "'"; + auto stmt = gnc_sql_create_statement_from_sql ((GncSqlBackend*)be, + buf.c_str()); query_transactions ((GncSqlBackend*)be, stmt); tx = xaccTransLookup (&guid, be->book); } if (tx != nullptr) - set_parameter (pObject, tx, setter, table_row.gobj_param_name); + set_parameter (pObject, tx, get_setter(obj_name), m_gobj_param_name); } catch (std::invalid_argument) {} } -static GncSqlColumnTypeHandler tx_guid_handler -= { load_tx_guid, - gnc_sql_add_objectref_guid_col_info_to_list, - gnc_sql_add_objectref_guid_to_vec - }; +template<> void +GncSqlColumnTableEntryImpl::add_to_table(const GncSqlBackend* be, + ColVec& vec) const noexcept +{ + add_objectref_guid_to_table(be, vec); +} + +template<> void +GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, + QofIdTypeConst obj_name, + const gpointer pObject, + PairVec& vec) const noexcept +{ + add_objectref_guid_to_query(be, obj_name, pObject, vec); +} + /* ================================================================= */ void gnc_sql_init_transaction_handler (void) @@ -1492,7 +1508,6 @@ gnc_sql_init_transaction_handler (void) gnc_sql_register_backend(&be_data_tx); gnc_sql_register_backend(&be_data_split); - gnc_sql_register_col_type_handler (CT_TXREF, &tx_guid_handler); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index f4625894d6..0caf56a3c9 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -42,7 +42,6 @@ extern "C" } #include "gnc-vendor-sql.h" -#include "gnc-address-sql.h" #include "gnc-bill-term-sql.h" #include "gnc-tax-table-sql.h" #include "gnc-backend-sql.h" @@ -63,17 +62,21 @@ G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN; static EntryVec col_table ({ - { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" }, - { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" }, - { "id", CT_STRING, MAX_ID_LEN, COL_NNUL, "id" }, - { "notes", CT_STRING, MAX_NOTES_LEN, COL_NNUL, "notes" }, - { "currency", CT_COMMODITYREF, 0, COL_NNUL, "currency" }, - { "active", CT_BOOLEAN, 0, COL_NNUL, "active" }, - { "tax_override", CT_BOOLEAN, 0, COL_NNUL, "tax-table-override" }, - { "addr", CT_ADDRESS, 0, 0, "address" }, - { "terms", CT_BILLTERMREF, 0, 0, "terms" }, - { "tax_inc", CT_STRING, MAX_TAX_INC_LEN, 0, "tax-included-string" }, - { "tax_table", CT_TAXTABLEREF, 0, 0, "tax-table" }, + gnc_sql_make_table_entry("guid", 0, COL_NNUL | COL_PKEY, "guid"), + gnc_sql_make_table_entry("name", MAX_NAME_LEN, COL_NNUL, "name"), + gnc_sql_make_table_entry("id", MAX_ID_LEN, COL_NNUL, "id"), + gnc_sql_make_table_entry("notes", MAX_NOTES_LEN, COL_NNUL, + "notes"), + gnc_sql_make_table_entry("currency", 0, COL_NNUL, + "currency"), + gnc_sql_make_table_entry("active", 0, COL_NNUL, "active"), + gnc_sql_make_table_entry("tax_override", 0, COL_NNUL, + "tax-table-override"), + gnc_sql_make_table_entry("addr", 0, 0, "address"), + gnc_sql_make_table_entry("terms", 0, 0, "terms"), + gnc_sql_make_table_entry("tax_inc", MAX_TAX_INC_LEN, 0, + "tax-included-string"), + gnc_sql_make_table_entry("tax_table", 0, 0, "tax-table"), }); static GncVendor* From 92f2f2765eaa701176e11559be9b0d29f525cdbd Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 17 Jun 2016 10:28:02 -0700 Subject: [PATCH 16/63] Replace the ptr-to-func GncSqlObjectBackend struct with a class hierarchy. Can't template them because we need to iterate on the collection when loading. --- src/backend/dbi/gnc-backend-dbi.cpp | 16 +- src/backend/sql/gnc-account-sql.cpp | 50 ++--- src/backend/sql/gnc-backend-sql.cpp | 176 ++++++++---------- src/backend/sql/gnc-backend-sql.h | 129 ++++++++----- src/backend/sql/gnc-bill-term-sql.cpp | 57 +++--- src/backend/sql/gnc-bill-term-sql.h | 1 - src/backend/sql/gnc-book-sql.cpp | 61 ++---- src/backend/sql/gnc-book-sql.h | 1 - src/backend/sql/gnc-budget-sql.cpp | 52 +++--- src/backend/sql/gnc-commodity-sql.cpp | 47 ++--- src/backend/sql/gnc-customer-sql.cpp | 61 +++--- src/backend/sql/gnc-employee-sql.cpp | 44 +++-- src/backend/sql/gnc-entry-sql.cpp | 55 +++--- src/backend/sql/gnc-invoice-sql.cpp | 50 ++--- src/backend/sql/gnc-job-sql.cpp | 68 ++----- src/backend/sql/gnc-lots-sql.cpp | 58 +++--- src/backend/sql/gnc-order-sql.cpp | 66 ++----- src/backend/sql/gnc-price-sql.cpp | 59 +++--- src/backend/sql/gnc-recurrence-sql.cpp | 34 ++-- src/backend/sql/gnc-schedxaction-sql.cpp | 48 ++--- src/backend/sql/gnc-slots-sql.cpp | 38 ++-- src/backend/sql/gnc-tax-table-sql.cpp | 50 ++--- src/backend/sql/gnc-transaction-sql.cpp | 227 ++++++++--------------- src/backend/sql/gnc-transaction-sql.h | 25 --- src/backend/sql/gnc-vendor-sql.cpp | 61 +++--- 25 files changed, 640 insertions(+), 894 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 2d70f7a9fe..6aa5c0d1f2 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -294,12 +294,9 @@ create_tables(const OBEEntry& entry, GncDbiBackend* be) std::string type; GncSqlObjectBackendPtr obe = nullptr; std::tie(type, obe) = entry; - g_return_if_fail(obe->version == GNC_SQL_BACKEND_VERSION); + g_return_if_fail(obe->is_version (GNC_SQL_BACKEND_VERSION)); - if (obe->create_tables != nullptr) - { - (obe->create_tables)(&be->sql_be); - } + obe->create_tables (&be->sql_be); } static void @@ -1926,9 +1923,12 @@ init_sql_backend (GncDbiBackend* dbi_be) be->sync = gnc_dbi_safe_sync_all; be->safe_sync = gnc_dbi_safe_sync_all; - be->compile_query = gnc_sql_compile_query; - be->run_query = gnc_sql_run_query; - be->free_query = gnc_sql_free_query; +// be->compile_query = gnc_sql_compile_query; +// be->run_query = gnc_sql_run_query; +// be->free_query = gnc_sql_free_query; + be->compile_query = nullptr; + be->run_query = nullptr; + be->free_query = nullptr; be->export_fn = NULL; diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index a9f3149dc6..bdb3bff121 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -91,6 +91,18 @@ static EntryVec parent_col_table "parent_guid", 0, 0, nullptr, (QofSetterFunc)set_parent_guid), }); +class GncSqlAccountBackend : public GncSqlObjectBackend +{ +public: + GncSqlAccountBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + bool commit(GncSqlBackend*, QofInstance*) override; +}; + + + typedef struct { Account* pAccount; @@ -198,8 +210,8 @@ load_single_account (GncSqlBackend* be, GncSqlRow& row, return pAccount; } -static void -load_all_accounts (GncSqlBackend* be) +void +GncSqlAccountBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt = NULL; QofBook* pBook; @@ -308,23 +320,8 @@ load_all_accounts (GncSqlBackend* be) } /* ================================================================= */ -static void -create_account_tables (GncSqlBackend* be) -{ - gint version; - - g_return_if_fail (be != NULL); - - version = gnc_sql_get_table_version (be, TABLE_NAME); - if (version == 0) - { - (void)gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); - } -} - -/* ================================================================= */ -gboolean -gnc_sql_save_account (GncSqlBackend* be, QofInstance* inst) +bool +GncSqlAccountBackend::commit (GncSqlBackend* be, QofInstance* inst) { Account* pAcc = GNC_ACCOUNT (inst); const GncGUID* guid; @@ -425,19 +422,8 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, void gnc_sql_init_account_handler (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_ACCOUNT, - gnc_sql_save_account, /* commit */ - load_all_accounts, /* initial_load */ - create_account_tables, /* create_tables */ - NULL, /* compile_query */ - NULL, /* run_query */ - NULL, /* free_query */ - NULL /* write */ - }; - + static GncSqlAccountBackend be_data{ + GNC_SQL_BACKEND_VERSION, GNC_ID_ACCOUNT, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index d03ca2983c..b4b3042293 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -136,7 +136,7 @@ gnc_sql_register_backend(OBEEntry&& entry) void gnc_sql_register_backend(GncSqlObjectBackendPtr obe) { - backend_registry.emplace_back(make_tuple(std::string{obe->type_name}, obe)); + backend_registry.emplace_back(make_tuple(std::string{obe->type()}, obe)); } const OBEVec& @@ -144,6 +144,21 @@ gnc_sql_get_backend_registry() { return backend_registry; } + +GncSqlObjectBackendPtr +gnc_sql_get_object_backend(const std::string& type) +{ + auto entry = std::find_if(backend_registry.begin(), + backend_registry.end(), + [type](const OBEEntry& entry){ + return type == std::get<0>(entry); + }); + auto obe = std::get<1>(*entry); + if (entry != backend_registry.end()) + return obe; + return nullptr; +} + void gnc_sql_init(GncSqlBackend* be) { @@ -164,13 +179,9 @@ create_tables(const OBEEntry& entry, GncSqlBackend* be) std::string type; GncSqlObjectBackendPtr obe = nullptr; std::tie(type, obe) = entry; - g_return_if_fail (obe->version == GNC_SQL_BACKEND_VERSION); - - if (obe->create_tables != nullptr) - { - update_progress(be); - (obe->create_tables)(be); - } + g_return_if_fail (obe->is_version (GNC_SQL_BACKEND_VERSION)); + update_progress(be); + obe->create_tables(be); } /* ================================================================= */ @@ -195,7 +206,7 @@ initial_load(const OBEEntry& entry, GncSqlBackend* be) std::string type; GncSqlObjectBackendPtr obe = nullptr; std::tie(type, obe) = entry; - g_return_if_fail(obe->version == GNC_SQL_BACKEND_VERSION); + g_return_if_fail(obe->is_version (GNC_SQL_BACKEND_VERSION)); /* Don't need to load anything if it has already been loaded with * the fixed order. @@ -205,8 +216,7 @@ initial_load(const OBEEntry& entry, GncSqlBackend* be) if (std::find(other_load_order.begin(), other_load_order.end(), type) != other_load_order.end()) return; - if (obe->initial_load != nullptr) - (obe->initial_load)(be); + obe->load_all (be); } void @@ -243,34 +253,20 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) /* Load any initial stuff. Some of this needs to happen in a certain order */ for (auto type : fixed_load_order) { - auto entry = std::find_if(backend_registry.begin(), - backend_registry.end(), - [type](const OBEEntry& entry){ - return type == std::get<0>(entry); - }); - auto obe = std::get<1>(*entry); - if (entry != backend_registry.end() && - obe->initial_load != nullptr) + auto obe = gnc_sql_get_object_backend(type); + if (obe) { update_progress(be); - (obe->initial_load)(be); + obe->load_all (be); } } for (auto type : other_load_order) { - auto entry = std::find_if(backend_registry.begin(), - backend_registry.end(), - [type](const OBEEntry& entry){ - return type == std::get<0>(entry); - }); - if (entry == backend_registry.end()) - continue; - auto obe = std::get<1>(*entry); - if (entry != backend_registry.end() && - obe->initial_load != nullptr) + auto obe = gnc_sql_get_object_backend(type); + if (obe) { update_progress(be); - (obe->initial_load)(be); + obe->load_all (be); } } @@ -287,7 +283,8 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) else if (loadType == LOAD_TYPE_LOAD_ALL) { // Load all transactions - gnc_sql_transaction_load_all_tx (be); + auto obe = gnc_sql_get_object_backend (GNC_ID_TRANS); + obe->load_all (be); } be->loading = FALSE; @@ -315,13 +312,14 @@ write_account_tree (GncSqlBackend* be, Account* root) g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (root != NULL, FALSE); - is_ok = gnc_sql_save_account (be, QOF_INSTANCE (root)); + auto obe = gnc_sql_get_object_backend (GNC_ID_ACCOUNT); + is_ok = obe->commit (be, QOF_INSTANCE (root)); if (is_ok) { descendants = gnc_account_get_descendants (root); for (node = descendants; node != NULL && is_ok; node = g_list_next (node)) { - is_ok = gnc_sql_save_account (be, QOF_INSTANCE (GNC_ACCOUNT (node->data))); + is_ok = obe->commit(be, QOF_INSTANCE (GNC_ACCOUNT (node->data))); if (!is_ok) break; } g_list_free (descendants); @@ -349,36 +347,34 @@ write_accounts (GncSqlBackend* be) return is_ok; } -static int +static gboolean write_tx (Transaction* tx, gpointer data) { - write_objects_t* s = (write_objects_t*)data; + auto s = static_cast(data); g_return_val_if_fail (tx != NULL, 0); g_return_val_if_fail (data != NULL, 0); - s->is_ok = gnc_sql_save_transaction (s->be, QOF_INSTANCE (tx)); + s->commit (QOF_INSTANCE (tx)); + auto splitbe = gnc_sql_get_object_backend (GNC_ID_SPLIT); + for (auto split_node = xaccTransGetSplitList (tx); + split_node != nullptr && s->is_ok; + split_node = g_list_next (split_node)) + { + s->is_ok = splitbe->commit(s->be, QOF_INSTANCE(split_node->data)); + } update_progress (s->be); - - if (s->is_ok) - { - return 0; - } - else - { - return 1; - } + return (s->is_ok ? 0 : 1); } static gboolean write_transactions (GncSqlBackend* be) { - write_objects_t data; - g_return_val_if_fail (be != NULL, FALSE); - data.be = be; - data.is_ok = TRUE; + auto obe = gnc_sql_get_object_backend(GNC_ID_TRANS); + write_objects_t data{be, true, obe}; + (void)xaccAccountTreeForEachTransaction ( gnc_book_get_root_account (be->book), write_tx, &data); update_progress (be); @@ -388,14 +384,11 @@ write_transactions (GncSqlBackend* be) static gboolean write_template_transactions (GncSqlBackend* be) { - Account* ra; - write_objects_t data; - g_return_val_if_fail (be != NULL, FALSE); - data.is_ok = TRUE; - data.be = be; - ra = gnc_book_get_template_root (be->book); + auto obe = gnc_sql_get_object_backend(GNC_ID_TRANS); + write_objects_t data{be, true, obe}; + auto ra = gnc_book_get_template_root (be->book); if (gnc_account_n_descendants (ra) > 0) { (void)xaccAccountTreeForEachTransaction (ra, write_tx, &data); @@ -415,32 +408,18 @@ write_schedXactions (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); schedXactions = gnc_book_get_schedxactions (be->book)->sx_list; + auto obe = gnc_sql_get_object_backend(GNC_ID_SCHEDXACTION); for (; schedXactions != NULL && is_ok; schedXactions = schedXactions->next) { tmpSX = static_cast (schedXactions->data); - is_ok = gnc_sql_save_schedxaction (be, QOF_INSTANCE (tmpSX)); + is_ok = obe->commit (be, QOF_INSTANCE (tmpSX)); } update_progress (be); return is_ok; } -static void -write(const OBEEntry& entry, GncSqlBackend* be) -{ - std::string type; - GncSqlObjectBackendPtr obe = nullptr; - std::tie(type, obe) = entry; - g_return_if_fail (obe->version == GNC_SQL_BACKEND_VERSION); - - if (obe->write != nullptr) - { - (void)(obe->write)(be); - update_progress(be); - } -} - static void update_progress (GncSqlBackend* be) { @@ -486,7 +465,8 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) //write_commodities( be, book ); if (is_ok) { - is_ok = gnc_sql_save_book (be, QOF_INSTANCE (book)); + auto obe = gnc_sql_get_object_backend(GNC_ID_BOOK); + is_ok = obe->commit (be, QOF_INSTANCE (book)); } if (is_ok) { @@ -507,7 +487,7 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) if (is_ok) { for (auto entry : backend_registry) - write(entry, be); + std::get<1>(entry)->write (be); } if (is_ok) { @@ -561,7 +541,7 @@ commit(const OBEEntry& entry, sql_backend* be_data) std::string type; GncSqlObjectBackendPtr obe= nullptr; std::tie(type, obe) = entry; - g_return_if_fail (obe->version == GNC_SQL_BACKEND_VERSION); + g_return_if_fail (obe->is_version (GNC_SQL_BACKEND_VERSION)); /* If this has already been handled, or is not the correct * handler, return @@ -569,11 +549,8 @@ commit(const OBEEntry& entry, sql_backend* be_data) if (type != std::string{be_data->inst->e_type}) return; if (be_data->is_known) return; - if (obe->commit != nullptr) - { - be_data->is_ok = (obe->commit)(be_data->be, be_data->inst); - be_data->is_known = TRUE; - } + be_data->is_ok = obe->commit (be_data->be, be_data->inst); + be_data->is_known = TRUE; } /* Commit_edit handler - find the correct backend handler for this object @@ -823,26 +800,23 @@ handle_and_term (QofQueryTerm* pTerm, GString* sql) g_string_append (sql, ")"); } - +#if 0 //The query compilation code was never tested so it isn't implemnted for GncSqlObjectBackend. static void compile_query(const OBEEntry& entry, sql_backend* be_data) { std::string type; GncSqlObjectBackendPtr obe = nullptr; std::tie(type, obe) = entry; - g_return_if_fail (obe->version == GNC_SQL_BACKEND_VERSION); + g_return_if_fail (obe->is_version (GNC_SQL_BACKEND_VERSION)); // Is this the right item? if (type != std::string{be_data->pQueryInfo->searchObj}) return; if (be_data->is_ok) return; - if (obe->compile_query != nullptr) - { - be_data->pQueryInfo->pCompiledQuery = (obe->compile_query)( - be_data->be, - be_data->pQuery); - be_data->is_ok = TRUE; - } + be_data->pQueryInfo->pCompiledQuery = (obe->compile_query)( + be_data->be, + be_data->pQuery); + be_data->is_ok = TRUE; } gchar* gnc_sql_compile_query_to_sql (GncSqlBackend* be, QofQuery* query); @@ -1052,7 +1026,7 @@ gnc_sql_run_query (QofBackend* pBEnd, gpointer pQuery) LEAVE (""); } - +#endif //if 0: query creation isn't used yet, code never tested. /* ================================================================= */ /* Order in which business objects need to be loaded */ static const StrVec business_fixed_load_order = @@ -2199,10 +2173,8 @@ build_delete_statement (GncSqlBackend* be, } /* ================================================================= */ -gboolean -gnc_sql_commit_standard_item (GncSqlBackend* be, QofInstance* inst, - const gchar* tableName, QofIdTypeConst obj_name, - const EntryVec& col_table) +bool +GncSqlObjectBackend::commit (GncSqlBackend* be, QofInstance* inst) { const GncGUID* guid; gboolean is_infant; @@ -2222,7 +2194,8 @@ gnc_sql_commit_standard_item (GncSqlBackend* be, QofInstance* inst, { op = OP_DB_UPDATE; } - is_ok = gnc_sql_do_db_operation (be, op, tableName, obj_name, inst, col_table); + is_ok = gnc_sql_do_db_operation (be, op, m_table_name.c_str(), + m_type_name.c_str(), inst, m_col_table); if (is_ok) { @@ -2280,6 +2253,19 @@ gnc_sql_create_table (GncSqlBackend* be, const char* table_name, return ok; } +void +GncSqlObjectBackend::create_tables (GncSqlBackend* be) +{ + g_return_if_fail (be != nullptr); + int version = gnc_sql_get_table_version (be, m_table_name.c_str()); + if (version == 0) //No tables, otherwise version will be >= 1. + gnc_sql_create_table (be, m_table_name.c_str(), + m_version, m_col_table); + else if (version != m_version) + PERR("Version mismatch in table %s, expecting %d but backend is %d." + "Table creation aborted.", m_table_name.c_str(), m_version, version); +} + gboolean gnc_sql_create_temp_table (const GncSqlBackend* be, const gchar* table_name, const EntryVec& col_table) diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 5cb0279ab8..78fc33961f 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -282,51 +282,100 @@ inline bool operator==(const GncSqlRow& lr, const GncSqlRow& rr) { return !(lr != rr); } -/** - * @struct GncSqlObjectBackend - * - * Struct used to handle a specific engine object type for an SQL backend. - * This handler should be registered with gnc_sql_register_backend(). - * - * commit() - commit an object to the db - * initial_load() - load stuff when new db opened - * create_tables() - create any db tables - * compile_query() - compile a backend object query - * run_query() - run a compiled query - * free_query() - free a compiled query - * write() - write all objects - */ -typedef struct -{ - int version; /**< Backend version number */ - const std::string type_name; /**< Engine object type name */ - /** Commit an instance of this object to the database - * @return TRUE if successful, FALSE if error - */ - gboolean (*commit) (GncSqlBackend* be, QofInstance* inst); - /** Load all objects of this type from the database */ - void (*initial_load) (GncSqlBackend* be); - /** Create database tables for this object */ - void (*create_tables) (GncSqlBackend* be); - /** Compile a query on these objects */ - gpointer (*compile_query) (GncSqlBackend* be, QofQuery* pQuery); - /** Run a query on these objects */ - void (*run_query) (GncSqlBackend* be, gpointer pQuery); - /** Free a query on these objects */ - void (*free_query) (GncSqlBackend* be, gpointer pQuery); - /** Write all objects of this type to the database - * @return TRUE if successful, FALSE if error - */ - gboolean (*write) (GncSqlBackend* be); -} GncSqlObjectBackend; #define GNC_SQL_BACKEND "gnc:sql:1" #define GNC_SQL_BACKEND_VERSION 1 + +/** + * Encapsulates per-class table schema with functions to load, create a table, + * commit a changed front-end object (note that database transaction semantics + * are not yet implemented; edit/commit applies to the front-end object!) and + * write all front-end objects of the type to the database. Additional functions + * for creating and runing queries existed but were unused and untested. They've + * been temporarily removed until the front end is ready to use them. + */ +class GncSqlObjectBackend +{ +public: + GncSqlObjectBackend (int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + m_table_name{table}, m_version{version}, m_type_name{type}, + m_col_table{vec} {} + /** + * Load all objects of m_type in the database into memory. + * @param be The GncSqlBackend containing the database connection. + */ + virtual void load_all (GncSqlBackend*) = 0; + /** + * Conditionally create or update a database table from m_col_table. The + * condition is the version returned by querying the database's version + * table: If it's 0 then the table wasn't found and will be created; All + * tables areat least version 1. If the database's version is less than the + * compiled version then the table schema is upgraded but the data isn't, + * that's the engine's responsibility when the object is loaded. If the + * version is greater than the compiled version then nothing is touched. + * @param be The GncSqlBackend containing the database connection. + */ + virtual void create_tables (GncSqlBackend*); + /** + * UPDATE/INSERT a single instance of m_type_name into the database. + * @param be The GncSqlBackend containing the database. + * @param inst The QofInstance to be written out. + */ + virtual bool commit (GncSqlBackend* be, QofInstance* inst); + /** + * Write all objects of m_type_name to the database. + * @param be The GncSqlBackend containing the database. + * @return true if the objects were successfully written, false otherwise. + */ + virtual bool write (GncSqlBackend*) { return true; } + /** + * Return the m_type_name for the class. This value is created at + * compilation time and is called QofIdType or QofIdTypeConst in other parts + * of GnuCash. Most values are defined in src/engine/gnc-engine.h. + * @return m_type_name. + */ + const char* type () const noexcept { return m_type_name.c_str(); } + /** + * Compare a version with the compiled version (m_version). + * @return true if they match. + */ + const bool is_version (int version) const noexcept { + return version == m_version; + } +protected: + const std::string m_table_name; + const int m_version; + const std::string m_type_name; /// The front-end QofIdType + const EntryVec& m_col_table; /// The ORM table definition. +}; + using GncSqlObjectBackendPtr = GncSqlObjectBackend*; + using OBEEntry = std::tuple; using OBEVec = std::vector; void gnc_sql_register_backend(OBEEntry&&); void gnc_sql_register_backend(GncSqlObjectBackendPtr); const OBEVec& gnc_sql_get_backend_registry(); +GncSqlObjectBackendPtr gnc_sql_get_object_backend(const std::string& table_name); + +/** + * Data-passing struct for callbacks to qof_object_foreach() used in + * GncSqlObjectBackend::write(). Once QofCollection is rewritten to use C++ + * containers we'll use std::foreach() and lambdas instead of callbacks and this + * can go away. + */ +struct write_objects_t +{ + write_objects_t() = default; + write_objects_t (GncSqlBackend* b, bool o, GncSqlObjectBackendPtr e) : + be{b}, is_ok{o}, obe{e} {} + void commit (QofInstance* inst) { + if (is_ok) is_ok = obe->commit (be, inst); + } + GncSqlBackend* be; + bool is_ok; + GncSqlObjectBackendPtr obe; +}; /** * Basic column type @@ -959,12 +1008,6 @@ gpointer gnc_sql_compile_query (QofBackend* pBEnd, QofQuery* pQuery); void gnc_sql_free_query (QofBackend* pBEnd, gpointer pQuery); void gnc_sql_run_query (QofBackend* pBEnd, gpointer pQuery); -typedef struct -{ - GncSqlBackend* be; - gboolean is_ok; -} write_objects_t; - template T GncSqlColumnTableEntry::get_row_value_from_object(QofIdTypeConst obj_name, const gpointer pObject) const diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index 718fec1803..af06bd2fb9 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -95,6 +95,17 @@ static EntryVec billterm_parent_col_table bt_set_parent_guid), }; +class GncSqlBillTermBackend : public GncSqlObjectBackend +{ +public: + GncSqlBillTermBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + void create_tables(GncSqlBackend*) override; + bool write(GncSqlBackend*) override; +}; + typedef struct { GncBillTerm* billterm; @@ -221,8 +232,8 @@ load_single_billterm (GncSqlBackend* be, GncSqlRow& row, return pBillTerm; } -static void -load_all_billterms (GncSqlBackend* be) +void +GncSqlBillTermBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; @@ -278,7 +289,8 @@ load_all_billterms (GncSqlBackend* be) typedef struct { GncSqlBackend* be; - gboolean is_ok; + GncSqlBillTermBackend* btbe; + bool is_ok; } write_billterms_t; static void @@ -288,26 +300,24 @@ do_save_billterm (QofInstance* inst, gpointer p2) if (data->is_ok) { - data->is_ok = gnc_sql_save_billterm (data->be, inst); + data->is_ok = data->btbe->commit (data->be, inst); } } -static gboolean -write_billterms (GncSqlBackend* be) +bool +GncSqlBillTermBackend::write (GncSqlBackend* be) { - write_billterms_t data; + write_billterms_t data {be, this, true}; g_return_val_if_fail (be != NULL, FALSE); - data.be = be; - data.is_ok = TRUE; qof_object_foreach (GNC_ID_BILLTERM, be->book, do_save_billterm, &data); return data.is_ok; } /* ================================================================= */ -static void -create_billterm_tables (GncSqlBackend* be) +void +GncSqlBillTermBackend::create_tables (GncSqlBackend* be) { gint version; @@ -329,18 +339,6 @@ create_billterm_tables (GncSqlBackend* be) } } -/* ================================================================= */ -gboolean -gnc_sql_save_billterm (GncSqlBackend* be, QofInstance* inst) -{ - g_return_val_if_fail (inst != NULL, FALSE); - g_return_val_if_fail (GNC_IS_BILLTERM (inst), FALSE); - g_return_val_if_fail (be != NULL, FALSE); - - return gnc_sql_commit_standard_item (be, inst, TABLE_NAME, GNC_ID_BILLTERM, - col_table); -} - /* ================================================================= */ template<> void @@ -374,17 +372,8 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be void gnc_billterm_sql_initialize (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_BILLTERM, - gnc_sql_save_billterm, /* commit */ - load_all_billterms, /* initial_load */ - create_billterm_tables, /* create_tables */ - NULL, NULL, NULL, - write_billterms /* write */ - }; - + static GncSqlBillTermBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_BILLTERM, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-bill-term-sql.h b/src/backend/sql/gnc-bill-term-sql.h index 442e1cf1ea..af6cced1b3 100644 --- a/src/backend/sql/gnc-bill-term-sql.h +++ b/src/backend/sql/gnc-bill-term-sql.h @@ -36,6 +36,5 @@ extern "C" #include "qof.h" } void gnc_billterm_sql_initialize (void); -gboolean gnc_sql_save_billterm (GncSqlBackend* be, QofInstance* inst); #endif /* GNC_BILLTERM_SQL_H */ diff --git a/src/backend/sql/gnc-book-sql.cpp b/src/backend/sql/gnc-book-sql.cpp index ea30076fdf..2145172b21 100644 --- a/src/backend/sql/gnc-book-sql.cpp +++ b/src/backend/sql/gnc-book-sql.cpp @@ -68,6 +68,15 @@ static const EntryVec col_table set_root_template_guid) }; +class GncSqlBookBackend : public GncSqlObjectBackend +{ +public: + GncSqlBookBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; +}; + /* ================================================================= */ static gpointer get_root_account_guid (gpointer pObject) @@ -157,8 +166,8 @@ load_single_book (GncSqlBackend* be, GncSqlRow& row) qof_instance_mark_clean (QOF_INSTANCE (pBook)); } -static void -load_all_books (GncSqlBackend* be) +void +GncSqlBookBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; @@ -177,7 +186,7 @@ load_all_books (GncSqlBackend* be) if (row == result->end()) { be->loading = FALSE; - (void)gnc_sql_save_book (be, QOF_INSTANCE (be->book)); + commit(be, QOF_INSTANCE (be->book)); be->loading = TRUE; } else @@ -188,54 +197,12 @@ load_all_books (GncSqlBackend* be) } } -/* ================================================================= */ -static void -create_book_tables (GncSqlBackend* be) -{ - gint version; - - g_return_if_fail (be != NULL); - - version = gnc_sql_get_table_version (be, BOOK_TABLE); - if (version == 0) - { - (void)gnc_sql_create_table (be, BOOK_TABLE, TABLE_VERSION, col_table); - } -} - -/* ================================================================= */ -gboolean -gnc_sql_save_book (GncSqlBackend* be, QofInstance* inst) -{ - gboolean status; - - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (inst != NULL, FALSE); - g_return_val_if_fail (QOF_IS_BOOK (inst), FALSE); - - status = gnc_sql_commit_standard_item (be, inst, BOOK_TABLE, GNC_ID_BOOK, - col_table); - - return status; -} - /* ================================================================= */ void gnc_sql_init_book_handler (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_BOOK, - gnc_sql_save_book, /* commit */ - load_all_books, /* initial_load */ - create_book_tables, /* create_tables */ - NULL, /* compile_query */ - NULL, /* run_query */ - NULL, /* free_query */ - NULL /* write */ - }; - + static GncSqlBookBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_BOOK, BOOK_TABLE, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-book-sql.h b/src/backend/sql/gnc-book-sql.h index 5a5c1f73cb..b1afb3eeb4 100644 --- a/src/backend/sql/gnc-book-sql.h +++ b/src/backend/sql/gnc-book-sql.h @@ -35,6 +35,5 @@ extern "C" #include "qof.h" } void gnc_sql_init_book_handler (void); -gboolean gnc_sql_save_book (GncSqlBackend* be, QofInstance* inst); #endif /* GNC_BOOK_SQL_H */ diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index 231851305e..beb87c27ea 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -76,6 +76,20 @@ static void set_period_num (gpointer pObj, gpointer val); static gnc_numeric get_amount (gpointer pObj); static void set_amount (gpointer pObj, gnc_numeric value); +class GncSqlBudgetBackend : public GncSqlObjectBackend +{ +public: + GncSqlBudgetBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + void create_tables(GncSqlBackend*) override; + bool commit (GncSqlBackend* be, QofInstance* inst) override; + bool write(GncSqlBackend*) override; +private: + static void save(QofInstance*, void*); +}; + typedef struct { GncBudget* budget; @@ -318,8 +332,8 @@ load_single_budget (GncSqlBackend* be, GncSqlRow& row) return pBudget; } -static void -load_all_budgets (GncSqlBackend* be) +void +GncSqlBudgetBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; GList* list = NULL; @@ -349,8 +363,8 @@ load_all_budgets (GncSqlBackend* be) } /* ================================================================= */ -static void -create_budget_tables (GncSqlBackend* be) +void +GncSqlBudgetBackend::create_tables (GncSqlBackend* be) { gint version; @@ -371,8 +385,8 @@ create_budget_tables (GncSqlBackend* be) } /* ================================================================= */ -static gboolean -save_budget (GncSqlBackend* be, QofInstance* inst) +bool +GncSqlBudgetBackend::commit (GncSqlBackend* be, QofInstance* inst) { GncBudget* pBudget = GNC_BUDGET (inst); const GncGUID* guid; @@ -435,18 +449,18 @@ save_budget (GncSqlBackend* be, QofInstance* inst) } static void -do_save_budget (QofInstance* inst, gpointer data) +do_save (QofInstance* inst, gpointer data) { write_objects_t* s = (write_objects_t*)data; if (s->is_ok) { - s->is_ok = save_budget (s->be, inst); + s->is_ok = s->obe->commit (s->be, inst); } } -static gboolean -write_budgets (GncSqlBackend* be) +bool +GncSqlBudgetBackend::write (GncSqlBackend* be) { write_objects_t data; @@ -454,8 +468,9 @@ write_budgets (GncSqlBackend* be) data.be = be; data.is_ok = TRUE; + data.obe = this; qof_collection_foreach (qof_book_get_collection (be->book, GNC_ID_BUDGET), - (QofInstanceForeachCB)do_save_budget, &data); + (QofInstanceForeachCB)do_save, &data); return data.is_ok; } @@ -492,19 +507,8 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, void gnc_sql_init_budget_handler (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_BUDGET, - save_budget, /* commit */ - load_all_budgets, /* initial_load */ - create_budget_tables, /* create_tables */ - NULL, /* compile_query */ - NULL, /* run_query */ - NULL, /* free_query */ - write_budgets /* write */ - }; - + static GncSqlBudgetBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_BUDGET, BUDGET_TABLE, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index 82c2972c69..a77090d3d3 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -84,6 +84,16 @@ static const EntryVec col_table "quote_tz", COMMODITY_MAX_QUOTE_TZ_LEN, 0, "quote-tz"), }; +class GncSqlCommodityBackend : public GncSqlObjectBackend +{ +public: + GncSqlCommodityBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + bool commit(GncSqlBackend*, QofInstance*) override; +}; + /* ================================================================= */ static gpointer @@ -130,8 +140,8 @@ load_single_commodity (GncSqlBackend* be, GncSqlRow& row) return pCommodity; } -static void -load_all_commodities (GncSqlBackend* be) +void +GncSqlCommodityBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; gnc_commodity_table* pTable; @@ -163,21 +173,6 @@ load_all_commodities (GncSqlBackend* be) g_free (sql); } } -/* ================================================================= */ -static void -create_commodities_tables (GncSqlBackend* be) -{ - gint version; - - g_return_if_fail (be != NULL); - - version = gnc_sql_get_table_version (be, COMMODITIES_TABLE); - if (version == 0) - { - (void)gnc_sql_create_table (be, COMMODITIES_TABLE, TABLE_VERSION, col_table); - } -} - /* ================================================================= */ static gboolean do_commit_commodity (GncSqlBackend* be, QofInstance* inst, @@ -221,8 +216,8 @@ do_commit_commodity (GncSqlBackend* be, QofInstance* inst, return is_ok; } -static gboolean -commit_commodity (GncSqlBackend* be, QofInstance* inst) +bool +GncSqlCommodityBackend::commit (GncSqlBackend* be, QofInstance* inst) { g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (inst != NULL, FALSE); @@ -298,19 +293,9 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* b void gnc_sql_init_commodity_handler (void) { - static GncSqlObjectBackend be_data = + static GncSqlCommodityBackend be_data = { - GNC_SQL_BACKEND_VERSION, - GNC_ID_COMMODITY, - commit_commodity, /* commit */ - load_all_commodities, /* initial_load */ - create_commodities_tables, /* create_tables */ - NULL, /* compile_query */ - NULL, /* run_query */ - NULL, /* free_query */ - NULL /* write */ - }; - + GNC_SQL_BACKEND_VERSION, GNC_ID_COMMODITY, COMMODITIES_TABLE, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index 583629fe23..c8b8c6ab09 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -90,6 +90,17 @@ static EntryVec col_table (QofSetterFunc)gncCustomerSetTaxTable), }); +class GncSqlCustomerBackend : public GncSqlObjectBackend +{ +public: + GncSqlCustomerBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + void create_tables(GncSqlBackend*) override; + bool write(GncSqlBackend*) override; +}; + static GncCustomer* load_single_customer (GncSqlBackend* be, GncSqlRow& row) { @@ -110,8 +121,8 @@ load_single_customer (GncSqlBackend* be, GncSqlRow& row) return pCustomer; } -static void -load_all_customers (GncSqlBackend* be) +void +GncSqlCustomerBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; @@ -140,8 +151,8 @@ load_all_customers (GncSqlBackend* be) } /* ================================================================= */ -static void -create_customer_tables (GncSqlBackend* be) +void +GncSqlCustomerBackend::create_tables (GncSqlBackend* be) { gint version; @@ -164,24 +175,6 @@ create_customer_tables (GncSqlBackend* be) } /* ================================================================= */ -static gboolean -save_customer (GncSqlBackend* be, QofInstance* inst) -{ - g_return_val_if_fail (inst != NULL, FALSE); - g_return_val_if_fail (GNC_CUSTOMER (inst), FALSE); - g_return_val_if_fail (be != NULL, FALSE); - - return gnc_sql_commit_standard_item (be, inst, TABLE_NAME, GNC_ID_CUSTOMER, - col_table); -} - -/* ================================================================= */ -typedef struct -{ - GncSqlBackend* be; - gboolean is_ok; -} write_customers_t; - static gboolean customer_should_be_saved (GncCustomer* customer) { @@ -202,7 +195,7 @@ customer_should_be_saved (GncCustomer* customer) static void write_single_customer (QofInstance* term_p, gpointer data_p) { - write_customers_t* data = (write_customers_t*)data_p; + auto data = reinterpret_cast(data_p); g_return_if_fail (term_p != NULL); g_return_if_fail (GNC_IS_CUSTOMER (term_p)); @@ -210,19 +203,20 @@ write_single_customer (QofInstance* term_p, gpointer data_p) if (customer_should_be_saved (GNC_CUSTOMER (term_p)) && data->is_ok) { - data->is_ok = save_customer (data->be, term_p); + data->is_ok = data->obe->commit (data->be, term_p); } } -static gboolean -write_customers (GncSqlBackend* be) +bool +GncSqlCustomerBackend::write (GncSqlBackend* be) { - write_customers_t data; + write_objects_t data; g_return_val_if_fail (be != NULL, FALSE); data.be = be; data.is_ok = TRUE; + data.obe = this; qof_object_foreach (GNC_ID_CUSTOMER, be->book, write_single_customer, (gpointer)&data); return data.is_ok; @@ -232,17 +226,8 @@ write_customers (GncSqlBackend* be) void gnc_customer_sql_initialize (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_CUSTOMER, - save_customer, /* commit */ - load_all_customers, /* initial_load */ - create_customer_tables, /* create_tables */ - NULL, NULL, NULL, - write_customers /* write */ - }; - + static GncSqlCustomerBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_CUSTOMER, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index 20e2df7ed3..b66ba07c1f 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -75,6 +75,18 @@ static EntryVec col_table gnc_sql_make_table_entry("addr", 0, 0, "address"), }); +class GncSqlEmployeeBackend : public GncSqlObjectBackend +{ +public: + GncSqlEmployeeBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + void create_tables(GncSqlBackend*) override; + bool commit(GncSqlBackend*, QofInstance*) override; + bool write(GncSqlBackend*) override; +}; + static GncEmployee* load_single_employee (GncSqlBackend* be, GncSqlRow& row) { @@ -95,8 +107,8 @@ load_single_employee (GncSqlBackend* be, GncSqlRow& row) return pEmployee; } -static void -load_all_employees (GncSqlBackend* be) +void +GncSqlEmployeeBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; @@ -126,8 +138,8 @@ load_all_employees (GncSqlBackend* be) } /* ================================================================= */ -static void -create_employee_tables (GncSqlBackend* be) +void +GncSqlEmployeeBackend::create_tables (GncSqlBackend* be) { gint version; @@ -150,8 +162,8 @@ create_employee_tables (GncSqlBackend* be) } /* ================================================================= */ -static gboolean -save_employee (GncSqlBackend* be, QofInstance* inst) +bool +GncSqlEmployeeBackend::commit (GncSqlBackend* be, QofInstance* inst) { GncEmployee* emp; const GncGUID* guid; @@ -236,12 +248,12 @@ write_single_employee (QofInstance* term_p, gpointer data_p) if (s->is_ok && employee_should_be_saved (GNC_EMPLOYEE (term_p))) { - s->is_ok = save_employee (s->be, term_p); + s->is_ok = s->obe->commit (s->be, term_p); } } -static gboolean -write_employees (GncSqlBackend* be) +bool +GncSqlEmployeeBackend::write (GncSqlBackend* be) { write_objects_t data; @@ -249,6 +261,7 @@ write_employees (GncSqlBackend* be) data.be = be; data.is_ok = TRUE; + data.obe = this; qof_object_foreach (GNC_ID_EMPLOYEE, be->book, write_single_employee, &data); return data.is_ok; @@ -258,17 +271,8 @@ write_employees (GncSqlBackend* be) void gnc_employee_sql_initialize (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_EMPLOYEE, - save_employee, /* commit */ - load_all_employees, /* initial_load */ - create_employee_tables, /* create_tables */ - NULL, NULL, NULL, - write_employees /* write */ - }; - + static GncSqlEmployeeBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_EMPLOYEE, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index 59b6bf891a..75195df86b 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -124,6 +124,17 @@ static EntryVec col_table (QofSetterFunc)gncEntrySetOrder), }); +class GncSqlEntryBackend : public GncSqlObjectBackend +{ +public: + GncSqlEntryBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + void create_tables(GncSqlBackend*) override; + bool write(GncSqlBackend*) override; +}; + static void entry_set_invoice (gpointer pObject, gpointer val) { @@ -178,8 +189,8 @@ load_single_entry (GncSqlBackend* be, GncSqlRow& row) return pEntry; } -static void -load_all_entries (GncSqlBackend* be) +void +GncSqlEntryBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; @@ -207,8 +218,8 @@ load_all_entries (GncSqlBackend* be) } /* ================================================================= */ -static void -create_entry_tables (GncSqlBackend* be) +void +GncSqlEntryBackend::create_tables (GncSqlBackend* be) { gint version; @@ -233,18 +244,6 @@ create_entry_tables (GncSqlBackend* be) } } -/* ================================================================= */ -static gboolean -save_entry (GncSqlBackend* be, QofInstance* inst) -{ - g_return_val_if_fail (inst != NULL, FALSE); - g_return_val_if_fail (GNC_IS_ENTRY (inst), FALSE); - g_return_val_if_fail (be != NULL, FALSE); - - return gnc_sql_commit_standard_item (be, inst, TABLE_NAME, GNC_ID_ENTRY, - col_table); -} - /* ================================================================= */ static void write_single_entry (QofInstance* term_p, gpointer data_p) @@ -261,19 +260,16 @@ write_single_entry (QofInstance* term_p, gpointer data_p) gncEntryGetInvoice (entry) != NULL || gncEntryGetBill (entry) != NULL)) { - s->is_ok = save_entry (s->be, term_p); + s->commit (term_p); } } -static gboolean -write_entries (GncSqlBackend* be) +bool +GncSqlEntryBackend::write (GncSqlBackend* be) { - write_objects_t data; - g_return_val_if_fail (be != NULL, FALSE); + write_objects_t data{be, true, this}; - data.be = be; - data.is_ok = TRUE; qof_object_foreach (GNC_ID_ENTRY, be->book, write_single_entry, &data); return data.is_ok; @@ -283,17 +279,8 @@ write_entries (GncSqlBackend* be) void gnc_entry_sql_initialize (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_ENTRY, - save_entry, /* commit */ - load_all_entries, /* initial_load */ - create_entry_tables, /* create_tables */ - NULL, NULL, NULL, - write_entries /* write */ - }; - + static GncSqlEntryBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_ENTRY, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index fd8450dbce..71eb5938be 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -96,6 +96,18 @@ static EntryVec col_table (QofSetterFunc)gncInvoiceSetToChargeAmount), }); +class GncSqlInvoiceBackend : public GncSqlObjectBackend +{ +public: + GncSqlInvoiceBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + void create_tables(GncSqlBackend*) override; + bool commit (GncSqlBackend* be, QofInstance* inst) override; + bool write(GncSqlBackend*) override; +}; + static GncInvoice* load_single_invoice (GncSqlBackend* be, GncSqlRow& row) { @@ -116,8 +128,8 @@ load_single_invoice (GncSqlBackend* be, GncSqlRow& row) return pInvoice; } -static void -load_all_invoices (GncSqlBackend* be) +void +GncSqlInvoiceBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; @@ -145,8 +157,8 @@ load_all_invoices (GncSqlBackend* be) } /* ================================================================= */ -static void -create_invoice_tables (GncSqlBackend* be) +void +GncSqlInvoiceBackend::create_tables (GncSqlBackend* be) { gint version; @@ -172,8 +184,8 @@ create_invoice_tables (GncSqlBackend* be) } /* ================================================================= */ -static gboolean -save_invoice (GncSqlBackend* be, QofInstance* inst) +bool +GncSqlInvoiceBackend::commit (GncSqlBackend* be, QofInstance* inst) { const GncGUID* guid; GncInvoice* invoice; @@ -250,7 +262,7 @@ invoice_should_be_saved (GncInvoice* invoice) static void write_single_invoice (QofInstance* term_p, gpointer data_p) { - write_objects_t* s = (write_objects_t*)data_p; + auto s = reinterpret_cast(data_p); g_return_if_fail (term_p != NULL); g_return_if_fail (GNC_IS_INVOICE (term_p)); @@ -258,19 +270,16 @@ write_single_invoice (QofInstance* term_p, gpointer data_p) if (s->is_ok && invoice_should_be_saved (GNC_INVOICE (term_p))) { - s->is_ok = save_invoice (s->be, term_p); + s->commit (term_p); } } -static gboolean -write_invoices (GncSqlBackend* be) +bool +GncSqlInvoiceBackend::write (GncSqlBackend* be) { - write_objects_t data; - g_return_val_if_fail (be != NULL, FALSE); + write_objects_t data{be, true, this}; - data.be = be; - data.is_ok = TRUE; qof_object_foreach (GNC_ID_INVOICE, be->book, write_single_invoice, &data); return data.is_ok; @@ -309,17 +318,8 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, void gnc_invoice_sql_initialize (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_INVOICE, - save_invoice, /* commit */ - load_all_invoices, /* initial_load */ - create_invoice_tables, /* create_tables */ - NULL, NULL, NULL, - write_invoices /* write */ - }; - + static GncSqlInvoiceBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_INVOICE, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index b57a867b7e..e7992e49b1 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -69,6 +69,17 @@ static EntryVec col_table (QofSetterFunc)gncJobSetOwner), }); +class GncSqlJobBackend : public GncSqlObjectBackend +{ +public: + GncSqlJobBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + bool write(GncSqlBackend*) override; +}; + + static GncJob* load_single_job (GncSqlBackend* be, GncSqlRow& row) { @@ -89,8 +100,8 @@ load_single_job (GncSqlBackend* be, GncSqlRow& row) return pJob; } -static void -load_all_jobs (GncSqlBackend* be) +void +GncSqlJobBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; g_return_if_fail (be != NULL); @@ -116,33 +127,6 @@ load_all_jobs (GncSqlBackend* be) } } -/* ================================================================= */ -static void -create_job_tables (GncSqlBackend* be) -{ - gint version; - - g_return_if_fail (be != NULL); - - version = gnc_sql_get_table_version (be, TABLE_NAME); - if (version == 0) - { - gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); - } -} - -/* ================================================================= */ -static gboolean -save_job (GncSqlBackend* be, QofInstance* inst) -{ - g_return_val_if_fail (inst != NULL, FALSE); - g_return_val_if_fail (GNC_IS_JOB (inst), FALSE); - g_return_val_if_fail (be != NULL, FALSE); - - return gnc_sql_commit_standard_item (be, inst, TABLE_NAME, GNC_ID_JOB, - col_table); -} - /* ================================================================= */ static gboolean job_should_be_saved (GncJob* job) @@ -164,7 +148,7 @@ job_should_be_saved (GncJob* job) static void write_single_job (QofInstance* term_p, gpointer data_p) { - write_objects_t* s = (write_objects_t*)data_p; + auto s = reinterpret_cast(data_p); g_return_if_fail (term_p != NULL); g_return_if_fail (GNC_IS_JOB (term_p)); @@ -172,19 +156,16 @@ write_single_job (QofInstance* term_p, gpointer data_p) if (s->is_ok && job_should_be_saved (GNC_JOB (term_p))) { - s->is_ok = save_job (s->be, term_p); + s->commit (term_p); } } -static gboolean -write_jobs (GncSqlBackend* be) +bool +GncSqlJobBackend::write (GncSqlBackend* be) { - write_objects_t data; - g_return_val_if_fail (be != NULL, FALSE); + write_objects_t data{be, true, this}; - data.be = be; - data.is_ok = TRUE; qof_object_foreach (GNC_ID_JOB, be->book, write_single_job, &data); return data.is_ok; @@ -194,17 +175,8 @@ write_jobs (GncSqlBackend* be) void gnc_job_sql_initialize (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_JOB, - save_job, /* commit */ - load_all_jobs, /* initial_load */ - create_job_tables, /* create_tables */ - NULL, NULL, NULL, - write_jobs /* write */ - }; - + static GncSqlJobBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_JOB, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index 42dfd9ec6e..5693459bcc 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -63,6 +63,17 @@ static const EntryVec col_table gnc_sql_make_table_entry("is_closed", 0, COL_NNUL, "is-closed") }); +class GncSqlLotsBackend : public GncSqlObjectBackend +{ +public: + GncSqlLotsBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + void create_tables(GncSqlBackend*) override; + bool write(GncSqlBackend*) override; +}; + /* ================================================================= */ static gpointer get_lot_account (gpointer pObject) @@ -111,8 +122,8 @@ load_single_lot (GncSqlBackend* be, GncSqlRow& row) return lot; } -static void -load_all_lots (GncSqlBackend* be) +void +GncSqlLotsBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; g_return_if_fail (be != NULL); @@ -135,8 +146,8 @@ load_all_lots (GncSqlBackend* be) } /* ================================================================= */ -static void -create_lots_tables (GncSqlBackend* be) +void +GncSqlLotsBackend::create_tables (GncSqlBackend* be) { gint version; @@ -163,39 +174,23 @@ create_lots_tables (GncSqlBackend* be) } } -/* ================================================================= */ - -static gboolean -commit_lot (GncSqlBackend* be, QofInstance* inst) -{ - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (inst != NULL, FALSE); - g_return_val_if_fail (GNC_IS_LOT (inst), FALSE); - - return gnc_sql_commit_standard_item (be, inst, TABLE_NAME, GNC_ID_LOT, - col_table); -} - static void do_save_lot (QofInstance* inst, gpointer data) { - write_objects_t* s = (write_objects_t*)data; + auto s = reinterpret_cast(data); if (s->is_ok) { - s->is_ok = commit_lot (s->be, inst); + s->commit (inst); } } -static gboolean -write_lots (GncSqlBackend* be) +bool +GncSqlLotsBackend::write (GncSqlBackend* be) { - write_objects_t data; - g_return_val_if_fail (be != NULL, FALSE); + write_objects_t data{be, true, this}; - data.be = be; - data.is_ok = TRUE; qof_collection_foreach (qof_book_get_collection (be->book, GNC_ID_LOT), (QofInstanceForeachCB)do_save_lot, &data); return data.is_ok; @@ -233,17 +228,8 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, void gnc_sql_init_lot_handler (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_LOT, - commit_lot, /* commit */ - load_all_lots, /* initial_load */ - create_lots_tables, /* create tables */ - NULL, NULL, NULL, - write_lots /* save all */ - }; - + static GncSqlLotsBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_LOT, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index d931eb7ce1..57f695446c 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -70,6 +70,16 @@ static EntryVec col_table ORDER_OWNER, true), }); +class GncSqlOrderBackend : public GncSqlObjectBackend +{ +public: + GncSqlOrderBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + bool write(GncSqlBackend*) override; +}; + static GncOrder* load_single_order (GncSqlBackend* be, GncSqlRow& row) { @@ -90,8 +100,8 @@ load_single_order (GncSqlBackend* be, GncSqlRow& row) return pOrder; } -static void -load_all_orders (GncSqlBackend* be) +void +GncSqlOrderBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; g_return_if_fail (be != NULL); @@ -117,33 +127,6 @@ load_all_orders (GncSqlBackend* be) } } -/* ================================================================= */ -static void -create_order_tables (GncSqlBackend* be) -{ - gint version; - - g_return_if_fail (be != NULL); - - version = gnc_sql_get_table_version (be, TABLE_NAME); - if (version == 0) - { - gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); - } -} - -/* ================================================================= */ -static gboolean -save_order (GncSqlBackend* be, QofInstance* inst) -{ - g_return_val_if_fail (inst != NULL, FALSE); - g_return_val_if_fail (GNC_IS_ORDER (inst), FALSE); - g_return_val_if_fail (be != NULL, FALSE); - - return gnc_sql_commit_standard_item (be, inst, TABLE_NAME, GNC_ID_ORDER, - col_table); -} - /* ================================================================= */ static gboolean order_should_be_saved (GncOrder* order) @@ -165,7 +148,7 @@ order_should_be_saved (GncOrder* order) static void write_single_order (QofInstance* term_p, gpointer data_p) { - write_objects_t* s = (write_objects_t*)data_p; + auto s = reinterpret_cast(data_p); g_return_if_fail (term_p != NULL); g_return_if_fail (GNC_IS_ORDER (term_p)); @@ -173,19 +156,16 @@ write_single_order (QofInstance* term_p, gpointer data_p) if (s->is_ok && order_should_be_saved (GNC_ORDER (term_p))) { - s->is_ok = save_order (s->be, term_p); + s->commit (term_p); } } -static gboolean -write_orders (GncSqlBackend* be) +bool +GncSqlOrderBackend::write (GncSqlBackend* be) { - write_objects_t data; - g_return_val_if_fail (be != NULL, FALSE); + write_objects_t data{be, true, this}; - data.be = be; - data.is_ok = TRUE; qof_object_foreach (GNC_ID_ORDER, be->book, write_single_order, &data); return data.is_ok; @@ -223,16 +203,8 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, void gnc_order_sql_initialize (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_ORDER, - save_order, /* commit */ - load_all_orders, /* initial_load */ - create_order_tables, /* create_tables */ - NULL, NULL, NULL, - write_orders /* write */ - }; + static GncSqlOrderBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_ORDER, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } diff --git a/src/backend/sql/gnc-price-sql.cpp b/src/backend/sql/gnc-price-sql.cpp index bea1c510da..f3c2f4e80e 100644 --- a/src/backend/sql/gnc-price-sql.cpp +++ b/src/backend/sql/gnc-price-sql.cpp @@ -67,6 +67,19 @@ static const EntryVec col_table gnc_sql_make_table_entry("value", 0, COL_NNUL, "value") }); +class GncSqlPriceBackend : public GncSqlObjectBackend +{ +public: + GncSqlPriceBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + void create_tables(GncSqlBackend*) override; + bool commit (GncSqlBackend* be, QofInstance* inst) override; + bool write(GncSqlBackend*) override; +}; + + /* ================================================================= */ static GNCPrice* @@ -85,8 +98,8 @@ load_single_price (GncSqlBackend* be, GncSqlRow& row) return pPrice; } -static void -load_all_prices (GncSqlBackend* be) +void +GncSqlPriceBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; QofBook* pBook; @@ -103,7 +116,7 @@ load_all_prices (GncSqlBackend* be) delete stmt; if (result->begin() == result->end()) return; - + GNCPrice* pPrice; gchar* sql; @@ -127,8 +140,8 @@ load_all_prices (GncSqlBackend* be) } /* ================================================================= */ -static void -create_prices_tables (GncSqlBackend* be) +void +GncSqlPriceBackend::create_tables (GncSqlBackend* be) { gint version; @@ -151,8 +164,8 @@ create_prices_tables (GncSqlBackend* be) /* ================================================================= */ -static gboolean -save_price (GncSqlBackend* be, QofInstance* inst) +bool +GncSqlPriceBackend::commit (GncSqlBackend* be, QofInstance* inst) { GNCPrice* pPrice = GNC_PRICE (inst); E_DB_OPERATION op; @@ -193,34 +206,29 @@ save_price (GncSqlBackend* be, QofInstance* inst) return is_ok; } -static gboolean +gboolean write_price (GNCPrice* p, gpointer data) { - write_objects_t* s = (write_objects_t*)data; + auto s = reinterpret_cast(data); g_return_val_if_fail (p != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE); if (s->is_ok && gnc_price_get_source (p) != PRICE_SOURCE_TEMP) { - s->is_ok = save_price (s->be, QOF_INSTANCE (p)); + s->commit (QOF_INSTANCE(p)); } return s->is_ok; } -static gboolean -write_prices (GncSqlBackend* be) +bool +GncSqlPriceBackend::write (GncSqlBackend* be) { - GNCPriceDB* priceDB; - write_objects_t data; - g_return_val_if_fail (be != NULL, FALSE); + write_objects_t data{be, true, this}; - priceDB = gnc_pricedb_get_db (be->book); - - data.be = be; - data.is_ok = TRUE; + auto priceDB = gnc_pricedb_get_db (be->book); return gnc_pricedb_foreach_price (priceDB, write_price, &data, TRUE); } @@ -228,17 +236,8 @@ write_prices (GncSqlBackend* be) void gnc_sql_init_price_handler (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_PRICE, - save_price, /* commit */ - load_all_prices, /* initial_load */ - create_prices_tables, /* create tables */ - NULL, NULL, NULL, - write_prices /* write */ - }; - + static GncSqlPriceBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_PRICE, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index c56f560a27..44a1675f54 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -109,6 +109,21 @@ static const EntryVec weekend_adjust_col_table "recurrence_weekend_adjust", BUDGET_MAX_RECURRENCE_WEEKEND_ADJUST_LEN, 0) }); +/** + * Recurrences are neither loadable nor committable. Note that the default + * write() implementation is also a no-op. + */ +class GncSqlRecurrenceBackend : public GncSqlObjectBackend +{ +public: + GncSqlRecurrenceBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override { return; } + void create_tables(GncSqlBackend*) override; + bool commit(GncSqlBackend*, QofInstance*) override { return false; } +}; + /* ================================================================= */ static gpointer @@ -389,8 +404,8 @@ upgrade_recurrence_table_1_2 (GncSqlBackend* be) } -static void -create_recurrence_tables (GncSqlBackend* be) +void +GncSqlRecurrenceBackend::create_tables (GncSqlBackend* be) { gint version; gboolean ok; @@ -421,19 +436,8 @@ create_recurrence_tables (GncSqlBackend* be) void gnc_sql_init_recurrence_handler (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_ACCOUNT, - NULL, /* commit - cannot occur */ - NULL, /* initial_load - cannot occur */ - create_recurrence_tables, /* create_tables */ - NULL, /* compile_query */ - NULL, /* run_query */ - NULL, /* free_query */ - NULL /* write */ - }; - + static GncSqlRecurrenceBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_ACCOUNT, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index 0f2fe6f4be..857507ad4d 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -81,6 +81,16 @@ static const EntryVec col_table "template_act_guid", 0, COL_NNUL, "template-account"), }); +class GncSqlSchedXactionBackend : public GncSqlObjectBackend +{ +public: + GncSqlSchedXactionBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + bool commit (GncSqlBackend* be, QofInstance* inst) override; +}; + /* ================================================================= */ static SchedXaction* load_single_sx (GncSqlBackend* be, GncSqlRow& row) @@ -108,8 +118,8 @@ load_single_sx (GncSqlBackend* be, GncSqlRow& row) return pSx; } -static void -load_all_sxes (GncSqlBackend* be) +void +GncSqlSchedXactionBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt = NULL; @@ -142,24 +152,10 @@ load_all_sxes (GncSqlBackend* be) } } -/* ================================================================= */ -static void -create_sx_tables (GncSqlBackend* be) -{ - gint version; - - g_return_if_fail (be != NULL); - - version = gnc_sql_get_table_version (be, SCHEDXACTION_TABLE); - if (version == 0) - { - (void)gnc_sql_create_table (be, SCHEDXACTION_TABLE, TABLE_VERSION, col_table); - } -} /* ================================================================= */ -gboolean -gnc_sql_save_schedxaction (GncSqlBackend* be, QofInstance* inst) +bool +GncSqlSchedXactionBackend::commit (GncSqlBackend* be, QofInstance* inst) { SchedXaction* pSx; const GncGUID* guid; @@ -218,19 +214,9 @@ gnc_sql_save_schedxaction (GncSqlBackend* be, QofInstance* inst) void gnc_sql_init_schedxaction_handler (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_SCHEDXACTION, - gnc_sql_save_schedxaction, /* commit */ - load_all_sxes, /* initial_load */ - create_sx_tables, /* create_tables */ - NULL, /* compile_query */ - NULL, /* run_query */ - NULL, /* free_query */ - NULL /* write */ - }; - + static GncSqlSchedXactionBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_SCHEDXACTION, SCHEDXACTION_TABLE, + col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index e6b159ec11..2a682a9fc2 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -160,6 +160,21 @@ static const EntryVec gdate_col_table gnc_sql_make_table_entry("gdate_val", 0, 0), }; +/** + * Slots are neither loadable nor committable. Note that the default + * write() implementation is also a no-op. + */ +class GncSqlSlotsBackend : public GncSqlObjectBackend +{ +public: + GncSqlSlotsBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override { return; } + void create_tables(GncSqlBackend*) override; + bool commit(GncSqlBackend*, QofInstance*) override { return false; } +}; + /* ================================================================= */ static gchar* @@ -994,8 +1009,8 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be, } /* ================================================================= */ -static void -create_slots_tables (GncSqlBackend* be) +void +GncSqlSlotsBackend::create_tables (GncSqlBackend* be) { gint version; gboolean ok; @@ -1048,23 +1063,8 @@ create_slots_tables (GncSqlBackend* be) void gnc_sql_init_slots_handler (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, -// This was GNC_ID_ACCOUNT. If somethine blows up, change it back, -// make the registry store a std::tuple, and check the first string against types -// in the functions that are called on each backend. - GNC_ID_ACCOUNT, - NULL, /* commit - cannot occur */ - NULL, /* initial_load - cannot occur */ - create_slots_tables, /* create_tables */ - NULL, /* compile_query */ - NULL, /* run_query */ - NULL, /* free_query */ - NULL /* write */ - }; - + static GncSqlSlotsBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_ACCOUNT, TABLE_NAME, col_table}; gnc_sql_register_backend(std::make_tuple(std::string{TABLE_NAME}, &be_data)); } diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index 577eef06a3..f336ef2e4c 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -113,6 +113,18 @@ static EntryVec guid_col_table get_obj_guid, set_obj_guid), }); +class GncSqlTaxTableBackend : public GncSqlObjectBackend +{ +public: + GncSqlTaxTableBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + void create_tables(GncSqlBackend*) override; + bool commit (GncSqlBackend* be, QofInstance* inst) override; + bool write(GncSqlBackend*) override; +}; + typedef struct { GncTaxTable* tt; @@ -278,8 +290,8 @@ load_single_taxtable (GncSqlBackend* be, GncSqlRow& row, qof_instance_mark_clean (QOF_INSTANCE (tt)); } -static void -load_all_taxtables (GncSqlBackend* be) +void +GncSqlTaxTableBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; @@ -319,8 +331,8 @@ load_all_taxtables (GncSqlBackend* be) } /* ================================================================= */ -static void -create_taxtable_tables (GncSqlBackend* be) +void +GncSqlTaxTableBackend::create_tables (GncSqlBackend* be) { gint version; @@ -396,8 +408,8 @@ save_tt_entries (GncSqlBackend* be, const GncGUID* guid, GList* entries) return is_ok; } -static gboolean -save_taxtable (GncSqlBackend* be, QofInstance* inst) +bool +GncSqlTaxTableBackend::commit (GncSqlBackend* be, QofInstance* inst) { GncTaxTable* tt; const GncGUID* guid; @@ -456,23 +468,20 @@ save_taxtable (GncSqlBackend* be, QofInstance* inst) static void save_next_taxtable (QofInstance* inst, gpointer data) { - write_objects_t* s = (write_objects_t*)data; + auto s = reinterpret_cast(data); if (s->is_ok) { - s->is_ok = save_taxtable (s->be, inst); + s->commit (inst); } } -static gboolean -write_taxtables (GncSqlBackend* be) +bool +GncSqlTaxTableBackend::write (GncSqlBackend* be) { - write_objects_t data; - g_return_val_if_fail (be != NULL, FALSE); + write_objects_t data{be, true, this}; - data.be = be; - data.is_ok = TRUE; qof_object_foreach (GNC_ID_TAXTABLE, be->book, save_next_taxtable, &data); return data.is_ok; @@ -511,17 +520,8 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be void gnc_taxtable_sql_initialize (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_TAXTABLE, - save_taxtable, /* commit */ - load_all_taxtables, /* initial_load */ - create_taxtable_tables, /* create_tables */ - NULL, NULL, NULL, - write_taxtables /* write */ - }; - + static GncSqlTaxTableBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_TAXTABLE, TT_TABLE_NAME, tt_col_table}; gnc_sql_register_backend(&be_data); } /* ========================== END OF FILE ===================== */ diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index 5baedef493..d64a797423 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -66,12 +66,14 @@ static QofLogModule log_module = G_LOG_DOMAIN; #define SPLIT_TABLE "splits" #define SPLIT_TABLE_VERSION 4 -typedef struct +struct split_info_t : public write_objects_t { - GncSqlBackend* be; + split_info_t () = default; + split_info_t (GncSqlBackend* be, bool o, + GncSqlObjectBackendPtr e, const GncGUID* g): + write_objects_t(be, o, e), guid{g} {} const GncGUID* guid; - gboolean is_ok; -} split_info_t; +}; #define TX_MAX_NUM_LEN 2048 #define TX_MAX_DESCRIPTION_LEN 2048 @@ -133,6 +135,36 @@ static const EntryVec tx_guid_col_table gnc_sql_make_table_entry("tx_guid", 0, 0, "guid"), }; +class GncSqlTransBackend : public GncSqlObjectBackend +{ +public: + GncSqlTransBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + void create_tables(GncSqlBackend*) override; + bool commit (GncSqlBackend* be, QofInstance* inst) override; +}; + +class GncSqlSplitBackend : public GncSqlObjectBackend +{ +public: + GncSqlSplitBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override { return; } // loaded by transaction. + void create_tables(GncSqlBackend*) override; + bool commit (GncSqlBackend* be, QofInstance* inst) override; +}; +static GncSqlSplitBackend be_data_split { + GNC_SQL_BACKEND_VERSION, GNC_ID_SPLIT, SPLIT_TABLE, split_col_table}; +/* These functions exist but have not been tested. + #if LOAD_TRANSACTIONS_AS_NEEDED + compile_split_query, + run_split_query, + free_split_query, +*/ + /* ================================================================= */ static gpointer @@ -447,15 +479,15 @@ query_transactions (GncSqlBackend* be, GncSqlStatement* stmt) * * @param be SQL backend */ -static void -create_transaction_tables (GncSqlBackend* be) +void +GncSqlTransBackend::create_tables (GncSqlBackend* be) { gint version; gboolean ok; g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TRANSACTION_TABLE); + version = gnc_sql_get_table_version (be, m_table_name.c_str()); if (version == 0) { (void)gnc_sql_create_table (be, TRANSACTION_TABLE, TX_TABLE_VERSION, @@ -467,35 +499,35 @@ create_transaction_tables (GncSqlBackend* be) PERR ("Unable to create index\n"); } } - else if (version < TX_TABLE_VERSION) + else if (version < m_version) { /* Upgrade: 1->2: 64 bit int handling 2->3: allow dates to be NULL */ - gnc_sql_upgrade_table (be, TRANSACTION_TABLE, tx_col_table); - (void)gnc_sql_set_table_version (be, TRANSACTION_TABLE, TX_TABLE_VERSION); - PINFO ("Transactions table upgraded from version %d to version %d\n", version, - TX_TABLE_VERSION); + gnc_sql_upgrade_table (be, m_table_name.c_str(), tx_col_table); + (void)gnc_sql_set_table_version (be, m_table_name.c_str(), m_version); + PINFO ("Transactions table upgraded from version %d to version %d\n", + version, m_version); } +} +void +GncSqlSplitBackend::create_tables (GncSqlBackend* be) +{ + g_return_if_fail (be != nullptr); - version = gnc_sql_get_table_version (be, SPLIT_TABLE); + auto version = gnc_sql_get_table_version (be, m_table_name.c_str()); if (version == 0) { - (void)gnc_sql_create_table (be, SPLIT_TABLE, SPLIT_TABLE_VERSION, - split_col_table); - ok = gnc_sql_create_index (be, "splits_tx_guid_index", SPLIT_TABLE, - tx_guid_col_table); - if (!ok) - { + (void)gnc_sql_create_table (be, m_table_name.c_str(), + m_version, m_col_table); + if (!gnc_sql_create_index (be, "splits_tx_guid_index", + m_table_name.c_str(), tx_guid_col_table)) PERR ("Unable to create index\n"); - } - ok = gnc_sql_create_index (be, "splits_account_guid_index", SPLIT_TABLE, - account_guid_col_table); - if (!ok) - { + if (!gnc_sql_create_index (be, "splits_account_guid_index", + m_table_name.c_str(), + account_guid_col_table)) PERR ("Unable to create index\n"); - } } else if (version < SPLIT_TABLE_VERSION) { @@ -503,22 +535,18 @@ create_transaction_tables (GncSqlBackend* be) /* Upgrade: 1->2: 64 bit int handling 3->4: Split reconcile date can be NULL */ - gnc_sql_upgrade_table (be, SPLIT_TABLE, split_col_table); - ok = gnc_sql_create_index (be, "splits_tx_guid_index", SPLIT_TABLE, - tx_guid_col_table); - if (!ok) - { + gnc_sql_upgrade_table (be, m_table_name.c_str(), split_col_table); + if (!gnc_sql_create_index (be, "splits_tx_guid_index", + m_table_name.c_str(), + tx_guid_col_table)) PERR ("Unable to create index\n"); - } - ok = gnc_sql_create_index (be, "splits_account_guid_index", SPLIT_TABLE, - account_guid_col_table); - if (!ok) - { + if (!gnc_sql_create_index (be, "splits_account_guid_index", + m_table_name.c_str(), + account_guid_col_table)) PERR ("Unable to create index\n"); - } - (void)gnc_sql_set_table_version (be, SPLIT_TABLE, SPLIT_TABLE_VERSION); + (void)gnc_sql_set_table_version (be, m_table_name.c_str(), m_version); PINFO ("Splits table upgraded from version %d to version %d\n", version, - SPLIT_TABLE_VERSION); + m_version); } } /* ================================================================= */ @@ -581,8 +609,8 @@ delete_splits (GncSqlBackend* be, Transaction* pTx) * @param inst Split * @return TRUE if successful, FALSE if error */ -static gboolean -commit_split (GncSqlBackend* be, QofInstance* inst) +bool +GncSqlSplitBackend::commit (GncSqlBackend* be, QofInstance* inst) { E_DB_OPERATION op; gboolean is_infant; @@ -623,54 +651,19 @@ commit_split (GncSqlBackend* be, QofInstance* inst) return is_ok; } -static void -save_split_cb (gpointer data, gpointer user_data) + +bool +GncSqlTransBackend::commit (GncSqlBackend* be, QofInstance* inst) { - split_info_t* split_info = (split_info_t*)user_data; - Split* pSplit = GNC_SPLIT (data); - - g_return_if_fail (data != NULL); - g_return_if_fail (GNC_IS_SPLIT (data)); - g_return_if_fail (user_data != NULL); - - if (split_info->is_ok) - { - split_info->is_ok = commit_split (split_info->be, QOF_INSTANCE (pSplit)); - } -} - -static gboolean -save_splits (GncSqlBackend* be, const GncGUID* tx_guid, SplitList* pSplitList) -{ - split_info_t split_info; - - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (tx_guid != NULL, FALSE); - g_return_val_if_fail (pSplitList != NULL, FALSE); - - split_info.be = be; - split_info.guid = tx_guid; - split_info.is_ok = TRUE; - g_list_foreach (pSplitList, save_split_cb, &split_info); - - return split_info.is_ok; -} - -static gboolean -save_transaction (GncSqlBackend* be, Transaction* pTx, gboolean do_save_splits) -{ - const GncGUID* guid; E_DB_OPERATION op; - gboolean is_infant; - QofInstance* inst; gboolean is_ok = TRUE; const char* err = NULL; g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (pTx != NULL, FALSE); + g_return_val_if_fail (inst != NULL, FALSE); - inst = QOF_INSTANCE (pTx); - is_infant = qof_instance_get_infant (inst); + auto pTx = GNC_TRANS(inst); + auto is_infant = qof_instance_get_infant (inst); if (qof_instance_get_destroying (inst)) { op = OP_DB_DELETE; @@ -708,8 +701,8 @@ save_transaction (GncSqlBackend* be, Transaction* pTx, gboolean do_save_splits) if (is_ok) { - // Commit slots and splits - guid = qof_instance_get_guid (inst); + // Commit slots + auto guid = qof_instance_get_guid (inst); if (!qof_instance_get_destroying (inst)) { is_ok = gnc_sql_slots_save (be, guid, is_infant, inst); @@ -717,14 +710,6 @@ save_transaction (GncSqlBackend* be, Transaction* pTx, gboolean do_save_splits) { err = "Slots save failed. Check trace log for SQL errors"; } - if (is_ok && do_save_splits) - { - is_ok = save_splits (be, guid, xaccTransGetSplitList (pTx)); - if (! is_ok) - { - err = "Split save failed. Check trace log for SQL errors"; - } - } } else { @@ -767,26 +752,6 @@ save_transaction (GncSqlBackend* be, Transaction* pTx, gboolean do_save_splits) return is_ok; } -gboolean -gnc_sql_save_transaction (GncSqlBackend* be, QofInstance* inst) -{ - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (inst != NULL, FALSE); - g_return_val_if_fail (GNC_IS_TRANS (inst), FALSE); - - return save_transaction (be, GNC_TRANS (inst), /* do_save_splits */TRUE); -} - -static gboolean -commit_transaction (GncSqlBackend* be, QofInstance* inst) -{ - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (inst != NULL, FALSE); - g_return_val_if_fail (GNC_IS_TRANS (inst), FALSE); - - return save_transaction (be, GNC_TRANS (inst), /* do_save_splits */FALSE); -} - /* ================================================================= */ /** * Loads all transactions for an account. @@ -825,7 +790,8 @@ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* be, * * @param be SQL backend */ -void gnc_sql_transaction_load_all_tx (GncSqlBackend* be) +void +GncSqlTransBackend::load_all (GncSqlBackend* be) { gchar* query_sql; GncSqlStatement* stmt; @@ -1471,41 +1437,8 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, void gnc_sql_init_transaction_handler (void) { - static GncSqlObjectBackend be_data_tx = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_TRANS, - commit_transaction, /* commit */ -#if LOAD_TRANSACTIONS_AS_NEEDED - NULL, /* initial load */ -#else - gnc_sql_transaction_load_all_tx, -#endif - create_transaction_tables, /* create tables */ - NULL, /* compile_query */ - NULL, /* run_query */ - NULL, /* free_query */ - NULL /* write */ - }; - static GncSqlObjectBackend be_data_split = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_SPLIT, - commit_split, /* commit */ - NULL, /* initial_load */ - NULL, /* create tables */ -#if LOAD_TRANSACTIONS_AS_NEEDED - compile_split_query, - run_split_query, - free_split_query, -#else - NULL, /* compile_query */ - NULL, /* run_query */ - NULL, /* free_query */ -#endif - NULL /* write */ - }; - + static GncSqlTransBackend be_data_tx { + GNC_SQL_BACKEND_VERSION, GNC_ID_TRANS, TRANSACTION_TABLE, tx_col_table}; gnc_sql_register_backend(&be_data_tx); gnc_sql_register_backend(&be_data_split); } diff --git a/src/backend/sql/gnc-transaction-sql.h b/src/backend/sql/gnc-transaction-sql.h index eae7e63dc7..9bec050faf 100644 --- a/src/backend/sql/gnc-transaction-sql.h +++ b/src/backend/sql/gnc-transaction-sql.h @@ -38,23 +38,6 @@ extern "C" } void gnc_sql_init_transaction_handler (void); -/** - * Commits all of the splits for a transaction. - * - * @param be SQL backend - * @param pTx Transaction - */ -void gnc_sql_transaction_commit_splits (GncSqlBackend* be, Transaction* pTx); - -/** - * Saves a transaction to the db. - * - * @param be SQL backend - * @param inst Transaction instance - * @return TRUE if successful, FALSE if unsuccessful - */ -gboolean gnc_sql_save_transaction (GncSqlBackend* be, QofInstance* inst); - /** * Loads all transactions which have splits for a specific account. * @@ -63,14 +46,6 @@ gboolean gnc_sql_save_transaction (GncSqlBackend* be, QofInstance* inst); */ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* be, Account* account); - -/** - * Loads all transactions. - * - * @param be SQL backend - */ -void gnc_sql_transaction_load_all_tx (GncSqlBackend* be); - typedef struct { Account* acct; diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index 0caf56a3c9..e2fe4252f1 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -79,6 +79,17 @@ static EntryVec col_table gnc_sql_make_table_entry("tax_table", 0, 0, "tax-table"), }); +class GncSqlVendorBackend : public GncSqlObjectBackend +{ +public: + GncSqlVendorBackend(int version, const std::string& type, + const std::string& table, const EntryVec& vec) : + GncSqlObjectBackend(version, type, table, vec) {} + void load_all(GncSqlBackend*) override; + bool commit(GncSqlBackend*, QofInstance*) override; + bool write(GncSqlBackend*) override; +}; + static GncVendor* load_single_vendor (GncSqlBackend* be, GncSqlRow& row) { @@ -99,8 +110,8 @@ load_single_vendor (GncSqlBackend* be, GncSqlRow& row) return pVendor; } -static void -load_all_vendors (GncSqlBackend* be) +void +GncSqlVendorBackend::load_all (GncSqlBackend* be) { GncSqlStatement* stmt; @@ -126,23 +137,8 @@ load_all_vendors (GncSqlBackend* be) } /* ================================================================= */ -static void -create_vendor_tables (GncSqlBackend* be) -{ - gint version; - - g_return_if_fail (be != NULL); - - version = gnc_sql_get_table_version (be, TABLE_NAME); - if (version == 0) - { - gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); - } -} - -/* ================================================================= */ -static gboolean -save_vendor (GncSqlBackend* be, QofInstance* inst) +bool +GncSqlVendorBackend::commit (GncSqlBackend* be, QofInstance* inst) { GncVendor* v; const GncGUID* guid; @@ -218,27 +214,24 @@ vendor_should_be_saved (GncVendor* vendor) static void write_single_vendor (QofInstance* term_p, gpointer data_p) { - write_objects_t* s = (write_objects_t*)data_p; + auto s = reinterpret_cast(data_p); g_return_if_fail (term_p != NULL); g_return_if_fail (GNC_IS_VENDOR (term_p)); g_return_if_fail (data_p != NULL); - if (s->is_ok && vendor_should_be_saved (GNC_VENDOR (term_p))) + if (vendor_should_be_saved (GNC_VENDOR (term_p))) { - s->is_ok = save_vendor (s->be, term_p); + s->commit (term_p); } } -static gboolean -write_vendors (GncSqlBackend* be) +bool +GncSqlVendorBackend::write (GncSqlBackend* be) { - write_objects_t data; - g_return_val_if_fail (be != NULL, FALSE); + write_objects_t data{be, true, this}; - data.be = be; - data.is_ok = TRUE; qof_object_foreach (GNC_ID_VENDOR, be->book, write_single_vendor, &data); return data.is_ok; @@ -248,16 +241,8 @@ write_vendors (GncSqlBackend* be) void gnc_vendor_sql_initialize (void) { - static GncSqlObjectBackend be_data = - { - GNC_SQL_BACKEND_VERSION, - GNC_ID_VENDOR, - save_vendor, /* commit */ - load_all_vendors, /* initial_load */ - create_vendor_tables, /* create_tables */ - NULL, NULL, NULL, - write_vendors /* write */ - }; + static GncSqlVendorBackend be_data { + GNC_SQL_BACKEND_VERSION, GNC_ID_VENDOR, TABLE_NAME, col_table}; gnc_sql_register_backend(&be_data); } From 64c1fda6ec1417b9d0dabd937c9981aff0f36261 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 17 Jun 2016 11:21:18 -0700 Subject: [PATCH 17/63] gnc-backend-dbi.cpp: NULL -> nullptr. --- src/backend/dbi/gnc-backend-dbi.cpp | 324 ++++++++++++++-------------- 1 file changed, 162 insertions(+), 162 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 6aa5c0d1f2..a7c7e7204e 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -138,7 +138,7 @@ struct QofPGSQLBackendProvider : public QofBackendProvider #if LIBDBI_VERSION >= 900 #define HAVE_LIBDBI_R 1 #define HAVE_LIBDBI_TO_LONGLONG 1 -static dbi_inst dbi_instance = NULL; +static dbi_inst dbi_instance = nullptr; #else #define HAVE_LIBDBI_R 0 #define HAVE_LIBDBI_TO_LONGLONG 0 @@ -238,7 +238,7 @@ static void gnc_table_slist_free (GSList* table_list) { GSList* list; - for (list = table_list; list != NULL; list = g_slist_next (list)) + for (list = table_list; list != nullptr; list = g_slist_next (list)) { g_free (list->data); } @@ -249,7 +249,7 @@ static void gnc_dbi_set_error (GncDbiSqlConnection* dbi_conn, gint last_error, gint error_repeat, gboolean retry) { - g_return_if_fail (dbi_conn != NULL); + g_return_if_fail (dbi_conn != nullptr); dbi_conn->last_error = last_error; if (error_repeat > 0) @@ -320,16 +320,16 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, { GncDbiBackend* be = (GncDbiBackend*)qbe; gint result; - gchar* dirname = NULL; - gchar* basename = NULL; - gchar* filepath = NULL; + gchar* dirname = nullptr; + gchar* basename = nullptr; + gchar* filepath = nullptr; const char* msg = nullptr; gboolean file_exists; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; - g_return_if_fail (qbe != NULL); - g_return_if_fail (session != NULL); - g_return_if_fail (book_id != NULL); + g_return_if_fail (qbe != nullptr); + g_return_if_fail (session != nullptr); + g_return_if_fail (book_id != nullptr); ENTER (" "); @@ -355,7 +355,7 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, } - if (be->conn != NULL) + if (be->conn != nullptr) { dbi_conn_close (be->conn); } @@ -369,7 +369,7 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, be->conn = dbi_conn_new ("sqlite3"); #endif - if (be->conn == NULL) + if (be->conn == nullptr) { PERR ("Unable to create sqlite3 dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); @@ -434,7 +434,7 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, { /* does now, and we don't want to */ dbi_conn_close (be->conn); /* leave it lying around. */ - be->conn = NULL; + be->conn = nullptr; g_unlink (filepath); } msg = "Bad DBI Library"; @@ -447,7 +447,7 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, goto exit; } - if (be->sql_be.conn != NULL) + if (be->sql_be.conn != nullptr) { gnc_sql_connection_dispose (be->sql_be.conn); } @@ -461,23 +461,23 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, PINFO ("logpath=%s", filepath ? filepath : "(null)"); exit: - if (filepath != NULL) g_free (filepath); - if (basename != NULL) g_free (basename); - if (dirname != NULL) g_free (dirname); + if (filepath != nullptr) g_free (filepath); + if (basename != nullptr) g_free (basename); + if (dirname != nullptr) g_free (dirname); LEAVE ("%s", msg); } static GSList* conn_get_index_list_sqlite3 (dbi_conn conn) { - GSList* list = NULL; + GSList* list = nullptr; const gchar* errmsg; dbi_result result = dbi_conn_query (conn, "SELECT name FROM sqlite_master WHERE type = 'index' AND name NOT LIKE 'sqlite_autoindex%'"); if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) { g_print ("Index Table Retrieval Error: %s\n", errmsg); - return NULL; + return nullptr; } while (dbi_result_next_row (result) != 0) { @@ -661,12 +661,12 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } result = dbi_conn_queryf (dcon, "CREATE TABLE %s ( Hostname varchar(%d), PID int )", lock_table, GNC_HOST_NAME_MAX); - if (dbi_conn_error (dcon, NULL)) + if (dbi_conn_error (dcon, nullptr)) { const gchar* errstr; dbi_conn_error (dcon, &errstr); @@ -675,20 +675,20 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } return FALSE; } if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } } if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } /* Protect everything with a single transaction to prevent races */ @@ -699,13 +699,13 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } result = dbi_conn_queryf (dcon, "SELECT * FROM %s", lock_table); if (result && dbi_result_get_numrows (result)) { dbi_result_free (result); - result = NULL; + result = nullptr; if (!ignore_lock) { qof_backend_set_error (qbe, ERR_BACKEND_LOCKED); @@ -722,14 +722,14 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } return FALSE; } if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } } /* Add an entry and commit the transaction */ @@ -746,20 +746,20 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } return FALSE; } if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } result = dbi_conn_query (dcon, "COMMIT"); if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } return TRUE; } @@ -769,7 +769,7 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } return FALSE; } @@ -779,21 +779,21 @@ gnc_dbi_unlock (QofBackend* qbe) GncDbiBackend* qe = (GncDbiBackend*)qbe; dbi_conn dcon = qe->conn; dbi_result result; - const gchar* dbname = NULL; + const gchar* dbname = nullptr; - g_return_if_fail (dcon != NULL); - g_return_if_fail (dbi_conn_error (dcon, NULL) == 0); + g_return_if_fail (dcon != nullptr); + g_return_if_fail (dbi_conn_error (dcon, nullptr) == 0); dbname = dbi_conn_get_option (dcon, "dbname"); /* Check if the lock table exists */ - g_return_if_fail (dbname != NULL); + g_return_if_fail (dbname != nullptr); result = dbi_conn_get_table_list (dcon, dbname, lock_table); if (! (result && dbi_result_get_numrows (result))) { if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } PWARN ("No lock table in database, so not unlocking it."); return; @@ -807,7 +807,7 @@ gnc_dbi_unlock (QofBackend* qbe) gchar hostname[ GNC_HOST_NAME_MAX + 1 ]; dbi_result_free (result); - result = NULL; + result = nullptr; memset (hostname, 0, sizeof (hostname)); gethostname (hostname, GNC_HOST_NAME_MAX); result = dbi_conn_queryf (dcon, @@ -818,7 +818,7 @@ gnc_dbi_unlock (QofBackend* qbe) if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } result = dbi_conn_queryf (dcon, "DELETE FROM %s", lock_table); if (!result) @@ -829,20 +829,20 @@ gnc_dbi_unlock (QofBackend* qbe) if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } return; } else { dbi_result_free (result); - result = NULL; + result = nullptr; } result = dbi_conn_query (dcon, "COMMIT"); if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } return; } @@ -850,7 +850,7 @@ gnc_dbi_unlock (QofBackend* qbe) if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } PWARN ("There was no lock entry in the Lock table"); return; @@ -858,7 +858,7 @@ gnc_dbi_unlock (QofBackend* qbe) if (result) { dbi_result_free (result); - result = NULL; + result = nullptr; } PWARN ("Unable to get a lock on LOCK, so failed to clear the lock entry."); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); @@ -937,21 +937,21 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, gboolean create, gboolean force) { GncDbiBackend* be = (GncDbiBackend*)qbe; - gchar* protocol = NULL; - gchar* host = NULL; - gchar* dbname = NULL; - gchar* username = NULL; - gchar* password = NULL; - gchar* basename = NULL; - gchar* translog_path = NULL; + gchar* protocol = nullptr; + gchar* host = nullptr; + gchar* dbname = nullptr; + gchar* username = nullptr; + gchar* password = nullptr; + gchar* basename = nullptr; + gchar* translog_path = nullptr; gint portnum = 0; gint result; gboolean success = FALSE; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; - g_return_if_fail (qbe != NULL); - g_return_if_fail (session != NULL); - g_return_if_fail (book_id != NULL); + g_return_if_fail (qbe != nullptr); + g_return_if_fail (session != nullptr); + g_return_if_fail (book_id != nullptr); ENTER (" "); @@ -964,7 +964,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, // Try to connect to the db. If it doesn't exist and the create // flag is TRUE, we'll need to connect to the 'mysql' db and execute the // CREATE DATABASE ddl statement there. - if (be->conn != NULL) + if (be->conn != nullptr) { dbi_conn_close (be->conn); } @@ -976,7 +976,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, #else be->conn = dbi_conn_new ("mysql"); #endif - if (be->conn == NULL) + if (be->conn == nullptr) { PERR ("Unable to create mysql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); @@ -1055,7 +1055,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, adjust_sql_options (be->conn); dresult = dbi_conn_queryf (be->conn, "CREATE DATABASE %s CHARACTER SET utf8", dbname); - if (dresult == NULL) + if (dresult == nullptr) { PERR ("Unable to create database '%s'\n", dbname); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); @@ -1073,7 +1073,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, be->conn = dbi_conn_new ("mysql"); #endif - if (be->conn == NULL) + if (be->conn == nullptr) { PERR ("Unable to create mysql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); @@ -1129,7 +1129,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, { dbi_result dresult; - if (be->sql_be.conn != NULL) + if (be->sql_be.conn != nullptr) { gnc_sql_connection_dispose (be->sql_be.conn); } @@ -1140,7 +1140,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, /* We should now have a proper session set up. * Let's start logging */ - basename = g_strjoin ("_", protocol, host, username, dbname, NULL); + basename = g_strjoin ("_", protocol, host, username, dbname, nullptr); translog_path = gnc_build_translog_path (basename); xaccLogSetBaseName (translog_path); PINFO ("logpath=%s", translog_path ? translog_path : "(null)"); @@ -1160,16 +1160,16 @@ exit: static GSList* conn_get_index_list_mysql (dbi_conn conn) { - GSList* index_list = NULL; + GSList* index_list = nullptr; dbi_result table_list; const char* errmsg; const gchar* dbname = dbi_conn_get_option (conn, "dbname"); - g_return_val_if_fail (conn != NULL, NULL); - table_list = dbi_conn_get_table_list (conn, dbname, NULL); + g_return_val_if_fail (conn != nullptr, nullptr); + table_list = dbi_conn_get_table_list (conn, dbname, nullptr); if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) { g_print ("Table Retrieval Error: %s\n", errmsg); - return NULL; + return nullptr; } while (dbi_result_next_row (table_list) != 0) { @@ -1188,7 +1188,7 @@ conn_get_index_list_mysql (dbi_conn conn) { const gchar* index_name = dbi_result_get_string_idx (result, 3); index_list = g_slist_prepend (index_list, g_strjoin (" ", index_name, - table_name, NULL)); + table_name, nullptr)); } dbi_result_free (result); } @@ -1204,7 +1204,7 @@ conn_drop_index_mysql (dbi_conn conn, const gchar* index) int splitlen = -1; /* Check if the index split can be valid */ - while (index_table_split[++splitlen] != NULL) + while (index_table_split[++splitlen] != nullptr) { /* do nothing, just count split members */ } if (splitlen != 2) @@ -1245,7 +1245,7 @@ pgsql_error_fn (dbi_conn conn, void* user_data) else if (g_strrstr (msg, "server closed the connection unexpectedly")) // Connection lost { - if (dbi_conn == NULL) + if (dbi_conn == nullptr) { PWARN ("DBI Error: Connection lost, connection pointer invalid"); return; @@ -1293,20 +1293,20 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, { GncDbiBackend* be = (GncDbiBackend*)qbe; gint result = 0; - gchar* protocol = NULL; - gchar* host = NULL; - gchar* dbname = NULL, *dbnamelc = NULL; - gchar* username = NULL; - gchar* password = NULL; - gchar* basename = NULL; - gchar* translog_path = NULL; + gchar* protocol = nullptr; + gchar* host = nullptr; + gchar* dbname = nullptr, *dbnamelc = nullptr; + gchar* username = nullptr; + gchar* password = nullptr; + gchar* basename = nullptr; + gchar* translog_path = nullptr; gboolean success = FALSE; gint portnum = 0; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; - g_return_if_fail (qbe != NULL); - g_return_if_fail (session != NULL); - g_return_if_fail (book_id != NULL); + g_return_if_fail (qbe != nullptr); + g_return_if_fail (session != nullptr); + g_return_if_fail (book_id != nullptr); ENTER (" "); @@ -1326,7 +1326,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, // Try to connect to the db. If it doesn't exist and the create // flag is TRUE, we'll need to connect to the 'postgres' db and execute the // CREATE DATABASE ddl statement there. - if (be->conn != NULL) + if (be->conn != nullptr) { dbi_conn_close (be->conn); } @@ -1340,7 +1340,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, be->conn = dbi_conn_new ("pgsql"); #endif - if (be->conn == NULL) + if (be->conn == nullptr) { PERR ("Unable to create pgsql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); @@ -1417,7 +1417,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, } dresult = dbi_conn_queryf (be->conn, "CREATE DATABASE %s WITH TEMPLATE template0 ENCODING 'UTF8'", dbnamelc); - if (dresult == NULL) + if (dresult == nullptr) { PERR ("Unable to create database '%s'\n", dbname); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); @@ -1437,7 +1437,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, be->conn = dbi_conn_new ("pgsql"); #endif - if (be->conn == NULL) + if (be->conn == nullptr) { PERR ("Unable to create pgsql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); @@ -1490,7 +1490,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, } if (success) { - if (be->sql_be.conn != NULL) + if (be->sql_be.conn != nullptr) { gnc_sql_connection_dispose (be->sql_be.conn); } @@ -1501,7 +1501,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, /* We should now have a proper session set up. * Let's start logging */ - basename = g_strjoin ("_", protocol, host, username, dbname, NULL); + basename = g_strjoin ("_", protocol, host, username, dbname, nullptr); translog_path = gnc_build_translog_path (basename); xaccLogSetBaseName (translog_path); PINFO ("logpath=%s", translog_path ? translog_path : "(null)"); @@ -1522,7 +1522,7 @@ exit: static GSList* conn_get_index_list_pgsql (dbi_conn conn) { - GSList* list = NULL; + GSList* list = nullptr; const gchar* errmsg; dbi_result result; PINFO ("Retrieving postgres index list\n"); @@ -1531,7 +1531,7 @@ conn_get_index_list_pgsql (dbi_conn conn) if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) { g_print ("Index Table Retrieval Error: %s\n", errmsg); - return NULL; + return nullptr; } while (dbi_result_next_row (result) != 0) { @@ -1560,20 +1560,20 @@ gnc_dbi_session_end (QofBackend* be_start) { GncDbiBackend* be = (GncDbiBackend*)be_start; - g_return_if_fail (be_start != NULL); + g_return_if_fail (be_start != nullptr); ENTER (" "); - if (be->conn != NULL) + if (be->conn != nullptr) { gnc_dbi_unlock (be_start); dbi_conn_close (be->conn); - be->conn = NULL; + be->conn = nullptr; } - if (be->sql_be.conn != NULL) + if (be->sql_be.conn != nullptr) { gnc_sql_connection_dispose (be->sql_be.conn); - be->sql_be.conn = NULL; + be->sql_be.conn = nullptr; } gnc_sql_finalize_version_info (&be->sql_be); @@ -1583,10 +1583,10 @@ gnc_dbi_session_end (QofBackend* be_start) static void gnc_dbi_destroy_backend (QofBackend* be) { - g_return_if_fail (be != NULL); + g_return_if_fail (be != nullptr); /* Stop transaction logging */ - xaccLogSetBaseName (NULL); + xaccLogSetBaseName (nullptr); qof_backend_destroy (be); @@ -1609,14 +1609,14 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) { GncDbiBackend* be = (GncDbiBackend*)qbe; - g_return_if_fail (qbe != NULL); - g_return_if_fail (book != NULL); + g_return_if_fail (qbe != nullptr); + g_return_if_fail (book != nullptr); ENTER ("be=%p, book=%p", be, book); if (loadType == LOAD_TYPE_INITIAL_LOAD) { - g_assert (be->primary_book == NULL); + g_assert (be->primary_book == nullptr); be->primary_book = book; // Set up table version information @@ -1664,7 +1664,7 @@ save_may_clobber_data (QofBackend* qbe) /* Data may be clobbered iff the number of tables != 0 */ dbname = dbi_conn_get_option (be->conn, "dbname"); - result = dbi_conn_get_table_list (be->conn, dbname, NULL); + result = dbi_conn_get_table_list (be->conn, dbname, nullptr); if (result) { retval = dbi_result_get_numrows (result) > 0; @@ -1678,7 +1678,7 @@ conn_table_manage_backup (GncDbiSqlConnection* conn, gchar* table_name, TableOpType op) { gchar* new_name = g_strdup_printf ("%s_%s", table_name, "back"); - dbi_result result = NULL; + dbi_result result = nullptr; switch (op) { case backup: @@ -1733,15 +1733,15 @@ conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, GSList* node; gboolean result = TRUE; GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (sql_conn); - GSList* full_table_name_list = NULL; + GSList* full_table_name_list = nullptr; const gchar* dbname = dbi_conn_get_option (conn->conn, "dbname"); - g_return_val_if_fail (table_name_list != NULL, FALSE); + g_return_val_if_fail (table_name_list != nullptr, FALSE); if (op == rollback) full_table_name_list = conn->provider->get_table_list (conn->conn, dbname); - for (node = table_name_list; node != NULL && result; node = node->next) + for (node = table_name_list; node != nullptr && result; node = node->next) { gchar* table_name = (gchar*)node->data; dbi_result result; @@ -1780,7 +1780,7 @@ conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, } } while (conn->retry); - if (result != NULL) + if (result != nullptr) { if (dbi_result_free (result) < 0) { @@ -1809,10 +1809,10 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (((GncSqlBackend*) be)->conn); GSList* table_list, *index_list, *iter; - const gchar* dbname = NULL; + const gchar* dbname = nullptr; - g_return_if_fail (be != NULL); - g_return_if_fail (book != NULL); + g_return_if_fail (be != nullptr); + g_return_if_fail (book != nullptr); ENTER ("book=%p, primary=%p", book, be->primary_book); dbname = dbi_conn_get_option (be->conn, "dbname"); @@ -1828,7 +1828,7 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) return; } index_list = conn->provider->get_index_list (conn->conn); - for (iter = index_list; iter != NULL; iter = g_slist_next (iter)) + for (iter = index_list; iter != nullptr; iter = g_slist_next (iter)) { const char* errmsg; conn->provider->drop_index (conn->conn, static_cast (iter->data)); @@ -1867,8 +1867,8 @@ gnc_dbi_begin_edit (QofBackend* qbe, QofInstance* inst) { GncDbiBackend* be = (GncDbiBackend*)qbe; - g_return_if_fail (be != NULL); - g_return_if_fail (inst != NULL); + g_return_if_fail (be != nullptr); + g_return_if_fail (inst != nullptr); gnc_sql_begin_edit (&be->sql_be, inst); } @@ -1878,8 +1878,8 @@ gnc_dbi_rollback_edit (QofBackend* qbe, QofInstance* inst) { GncDbiBackend* be = (GncDbiBackend*)qbe; - g_return_if_fail (be != NULL); - g_return_if_fail (inst != NULL); + g_return_if_fail (be != nullptr); + g_return_if_fail (inst != nullptr); gnc_sql_rollback_edit (&be->sql_be, inst); } @@ -1889,8 +1889,8 @@ gnc_dbi_commit_edit (QofBackend* qbe, QofInstance* inst) { GncDbiBackend* be = (GncDbiBackend*)qbe; - g_return_if_fail (be != NULL); - g_return_if_fail (inst != NULL); + g_return_if_fail (be != nullptr); + g_return_if_fail (inst != nullptr); gnc_sql_commit_edit (&be->sql_be, inst); } @@ -1915,8 +1915,8 @@ init_sql_backend (GncDbiBackend* dbi_be) be->rollback = gnc_dbi_rollback_edit; /* The gda backend will not be multi-user (for now)... */ - be->events_pending = NULL; - be->process_events = NULL; + be->events_pending = nullptr; + be->process_events = nullptr; /* The SQL/DBI backend doesn't need to be synced until it is * configured for multiuser access. */ @@ -1930,12 +1930,12 @@ init_sql_backend (GncDbiBackend* dbi_be) be->run_query = nullptr; be->free_query = nullptr; - be->export_fn = NULL; + be->export_fn = nullptr; gnc_sql_init (&dbi_be->sql_be); - dbi_be->sql_be.conn = NULL; - dbi_be->sql_be.book = NULL; + dbi_be->sql_be.conn = nullptr; + dbi_be->sql_be.book = nullptr; } static QofBackend* @@ -1948,7 +1948,7 @@ new_backend (void (*session_begin) (QofBackend*, QofSession*, const gchar*, QofBackend* be; dbi_be = g_new0 (GncDbiBackend, 1); - g_assert (dbi_be != NULL); + g_assert (dbi_be != nullptr); be = (QofBackend*)dbi_be; qof_backend_init (be); @@ -1992,14 +1992,14 @@ QofSQLITEBackendProvider::type_check(const char *uri) gchar* filename; // BAD if the path is null - g_return_val_if_fail (uri != NULL, FALSE); + g_return_val_if_fail (uri != nullptr, FALSE); filename = gnc_uri_get_path (uri); f = g_fopen (filename, "r"); g_free (filename); // OK if the file doesn't exist - new file - if (f == NULL) + if (f == nullptr) { PINFO ("doesn't exist (errno=%d) -> DBI", errno); return TRUE; @@ -2035,7 +2035,7 @@ gnc_module_init_backend_dbi (void) /* Initialize libdbi and see which drivers are available. Only register qof backends which have drivers available. */ driver_dir = g_getenv ("GNC_DBD_DIR"); - if (driver_dir == NULL) + if (driver_dir == nullptr) { PINFO ("GNC_DBD_DIR not set: using libdbi built-in default\n"); } @@ -2050,7 +2050,7 @@ gnc_module_init_backend_dbi (void) #endif if (num_drivers <= 0) { - gchar* dir = g_build_filename (gnc_path_get_libdir (), "dbd", NULL); + gchar* dir = g_build_filename (gnc_path_get_libdir (), "dbd", nullptr); #if HAVE_LIBDBI_R if (dbi_instance) return; @@ -2066,7 +2066,7 @@ gnc_module_init_backend_dbi (void) } else { - dbi_driver driver = NULL; + dbi_driver driver = nullptr; PINFO ("%d DBD drivers found\n", num_drivers); do @@ -2077,7 +2077,7 @@ gnc_module_init_backend_dbi (void) driver = dbi_driver_list (driver); #endif - if (driver != NULL) + if (driver != nullptr) { const gchar* name = dbi_driver_get_name (driver); @@ -2096,7 +2096,7 @@ gnc_module_init_backend_dbi (void) } } } - while (driver != NULL); + while (driver != nullptr); } if (have_sqlite3_driver) @@ -2148,7 +2148,7 @@ gnc_module_finalize_backend_dbi (void) if (dbi_instance) { dbi_shutdown_r (dbi_instance); - dbi_instance = NULL; + dbi_instance = nullptr; } #else dbi_shutdown (); @@ -2384,7 +2384,7 @@ conn_execute_nonselect_statement (GncSqlConnection* conn, result = dbi_conn_query (dbi_conn->conn, stmt->to_sql()); } while (dbi_conn->retry); - if (result == NULL) + if (result == nullptr && dbi_conn->last_error) { PERR ("Error executing SQL %s\n", stmt->to_sql()); return -1; @@ -2414,8 +2414,8 @@ conn_does_table_exist (GncSqlConnection* conn, const gchar* table_name) const gchar* dbname; gint status; - g_return_val_if_fail (conn != NULL, FALSE); - g_return_val_if_fail (table_name != NULL, FALSE); + g_return_val_if_fail (conn != nullptr, FALSE); + g_return_val_if_fail (table_name != nullptr, FALSE); dbname = dbi_conn_get_option (dbi_conn->conn, "dbname"); tables = dbi_conn_get_table_list (dbi_conn->conn, dbname, table_name); @@ -2461,7 +2461,7 @@ conn_begin_transaction (GncSqlConnection* conn) } while (dbi_conn->retry); - success = (result != NULL); + success = (result != nullptr); status = dbi_result_free (result); if (status < 0) { @@ -2488,7 +2488,7 @@ conn_rollback_transaction (GncSqlConnection* conn) DEBUG ("ROLLBACK\n"); const char* command = "ROLLBACK"; result = dbi_conn_query (dbi_conn->conn, command); - success = (result != NULL); + success = (result != nullptr); status = dbi_result_free (result); if (status < 0) @@ -2515,7 +2515,7 @@ conn_commit_transaction (GncSqlConnection* conn) DEBUG ("COMMIT\n"); result = dbi_conn_queryf (dbi_conn->conn, "COMMIT"); - success = (result != NULL); + success = (result != nullptr); status = dbi_result_free (result); if (status < 0) @@ -2538,9 +2538,9 @@ create_index_ddl (GncSqlConnection* conn, const char* index_name, { GString* ddl; - g_return_val_if_fail (conn != NULL, NULL); - g_return_val_if_fail (index_name != NULL, NULL); - g_return_val_if_fail (table_name != NULL, NULL); + g_return_val_if_fail (conn != nullptr, nullptr); + g_return_val_if_fail (index_name != nullptr, nullptr); + g_return_val_if_fail (table_name != nullptr, nullptr); ddl = g_string_new (""); g_string_printf (ddl, "CREATE INDEX %s ON %s (", index_name, table_name); @@ -2565,8 +2565,8 @@ add_columns_ddl(GncSqlConnection* conn, GString* ddl; GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - g_return_val_if_fail (conn != NULL, NULL); - g_return_val_if_fail (table_name != NULL, NULL); + g_return_val_if_fail (conn != nullptr, nullptr); + g_return_val_if_fail (table_name != nullptr, nullptr); ddl = g_string_new (""); g_string_printf (ddl, "ALTER TABLE %s ", table_name); @@ -2637,8 +2637,8 @@ conn_create_table_ddl_sqlite3 (GncSqlConnection* conn, GString* ddl; unsigned int col_num = 0; - g_return_val_if_fail (conn != NULL, NULL); - g_return_val_if_fail (table_name != NULL, NULL); + g_return_val_if_fail (conn != nullptr, nullptr); + g_return_val_if_fail (table_name != nullptr, nullptr); ddl = g_string_new (""); g_string_printf (ddl, "CREATE TABLE %s (", table_name); @@ -2719,8 +2719,8 @@ conn_create_table_ddl_mysql (GncSqlConnection* conn, const gchar* table_name, GString* ddl; unsigned int col_num = 0; - g_return_val_if_fail (conn != NULL, NULL); - g_return_val_if_fail (table_name != NULL, NULL); + g_return_val_if_fail (conn != nullptr, nullptr); + g_return_val_if_fail (table_name != nullptr, nullptr); ddl = g_string_new (""); g_string_printf (ddl, "CREATE TABLE %s (", table_name); @@ -2801,8 +2801,8 @@ conn_create_table_ddl_pgsql (GncSqlConnection* conn, const gchar* table_name, GString* ddl; unsigned int col_num = 0; - g_return_val_if_fail (conn != NULL, NULL); - g_return_val_if_fail (table_name != NULL, NULL); + g_return_val_if_fail (conn != nullptr, nullptr); + g_return_val_if_fail (table_name != nullptr, nullptr); ddl = g_string_new (""); g_string_printf (ddl, "CREATE TABLE %s (", table_name); @@ -2827,11 +2827,11 @@ conn_create_table (GncSqlConnection* conn, const gchar* table_name, gchar* ddl; dbi_result result; - g_return_val_if_fail (conn != NULL, FALSE); - g_return_val_if_fail (table_name != NULL, FALSE); + g_return_val_if_fail (conn != nullptr, FALSE); + g_return_val_if_fail (table_name != nullptr, FALSE); ddl = dbi_conn->provider->create_table_ddl(conn, table_name, info_vec); - if (ddl != NULL) + if (ddl != nullptr) { gint status; @@ -2861,12 +2861,12 @@ conn_create_index(GncSqlConnection* conn, const char* index_name, gchar* ddl; dbi_result result; - g_return_val_if_fail (conn != NULL, FALSE); - g_return_val_if_fail (index_name != NULL, FALSE); - g_return_val_if_fail (table_name != NULL, FALSE); + g_return_val_if_fail (conn != nullptr, FALSE); + g_return_val_if_fail (index_name != nullptr, FALSE); + g_return_val_if_fail (table_name != nullptr, FALSE); ddl = create_index_ddl (conn, index_name, table_name, col_table); - if (ddl != NULL) + if (ddl != nullptr) { gint status; @@ -2896,11 +2896,11 @@ conn_add_columns_to_table(GncSqlConnection* conn, const char* table_name, gchar* ddl; dbi_result result; - g_return_val_if_fail (conn != NULL, FALSE); - g_return_val_if_fail (table_name != NULL, FALSE); + g_return_val_if_fail (conn != nullptr, FALSE); + g_return_val_if_fail (table_name != nullptr, FALSE); ddl = add_columns_ddl(conn, table_name, info_vec); - if (ddl == NULL) + if (ddl == nullptr) return FALSE; DEBUG ("SQL: %s\n", ddl); @@ -2931,7 +2931,7 @@ conn_quote_string (const GncSqlConnection* conn, const char* unquoted_str) } else { - return NULL; + return nullptr; } } @@ -2939,9 +2939,9 @@ static GSList* conn_get_table_list (dbi_conn conn, const gchar* dbname) { dbi_result tables; - GSList* list = NULL; + GSList* list = nullptr; - tables = dbi_conn_get_table_list (conn, dbname, NULL); + tables = dbi_conn_get_table_list (conn, dbname, nullptr); while (dbi_result_next_row (tables) != 0) { const gchar* table_name; @@ -2962,12 +2962,12 @@ conn_get_table_list_sqlite3 (dbi_conn conn, const gchar* dbname) * its own use. */ GSList* list = conn_get_table_list (conn, dbname); change_made = TRUE; - while (list != NULL && change_made) + while (list != nullptr && change_made) { GSList* node; change_made = FALSE; - for (node = list; node != NULL; node = node->next) + for (node = list; node != nullptr; node = node->next) { const gchar* table_name = (const gchar*)node->data; @@ -2991,12 +2991,12 @@ conn_get_table_list_pgsql (dbi_conn conn, const gchar* dbname) /* Return the list, but remove the tables that postgresql adds from the information schema. */ GSList* list = conn_get_table_list (conn, dbname); change_made = TRUE; - while (list != NULL && change_made) + while (list != nullptr && change_made) { GSList* node; change_made = FALSE; - for (node = list; node != NULL; node = node->next) + for (node = list; node != nullptr; node = node->next) { const gchar* table_name = (const gchar*)node->data; @@ -3041,7 +3041,7 @@ conn_test_dbi_library (dbi_conn conn) result = dbi_conn_query (conn, "CREATE TEMPORARY TABLE numtest " "( test_int BIGINT, test_unsigned BIGINT," " test_double FLOAT8 )"); - if (result == NULL) + if (result == nullptr) { PWARN ("Test_DBI_Library: Create table failed"); return GNC_DBI_FAIL_SETUP; @@ -3053,7 +3053,7 @@ conn_test_dbi_library (dbi_conn conn) testlonglong, testulonglong, doublestr); result = dbi_conn_query (conn, querystr); g_free (querystr); - if (result == NULL) + if (result == nullptr) { PWARN ("Test_DBI_Library: Failed to insert test row into table"); return GNC_DBI_FAIL_SETUP; @@ -3061,7 +3061,7 @@ conn_test_dbi_library (dbi_conn conn) dbi_result_free (result); gnc_push_locale (LC_NUMERIC, "C"); result = dbi_conn_query (conn, "SELECT * FROM numtest"); - if (result == NULL) + if (result == nullptr) { const char* errmsg; dbi_conn_error (conn, &errmsg); @@ -3112,7 +3112,7 @@ create_dbi_connection (provider_functions_t* provider, GncDbiSqlConnection* dbi_conn; dbi_conn = g_new0 (GncDbiSqlConnection, 1); - g_assert (dbi_conn != NULL); + g_assert (dbi_conn != nullptr); dbi_conn->base.dispose = conn_dispose; dbi_conn->base.executeSelectStatement = conn_execute_select_statement; From 12e763884e3044483c9d0a008ccf1870c7d5ae40 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 18 Jun 2016 12:38:11 -0700 Subject: [PATCH 18/63] Use a std::unique_ptr for GncSqlStatement for better memory management. --- src/backend/dbi/gnc-backend-dbi.cpp | 9 +-- src/backend/sql/gnc-account-sql.cpp | 6 +- src/backend/sql/gnc-backend-sql.cpp | 87 +++++++++++------------- src/backend/sql/gnc-backend-sql.h | 18 ++--- src/backend/sql/gnc-bill-term-sql.cpp | 4 +- src/backend/sql/gnc-book-sql.cpp | 7 +- src/backend/sql/gnc-budget-sql.cpp | 17 ++--- src/backend/sql/gnc-commodity-sql.cpp | 6 +- src/backend/sql/gnc-customer-sql.cpp | 5 +- src/backend/sql/gnc-employee-sql.cpp | 5 +- src/backend/sql/gnc-entry-sql.cpp | 5 +- src/backend/sql/gnc-invoice-sql.cpp | 5 +- src/backend/sql/gnc-job-sql.cpp | 4 +- src/backend/sql/gnc-lots-sql.cpp | 6 +- src/backend/sql/gnc-order-sql.cpp | 4 +- src/backend/sql/gnc-price-sql.cpp | 6 +- src/backend/sql/gnc-recurrence-sql.cpp | 4 +- src/backend/sql/gnc-schedxaction-sql.cpp | 5 +- src/backend/sql/gnc-slots-sql.cpp | 24 +++---- src/backend/sql/gnc-tax-table-sql.cpp | 9 +-- src/backend/sql/gnc-transaction-sql.cpp | 29 +++----- src/backend/sql/gnc-vendor-sql.cpp | 5 +- 22 files changed, 99 insertions(+), 171 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index a7c7e7204e..e1c82f98ba 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -2349,7 +2349,8 @@ conn_dispose (GncSqlConnection* conn) } static GncSqlResultPtr -conn_execute_select_statement (GncSqlConnection* conn, GncSqlStatement* stmt) +conn_execute_select_statement (GncSqlConnection* conn, + const GncSqlStatementPtr& stmt) { GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; dbi_result result; @@ -2370,7 +2371,7 @@ conn_execute_select_statement (GncSqlConnection* conn, GncSqlStatement* stmt) static gint conn_execute_nonselect_statement (GncSqlConnection* conn, - GncSqlStatement* stmt) + const GncSqlStatementPtr& stmt) { GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; dbi_result result; @@ -2399,10 +2400,10 @@ conn_execute_nonselect_statement (GncSqlConnection* conn, return num_rows; } -static GncSqlStatement* +static GncSqlStatementPtr conn_create_statement_from_sql (GncSqlConnection* conn, const gchar* sql) { - return new GncDbiSqlStatement (conn, sql); + return std::unique_ptr(new GncDbiSqlStatement (conn, sql)); } static gboolean diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index bdb3bff121..f0114ff10c 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -213,7 +213,6 @@ load_single_account (GncSqlBackend* be, GncSqlRow& row, void GncSqlAccountBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt = NULL; QofBook* pBook; GList* l_accounts_needing_parents = NULL; GSList* bal_slist; @@ -225,14 +224,13 @@ GncSqlAccountBackend::load_all (GncSqlBackend* be) pBook = be->book; - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - if (stmt == NULL) + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + if (stmt == nullptr) { LEAVE ("stmt == NULL"); return; } auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; for (auto row : *result) load_single_account (be, row, &l_accounts_needing_parents); diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index b4b3042293..58cf98d45f 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -86,18 +86,21 @@ static void gnc_sql_init_object_handlers (void); static void update_progress (GncSqlBackend* be); static void finish_progress (GncSqlBackend* be); static gboolean reset_version_info (GncSqlBackend* be); -static GncSqlStatement* build_insert_statement (GncSqlBackend* be, - const gchar* table_name, - QofIdTypeConst obj_name, gpointer pObject, - const EntryVec& table); -static GncSqlStatement* build_update_statement (GncSqlBackend* be, - const gchar* table_name, - QofIdTypeConst obj_name, gpointer pObject, - const EntryVec& table); -static GncSqlStatement* build_delete_statement (GncSqlBackend* be, - const gchar* table_name, - QofIdTypeConst obj_name, gpointer pObject, - const EntryVec& table); +static GncSqlStatementPtr build_insert_statement (GncSqlBackend* be, + const gchar* table_name, + QofIdTypeConst obj_name, + gpointer pObject, + const EntryVec& table); +static GncSqlStatementPtr build_update_statement (GncSqlBackend* be, + const gchar* table_name, + QofIdTypeConst obj_name, + gpointer pObject, + const EntryVec& table); +static GncSqlStatementPtr build_delete_statement (GncSqlBackend* be, + const gchar* table_name, + QofIdTypeConst obj_name, + gpointer pObject, + const EntryVec& table); static GList* post_load_commodities = NULL; @@ -1832,22 +1835,19 @@ gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow& row, } /* ================================================================= */ -GncSqlStatement* +GncSqlStatementPtr gnc_sql_create_select_statement (GncSqlBackend* be, const gchar* table_name) { - gchar* sql; - GncSqlStatement* stmt; - g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (table_name != NULL, NULL); - sql = g_strdup_printf ("SELECT * FROM %s", table_name); - stmt = gnc_sql_create_statement_from_sql (be, sql); + auto sql = g_strdup_printf ("SELECT * FROM %s", table_name); + auto stmt = gnc_sql_create_statement_from_sql (be, sql); g_free (sql); return stmt; } -static GncSqlStatement* +static GncSqlStatementPtr create_single_col_select_statement (GncSqlBackend* be, const gchar* table_name, const GncSqlColumnTableEntryPtr table_row) @@ -1862,7 +1862,8 @@ create_single_col_select_statement (GncSqlBackend* be, /* ================================================================= */ GncSqlResultPtr -gnc_sql_execute_select_statement (GncSqlBackend* be, GncSqlStatement* stmt) +gnc_sql_execute_select_statement (GncSqlBackend* be, + const GncSqlStatementPtr& stmt) { g_return_val_if_fail (be != NULL, NULL); @@ -1879,15 +1880,13 @@ gnc_sql_execute_select_statement (GncSqlBackend* be, GncSqlStatement* stmt) return result; } -GncSqlStatement* +GncSqlStatementPtr gnc_sql_create_statement_from_sql (GncSqlBackend* be, const gchar* sql) { - GncSqlStatement* stmt; - g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (sql != NULL, NULL); - stmt = gnc_sql_connection_create_statement_from_sql (be->conn, sql); + auto stmt = gnc_sql_connection_create_statement_from_sql (be->conn, sql); if (stmt == NULL) { PERR ("SQL error: %s\n", sql); @@ -1901,18 +1900,15 @@ gnc_sql_create_statement_from_sql (GncSqlBackend* be, const gchar* sql) GncSqlResultPtr gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) { - GncSqlStatement* stmt; - g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (sql != NULL, NULL); - stmt = gnc_sql_create_statement_from_sql (be, sql); - if (stmt == NULL) + auto stmt = gnc_sql_create_statement_from_sql (be, sql); + if (stmt == nullptr) { - return NULL; + return nullptr; } auto result = gnc_sql_connection_execute_select_statement (be->conn, stmt); - delete stmt; if (result == NULL) { PERR ("SQL error: %s\n", sql); @@ -1926,19 +1922,16 @@ gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) gint gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql) { - GncSqlStatement* stmt; - gint result; - g_return_val_if_fail (be != NULL, 0); g_return_val_if_fail (sql != NULL, 0); - stmt = gnc_sql_create_statement_from_sql (be, sql); + auto stmt = gnc_sql_create_statement_from_sql (be, sql); if (stmt == NULL) { return -1; } - result = gnc_sql_connection_execute_nonselect_statement (be->conn, stmt); - delete stmt; + auto result = gnc_sql_connection_execute_nonselect_statement (be->conn, + stmt); return result; } @@ -1987,7 +1980,6 @@ get_object_values (GncSqlBackend* be, QofIdTypeConst obj_name, return vec; } - gboolean gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, @@ -2007,7 +1999,6 @@ gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, PairVec values{get_object_values(be, obj_name, pObject, table)}; stmt->add_where_cond(obj_name, values); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; if (result != NULL) { auto retval = result->size() > 0; @@ -2024,7 +2015,7 @@ gnc_sql_do_db_operation (GncSqlBackend* be, QofIdTypeConst obj_name, gpointer pObject, const EntryVec& table) { - GncSqlStatement* stmt = NULL; + GncSqlStatementPtr stmt; gboolean ok = FALSE; g_return_val_if_fail (be != NULL, FALSE); @@ -2048,7 +2039,7 @@ gnc_sql_do_db_operation (GncSqlBackend* be, { g_assert (FALSE); } - if (stmt != NULL) + if (stmt != nullptr) { gint result; @@ -2063,19 +2054,18 @@ gnc_sql_do_db_operation (GncSqlBackend* be, { ok = TRUE; } - delete stmt; } return ok; } -static GncSqlStatement* +static GncSqlStatementPtr build_insert_statement (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, const EntryVec& table) { - GncSqlStatement* stmt; + GncSqlStatementPtr stmt; PairVec col_values; std::ostringstream sql; @@ -2108,13 +2098,13 @@ build_insert_statement (GncSqlBackend* be, return stmt; } -static GncSqlStatement* +static GncSqlStatementPtr build_update_statement (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, const EntryVec& table) { - GncSqlStatement* stmt; + GncSqlStatementPtr stmt; std::ostringstream sql; g_return_val_if_fail (be != NULL, NULL); @@ -2145,13 +2135,12 @@ build_update_statement (GncSqlBackend* be, return stmt; } -static GncSqlStatement* +static GncSqlStatementPtr build_delete_statement (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, gpointer pObject, const EntryVec& table) { - GncSqlStatement* stmt; std::ostringstream sql; g_return_val_if_fail (be != NULL, NULL); @@ -2160,8 +2149,8 @@ build_delete_statement (GncSqlBackend* be, g_return_val_if_fail (pObject != NULL, NULL); sql << "DELETE FROM " << table_name; - stmt = gnc_sql_connection_create_statement_from_sql (be->conn, - sql.str().c_str()); + auto stmt = gnc_sql_connection_create_statement_from_sql (be->conn, + sql.str().c_str()); /* WHERE */ PairVec values; diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 78fc33961f..5df615bd49 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -155,6 +155,8 @@ public: virtual void add_where_cond (QofIdTypeConst, const PairVec&) = 0; }; +using GncSqlStatementPtr = std::unique_ptr; + /** * @struct GncSqlConnection * @@ -164,9 +166,9 @@ public: struct GncSqlConnection { void (*dispose) (GncSqlConnection*); - GncSqlResultPtr (*executeSelectStatement) (GncSqlConnection*, GncSqlStatement*); /**< Returns NULL if error */ - gint (*executeNonSelectStatement) (GncSqlConnection*, GncSqlStatement*); /**< Returns -1 if error */ - GncSqlStatement* (*createStatementFromSql) (GncSqlConnection*, const gchar*); + GncSqlResultPtr (*executeSelectStatement) (GncSqlConnection*, const GncSqlStatementPtr&); /**< Returns NULL if error */ + gint (*executeNonSelectStatement) (GncSqlConnection*, const GncSqlStatementPtr&); /**< Returns -1 if error */ + GncSqlStatementPtr (*createStatementFromSql) (GncSqlConnection*, const gchar*); gboolean (*doesTableExist) (GncSqlConnection*, const gchar*); /**< Returns true if successful */ gboolean (*beginTransaction) (GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ gboolean (*rollbackTransaction) (GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ @@ -763,7 +765,7 @@ gboolean gnc_sql_do_db_operation (GncSqlBackend* be, * @return Results, or NULL if an error has occured */ GncSqlResultPtr gnc_sql_execute_select_statement (GncSqlBackend* be, - GncSqlStatement* statement); + const GncSqlStatementPtr& statement); /** * Executes an SQL SELECT statement from an SQL char string and returns the @@ -792,8 +794,8 @@ gint gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql); * @param sql SQL char string * @return Statement */ -GncSqlStatement* gnc_sql_create_statement_from_sql (GncSqlBackend* be, - const gchar* sql); +GncSqlStatementPtr gnc_sql_create_statement_from_sql (GncSqlBackend* be, + const gchar* sql); /** * Loads a Gnucash object from the database. @@ -906,8 +908,8 @@ const GncGUID* gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow& row); * @param table_name Table name * @return Statement */ -GncSqlStatement* gnc_sql_create_select_statement (GncSqlBackend* be, - const gchar* table_name); +GncSqlStatementPtr gnc_sql_create_select_statement (GncSqlBackend* be, + const gchar* table_name); /** * Appends the ascii strings for a list of GUIDs to the end of an SQL string. diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index af06bd2fb9..3f61d9b78c 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -235,13 +235,11 @@ load_single_billterm (GncSqlBackend* be, GncSqlRow& row, void GncSqlBillTermBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; GList* list = NULL; GList* l_billterms_needing_parents = NULL; diff --git a/src/backend/sql/gnc-book-sql.cpp b/src/backend/sql/gnc-book-sql.cpp index 2145172b21..081a74439c 100644 --- a/src/backend/sql/gnc-book-sql.cpp +++ b/src/backend/sql/gnc-book-sql.cpp @@ -169,15 +169,12 @@ load_single_book (GncSqlBackend* be, GncSqlRow& row) void GncSqlBookBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; - g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, BOOK_TABLE); - if (stmt != NULL) + auto stmt = gnc_sql_create_select_statement (be, BOOK_TABLE); + if (stmt != nullptr) { auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; auto row = result->begin(); /* If there are no rows, try committing the book; unset diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index beb87c27ea..8c76172394 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -206,22 +206,19 @@ static void load_budget_amounts (GncSqlBackend* be, GncBudget* budget) { gchar guid_buf[GUID_ENCODING_LENGTH + 1]; - gchar* sql; - GncSqlStatement* stmt; g_return_if_fail (be != NULL); g_return_if_fail (budget != NULL); (void)guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (budget)), guid_buf); - sql = g_strdup_printf ("SELECT * FROM %s WHERE budget_guid='%s'", - AMOUNTS_TABLE, guid_buf); - stmt = gnc_sql_create_statement_from_sql (be, sql); + auto sql = g_strdup_printf ("SELECT * FROM %s WHERE budget_guid='%s'", + AMOUNTS_TABLE, guid_buf); + auto stmt = gnc_sql_create_statement_from_sql (be, sql); g_free (sql); - if (stmt != NULL) + if (stmt != nullptr) { auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; budget_amount_info_t info = { budget, NULL, 0 }; for (auto row : *result) @@ -335,16 +332,14 @@ load_single_budget (GncSqlBackend* be, GncSqlRow& row) void GncSqlBudgetBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; GList* list = NULL; g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, BUDGET_TABLE); - if (stmt != NULL) + auto stmt = gnc_sql_create_select_statement (be, BUDGET_TABLE); + if (stmt != nullptr) { auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; for (auto row : *result) { auto b = load_single_budget (be, row); diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index a77090d3d3..efac9acc46 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -143,14 +143,12 @@ load_single_commodity (GncSqlBackend* be, GncSqlRow& row) void GncSqlCommodityBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; gnc_commodity_table* pTable; pTable = gnc_commodity_table_get_table (be->book); - stmt = gnc_sql_create_select_statement (be, COMMODITIES_TABLE); - if (stmt == NULL) return; + auto stmt = gnc_sql_create_select_statement (be, COMMODITIES_TABLE); + if (stmt == nullptr) return; auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; for (auto row : *result) { diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index c8b8c6ab09..ce923fda08 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -124,14 +124,11 @@ load_single_customer (GncSqlBackend* be, GncSqlRow& row) void GncSqlCustomerBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; - g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; GList* list = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index b66ba07c1f..166596a193 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -110,13 +110,10 @@ load_single_employee (GncSqlBackend* be, GncSqlRow& row) void GncSqlEmployeeBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; - g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; GList* list = NULL; diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index 75195df86b..c9ca9c10ea 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -192,13 +192,10 @@ load_single_entry (GncSqlBackend* be, GncSqlRow& row) void GncSqlEntryBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; - g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; GList* list = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index 71eb5938be..e3e5b036de 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -131,13 +131,10 @@ load_single_invoice (GncSqlBackend* be, GncSqlRow& row) void GncSqlInvoiceBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; - g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; GList* list = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index e7992e49b1..da052c442d 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -103,12 +103,10 @@ load_single_job (GncSqlBackend* be, GncSqlRow& row) void GncSqlJobBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; GList* list = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index 5693459bcc..4e3bebe979 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -125,14 +125,12 @@ load_single_lot (GncSqlBackend* be, GncSqlRow& row) void GncSqlLotsBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - if (stmt != NULL) + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + if (stmt != nullptr) { auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; if (result->begin () == nullptr) return; for (auto row : *result) diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index 57f695446c..f330f3e1ec 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -103,12 +103,10 @@ load_single_order (GncSqlBackend* be, GncSqlRow& row) void GncSqlOrderBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; GList* list = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-price-sql.cpp b/src/backend/sql/gnc-price-sql.cpp index f3c2f4e80e..1fa67b8c11 100644 --- a/src/backend/sql/gnc-price-sql.cpp +++ b/src/backend/sql/gnc-price-sql.cpp @@ -101,7 +101,6 @@ load_single_price (GncSqlBackend* be, GncSqlRow& row) void GncSqlPriceBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; QofBook* pBook; GNCPriceDB* pPriceDB; @@ -109,11 +108,10 @@ GncSqlPriceBackend::load_all (GncSqlBackend* be) pBook = be->book; pPriceDB = gnc_pricedb_get_db (pBook); - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - if (stmt != NULL) + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + if (stmt != nullptr) { auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; if (result->begin() == result->end()) return; diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index 44a1675f54..112bcabd1c 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -314,7 +314,6 @@ gnc_sql_set_recurrences_from_db (GncSqlBackend* be, const GncGUID* guid) { gchar* buf; gchar guid_buf[GUID_ENCODING_LENGTH + 1]; - GncSqlStatement* stmt; g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (guid != NULL, NULL); @@ -322,10 +321,9 @@ gnc_sql_set_recurrences_from_db (GncSqlBackend* be, const GncGUID* guid) (void)guid_to_string_buff (guid, guid_buf); buf = g_strdup_printf ("SELECT * FROM %s WHERE obj_guid='%s'", TABLE_NAME, guid_buf); - stmt = gnc_sql_connection_create_statement_from_sql (be->conn, buf); + auto stmt = gnc_sql_connection_create_statement_from_sql (be->conn, buf); g_free (buf); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; return result; } diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index 857507ad4d..2ed4002ae7 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -121,14 +121,11 @@ load_single_sx (GncSqlBackend* be, GncSqlRow& row) void GncSqlSchedXactionBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt = NULL; - g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, SCHEDXACTION_TABLE); + auto stmt = gnc_sql_create_select_statement (be, SCHEDXACTION_TABLE); if (stmt == NULL) return; auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; SchedXactions* sxes; GList* list = NULL; sxes = gnc_book_get_schedxactions (be->book); diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index 2a682a9fc2..b87dfd6297 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -732,7 +732,6 @@ gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid) { gchar* buf; gchar guid_buf[GUID_ENCODING_LENGTH + 1]; - GncSqlStatement* stmt; slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID, NULL, FRAME, NULL, g_string_new (NULL) }; g_return_val_if_fail (be != NULL, FALSE); @@ -742,12 +741,11 @@ gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid) buf = g_strdup_printf ("SELECT * FROM %s WHERE obj_guid='%s' and slot_type in ('%d', '%d') and not guid_val is null", TABLE_NAME, guid_buf, KvpValue::Type::FRAME, KvpValue::Type::GLIST); - stmt = gnc_sql_create_statement_from_sql (be, buf); + auto stmt = gnc_sql_create_statement_from_sql (be, buf); g_free (buf); - if (stmt != NULL) + if (stmt != nullptr) { auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; for (auto row : *result) { try @@ -828,7 +826,6 @@ slots_load_info (slot_info_t* pInfo) { gchar* buf; gchar guid_buf[GUID_ENCODING_LENGTH + 1]; - GncSqlStatement* stmt; g_return_if_fail (pInfo != NULL); g_return_if_fail (pInfo->be != NULL); @@ -839,12 +836,11 @@ slots_load_info (slot_info_t* pInfo) buf = g_strdup_printf ("SELECT * FROM %s WHERE obj_guid='%s'", TABLE_NAME, guid_buf); - stmt = gnc_sql_create_statement_from_sql (pInfo->be, buf); + auto stmt = gnc_sql_create_statement_from_sql (pInfo->be, buf); g_free (buf); - if (stmt != NULL) + if (stmt != nullptr) { auto result = gnc_sql_execute_select_statement (pInfo->be, stmt); - delete stmt; for (auto row : *result) load_slot (pInfo, row); } @@ -893,7 +889,6 @@ void gnc_sql_slots_load_for_list (GncSqlBackend* be, GList* list) { QofCollection* coll; - GncSqlStatement* stmt; GString* sql; gboolean single_item; @@ -926,8 +921,8 @@ gnc_sql_slots_load_for_list (GncSqlBackend* be, GList* list) } // Execute the query and load the slots - stmt = gnc_sql_create_statement_from_sql (be, sql->str); - if (stmt == NULL) + auto stmt = gnc_sql_create_statement_from_sql (be, sql->str); + if (stmt == nullptr) { PERR ("stmt == NULL, SQL = '%s'\n", sql->str); (void)g_string_free (sql, TRUE); @@ -935,7 +930,6 @@ gnc_sql_slots_load_for_list (GncSqlBackend* be, GList* list) } (void)g_string_free (sql, TRUE); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; for (auto row : *result) load_slot_for_list_item (be, row, coll); } @@ -982,7 +976,6 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be, BookLookupFn lookup_fn) { gchar* sql; - GncSqlStatement* stmt; g_return_if_fail (be != NULL); @@ -994,8 +987,8 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be, subquery); // Execute the query and load the slots - stmt = gnc_sql_create_statement_from_sql (be, sql); - if (stmt == NULL) + auto stmt = gnc_sql_create_statement_from_sql (be, sql); + if (stmt == nullptr) { PERR ("stmt == NULL, SQL = '%s'\n", sql); g_free (sql); @@ -1003,7 +996,6 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be, } g_free (sql); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; for (auto row : *result) load_slot_for_book_object (be, row, lookup_fn); } diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index f336ef2e4c..ca22a60f3f 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -227,7 +227,6 @@ load_taxtable_entries (GncSqlBackend* be, GncTaxTable* tt) gchar guid_buf[GUID_ENCODING_LENGTH + 1]; GValue value; gchar* buf; - GncSqlStatement* stmt; g_return_if_fail (be != NULL); g_return_if_fail (tt != NULL); @@ -238,10 +237,9 @@ load_taxtable_entries (GncSqlBackend* be, GncTaxTable* tt) g_value_set_string (&value, guid_buf); buf = g_strdup_printf ("SELECT * FROM %s WHERE taxtable='%s'", TTENTRIES_TABLE_NAME, guid_buf); - stmt = gnc_sql_connection_create_statement_from_sql (be->conn, buf); + auto stmt = gnc_sql_connection_create_statement_from_sql (be->conn, buf); g_free (buf); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; for (auto row : *result) load_single_ttentry (be, row, tt); } @@ -293,14 +291,11 @@ load_single_taxtable (GncSqlBackend* be, GncSqlRow& row, void GncSqlTaxTableBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; - g_return_if_fail (be != NULL); /* First time, create the query */ - stmt = gnc_sql_create_select_statement (be, TT_TABLE_NAME); + auto stmt = gnc_sql_create_select_statement (be, TT_TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; GList* tt_needing_parents = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index d64a797423..f595eba66c 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -355,7 +355,7 @@ typedef struct * @param stmt SQL statement */ static void -query_transactions (GncSqlBackend* be, GncSqlStatement* stmt) +query_transactions (GncSqlBackend* be, const GncSqlStatementPtr& stmt) { g_return_if_fail (be != NULL); g_return_if_fail (stmt != NULL); @@ -765,7 +765,6 @@ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* be, const GncGUID* guid; gchar guid_buf[GUID_ENCODING_LENGTH + 1]; gchar* query_sql; - GncSqlStatement* stmt; g_return_if_fail (be != NULL); g_return_if_fail (account != NULL); @@ -775,12 +774,11 @@ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* be, 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); - stmt = gnc_sql_create_statement_from_sql (be, query_sql); + auto stmt = gnc_sql_create_statement_from_sql (be, query_sql); g_free (query_sql); - if (stmt != NULL) + if (stmt != nullptr) { query_transactions (be, stmt); - delete stmt; } } @@ -793,18 +791,14 @@ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* be, void GncSqlTransBackend::load_all (GncSqlBackend* be) { - gchar* query_sql; - GncSqlStatement* stmt; - g_return_if_fail (be != NULL); - query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE); - stmt = gnc_sql_create_statement_from_sql (be, query_sql); + auto query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE); + auto stmt = gnc_sql_create_statement_from_sql (be, query_sql); g_free (query_sql); - if (stmt != NULL) + if (stmt != nullptr) { query_transactions (be, stmt); - delete stmt; } } @@ -1033,7 +1027,7 @@ convert_query_term_to_sql (const GncSqlBackend* be, const gchar* fieldName, typedef struct { - GncSqlStatement* stmt; + GncSqlStatementPtr stmt; gboolean has_been_run; } split_query_info_t; @@ -1213,8 +1207,7 @@ run_split_query (GncSqlBackend* be, gpointer pQuery) { query_transactions (be, query_info->stmt); query_info->has_been_run = TRUE; - delete query_info->stmt; - query_info->stmt = NULL; + query_info->stmt = nullptr; } } @@ -1300,7 +1293,6 @@ GSList* gnc_sql_get_account_balances_slist (GncSqlBackend* be) { #if LOAD_TRANSACTIONS_AS_NEEDED - GncSqlStatement* stmt; gchar* buf; GSList* bal_slist = NULL; @@ -1308,11 +1300,10 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be) 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); - stmt = gnc_sql_create_statement_from_sql (be, buf); - g_assert (stmt != NULL); + auto stmt = gnc_sql_create_statement_from_sql (be, buf); + g_assert (stmt != nullptr); g_free (buf); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; acct_balances_t* bal = NULL; for (auto row : *result) diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index e2fe4252f1..3c40be7862 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -113,13 +113,10 @@ load_single_vendor (GncSqlBackend* be, GncSqlRow& row) void GncSqlVendorBackend::load_all (GncSqlBackend* be) { - GncSqlStatement* stmt; - g_return_if_fail (be != NULL); - stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - delete stmt; GList* list = NULL; for (auto row : *result) From cfa3ab24f68250c6f04b158763874715826ffa09 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 18 Jun 2016 12:40:28 -0700 Subject: [PATCH 19/63] Convert GncSqlConnection to a C++ class. --- src/backend/dbi/gnc-backend-dbi-priv.h | 111 +++- src/backend/dbi/gnc-backend-dbi.cpp | 552 +++++++----------- .../dbi/test/test-backend-dbi-basic.cpp | 6 +- src/backend/dbi/test/test-dbi-stuff.cpp | 6 +- src/backend/sql/gnc-backend-sql.cpp | 55 +- src/backend/sql/gnc-backend-sql.h | 73 +-- src/backend/sql/gnc-bill-term-sql.cpp | 19 +- src/backend/sql/gnc-customer-sql.cpp | 4 +- src/backend/sql/gnc-recurrence-sql.cpp | 2 +- src/backend/sql/gnc-tax-table-sql.cpp | 2 +- .../sql/test/utest-gnc-backend-sql.cpp | 86 ++- 11 files changed, 448 insertions(+), 468 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi-priv.h b/src/backend/dbi/gnc-backend-dbi-priv.h index 0743771217..41d46f13d1 100644 --- a/src/backend/dbi/gnc-backend-dbi-priv.h +++ b/src/backend/dbi/gnc-backend-dbi-priv.h @@ -32,6 +32,13 @@ extern "C" #endif #include "gnc-backend-sql.h" +enum class DbType +{ + DBI_SQLITE, + DBI_MYSQL, + DBI_PGSQL +}; + /** * Options to conn_table_operation * @var drop Drop (remove without recourse) the table from the database @@ -62,7 +69,7 @@ typedef enum GNC_DBI_FAIL_TEST } GncDbiTestResult; -typedef gchar* (*CREATE_TABLE_DDL_FN) (GncSqlConnection* conn, +typedef gchar* (*CREATE_TABLE_DDL_FN) (const GncSqlConnection* conn, const gchar* table_name, const ColVec& info_vec); typedef GSList* (*GET_TABLE_LIST_FN) (dbi_conn conn, const gchar* dbname); @@ -79,7 +86,9 @@ typedef struct DROP_INDEX_FN drop_index; } provider_functions_t; - +/** + * Implementations of GncSqlBackend. + */ struct GncDbiBackend_struct { GncSqlBackend sql_be; @@ -100,22 +109,90 @@ struct GncDbiBackend_struct typedef struct GncDbiBackend_struct GncDbiBackend; -typedef struct +class GncDbiSqlConnection : public GncSqlConnection { - GncSqlConnection base; +public: + GncDbiSqlConnection (provider_functions_t* provider, QofBackend* qbe, + dbi_conn conn) : + m_qbe{qbe}, m_conn{conn}, m_provider{provider}, m_conn_ok{true}, + m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, m_retry{false} {} + ~GncDbiSqlConnection() override = default; + GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr&) + noexcept override; + int execute_nonselect_statement (const GncSqlStatementPtr&) + noexcept override; + GncSqlStatementPtr create_statement_from_sql (const std::string&) + const noexcept override; + bool does_table_exist (const std::string&) const noexcept override; + bool begin_transaction () noexcept override; + bool rollback_transaction () const noexcept override; + bool commit_transaction () const noexcept override; + bool create_table (const std::string&, const ColVec&) const noexcept override; + bool create_index (const std::string&, const std::string&, const EntryVec&) + const noexcept override; + bool add_columns_to_table (const std::string&, const ColVec&) + const noexcept override; + std::string quote_string (const std::string&) const noexcept override; + QofBackend* qbe () const noexcept { return m_qbe; } + dbi_conn conn() const noexcept { return m_conn; } + provider_functions_t* provider() { return m_provider; } + inline void set_error (int error, int repeat, bool retry) noexcept + { + m_last_error = error; + m_error_repeat = repeat; + m_retry = retry; + } + inline void init_error () noexcept + { + set_error(ERR_BACKEND_NO_ERR, 0, false); + } + /** Check if the dbi connection is valid. If not attempt to re-establish it + * Returns TRUE is there is a valid connection in the end or FALSE otherwise + */ + bool verify() noexcept; + bool retry_connection(const char* msg) noexcept; + dbi_result table_manage_backup(const std::string& table_name, TableOpType op); + /* FIXME: These three friend functions should really be members, but doing + * that is too invasive just yet. */ + friend gboolean conn_table_operation (GncSqlConnection* sql_conn, + GSList* table_name_list, + TableOpType op); + friend void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book); + friend gchar* add_columns_ddl(const GncSqlConnection* conn, + const gchar* table_name, + const ColVec& info_vec); - QofBackend* qbe; - dbi_conn conn; - provider_functions_t* provider; - gboolean conn_ok; // Used by the error handler routines to flag if the connection is ok to use - gint last_error; // Code of the last error that occurred. This is set in the error callback function - gint error_repeat; // Used in case of transient errors. After such error, another attempt at the - // original call is allowed. error_repeat tracks the number of attempts and can - // be used to prevent infinite loops. - gboolean retry; // Signals the calling function that it should retry (the error handler detected - // transient error and managed to resolve it, but it can't run the original query) +private: + QofBackend* m_qbe; + dbi_conn m_conn; + provider_functions_t* m_provider; + /** Used by the error handler routines to flag if the connection is ok to + * use + */ + bool m_conn_ok; + /** Code of the last error that occurred. This is set in the error callback + * function. + */ + int m_last_error; + /** Used in case of transient errors. After such error, another attempt at + * the original call is allowed. error_repeat tracks the number of attempts + * and can be used to prevent infinite loops. + */ + int m_error_repeat; + /** Signals the calling function that it should retry (the error handler + * detected transient error and managed to resolve it, but it can't run the + * original query) + */ + gboolean m_retry; + +}; + +gboolean conn_table_operation (GncSqlConnection* sql_conn, + GSList* table_name_list, TableOpType op); +void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book); +gchar* add_columns_ddl(const GncSqlConnection* conn, const gchar* table_name, + const ColVec& info_vec); -} GncDbiSqlConnection; /* external access required for tests */ std::string adjust_sql_options_string(const std::string&); @@ -123,7 +200,7 @@ std::string adjust_sql_options_string(const std::string&); class GncDbiSqlResult : public GncSqlResult { public: - GncDbiSqlResult(GncDbiSqlConnection* conn, dbi_result result) : + GncDbiSqlResult(const GncDbiSqlConnection* conn, dbi_result result) : m_conn{conn}, m_dbi_result{result}, m_iter{this}, m_row{&m_iter}, m_sentinel{nullptr} {} ~GncDbiSqlResult(); @@ -153,7 +230,7 @@ protected: GncDbiSqlResult* m_inst; }; private: - GncDbiSqlConnection* m_conn; + const GncDbiSqlConnection* m_conn; dbi_result m_dbi_result; IteratorImpl m_iter; GncSqlRow m_row; diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index e1c82f98ba..cabd8a4354 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -157,7 +157,7 @@ static gchar lock_table[] = "gnclock"; #define SQLITE3_URI_PREFIX (SQLITE3_URI_TYPE "://") #define PGSQL_DEFAULT_PORT 5432 -static gchar* conn_create_table_ddl_sqlite3 (GncSqlConnection* conn, +static gchar* conn_create_table_ddl_sqlite3 (const GncSqlConnection* conn, const gchar* table_name, const ColVec& info_vec); static GSList* conn_get_table_list (dbi_conn conn, const gchar* dbname); @@ -175,7 +175,7 @@ static provider_functions_t provider_sqlite3 = }; #define SQLITE3_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" -static gchar* conn_create_table_ddl_mysql (GncSqlConnection* conn, +static gchar* conn_create_table_ddl_mysql (const GncSqlConnection* conn, const gchar* table_name, const ColVec& info_vec); static void append_mysql_col_def (GString* ddl, const GncSqlColumnInfo& info); @@ -191,7 +191,7 @@ static provider_functions_t provider_mysql = }; #define MYSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" -static gchar* conn_create_table_ddl_pgsql (GncSqlConnection* conn, +static gchar* conn_create_table_ddl_pgsql (const GncSqlConnection* conn, const gchar* table_name, const ColVec& info_vec ); static GSList* conn_get_table_list_pgsql (dbi_conn conn, const gchar* dbname); @@ -213,15 +213,10 @@ static gboolean gnc_dbi_lock_database (QofBackend *qbe, gboolean ignore_lock); static void gnc_dbi_unlock (QofBackend *qbe); static gboolean save_may_clobber_data (QofBackend* qbe); -static gchar* create_index_ddl (GncSqlConnection* conn, +static gchar* create_index_ddl (const GncSqlConnection* conn, const gchar* index_name, const gchar* table_name, const EntryVec& col_table); -static gchar* add_columns_ddl (GncSqlConnection* conn, - const gchar* table_name, - const ColVec& info_vec); -static GncSqlConnection* create_dbi_connection (provider_functions_t* provider, - QofBackend* qbe, dbi_conn conn); static GncDbiTestResult conn_test_dbi_library (dbi_conn conn); #define GNC_DBI_PROVIDER_SQLITE (&provider_sqlite3) #define GNC_DBI_PROVIDER_MYSQL (&provider_mysql) @@ -245,45 +240,54 @@ gnc_table_slist_free (GSList* table_list) g_slist_free (table_list); } -static void -gnc_dbi_set_error (GncDbiSqlConnection* dbi_conn, gint last_error, - gint error_repeat, gboolean retry) -{ - g_return_if_fail (dbi_conn != nullptr); - - dbi_conn->last_error = last_error; - if (error_repeat > 0) - dbi_conn->error_repeat = dbi_conn->error_repeat + error_repeat; - else - dbi_conn->error_repeat = 0; - dbi_conn->retry = retry; -} - -static void -gnc_dbi_init_error (GncDbiSqlConnection* dbi_conn) -{ - gnc_dbi_set_error (dbi_conn, ERR_BACKEND_NO_ERR, 0, FALSE); -} - /* Check if the dbi connection is valid. If not attempt to re-establish it * Returns TRUE is there is a valid connection in the end or FALSE otherwise */ -static gboolean -gnc_dbi_verify_conn (GncDbiSqlConnection* dbi_conn) +bool +GncDbiSqlConnection::verify () noexcept { - if (dbi_conn->conn_ok) - return TRUE; + if (m_conn_ok) + return true; - /* We attempt to connect only once here. The error function will automatically - * re-attempt up until DBI_MAX_CONN_ATTEMPTS time to connect if this call fails. - * After all these attempts, conn_ok will indicate if there is a valid connection - * or not. + /* We attempt to connect only once here. The error function will + * automatically re-attempt up until DBI_MAX_CONN_ATTEMPTS time to connect + * if this call fails. After all these attempts, conn_ok will indicate if + * there is a valid connection or not. */ - gnc_dbi_init_error (dbi_conn); - dbi_conn->conn_ok = TRUE; - (void)dbi_conn_connect (dbi_conn->conn); + init_error (); + m_conn_ok = true; + (void)dbi_conn_connect (m_conn); - return dbi_conn->conn_ok; + return m_conn_ok; +} + +bool +GncDbiSqlConnection::retry_connection(const char* msg) + noexcept +{ + while (m_retry && m_error_repeat <= DBI_MAX_CONN_ATTEMPTS) + { + m_conn_ok = false; + if (dbi_conn_connect(m_conn) == 0) + { + init_error(); + m_conn_ok = true; + return true; + } +#ifdef G_OS_WIN32 + const guint backoff_msecs = 1; + Sleep (backoff_msecs * 2 << ++m_error_repeat); +#else + const guint backoff_usecs = 1000; + usleep (backoff_usecs * 2 << ++m_error_repeat); +#endif + PINFO ("DBI error: %s - Reconnecting...\n", msg); + + } + PERR ("DBI error: %s - Giving up after %d consecutive attempts.\n", msg, + DBI_MAX_CONN_ATTEMPTS); + m_conn_ok = false; + return false; } /* ================================================================= */ @@ -304,13 +308,12 @@ sqlite3_error_fn (dbi_conn conn, void* user_data) { const gchar* msg; GncDbiBackend *be = static_cast(user_data); -/* FIXME: Cast won't be necessary once GncDbiSqlConnection is a derived class of - * GncSqlConnection. */ +/* FIXME: GncSqlConnection doesn't have the error calls so we have to dynamic_cast from the connection stored in GncSqlBackend. Yuck. */ GncDbiSqlConnection *dbi_conn = - reinterpret_cast(be->sql_be.conn); - (void)dbi_conn_error(conn, &msg); - PERR( "DBI error: %s\n", msg ); - gnc_dbi_set_error(dbi_conn, ERR_BACKEND_MISC, 0, FALSE); + dynamic_cast(be->sql_be.conn); + int errnum = dbi_conn_error (conn, &msg); + PERR ("DBI error: %s\n", msg); + dbi_conn->set_error (ERR_BACKEND_MISC, 0, false); } static void @@ -449,9 +452,9 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, if (be->sql_be.conn != nullptr) { - gnc_sql_connection_dispose (be->sql_be.conn); + delete (be->sql_be.conn); } - be->sql_be.conn = create_dbi_connection (GNC_DBI_PROVIDER_SQLITE, qbe, + be->sql_be.conn = new GncDbiSqlConnection (GNC_DBI_PROVIDER_SQLITE, qbe, be->conn); be->sql_be.timespec_format = SQLITE3_TIMESPEC_STR_FORMAT; @@ -502,16 +505,11 @@ static void mysql_error_fn (dbi_conn conn, void* user_data) { GncDbiBackend* be = (GncDbiBackend*)user_data; - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)be->sql_be.conn; - const gchar* msg; - gint err_num; -#ifdef G_OS_WIN32 - const guint backoff_msecs = 1; -#else - const guint backoff_usecs = 1000; -#endif + GncDbiSqlConnection* dbi_conn = + dynamic_cast(be->sql_be.conn); + const char* msg; - err_num = dbi_conn_error (conn, &msg); + auto err_num = dbi_conn_error (conn, &msg); /* Note: the sql connection may not have been initialized yet * so let's be careful with using it @@ -543,39 +541,19 @@ mysql_error_fn (dbi_conn conn, void* user_data) { PINFO ("DBI error: %s - Reconnecting...\n", msg); if (dbi_conn) - gnc_dbi_set_error (dbi_conn, ERR_BACKEND_CONN_LOST, 1, TRUE); - dbi_conn->conn_ok = TRUE; - (void)dbi_conn_connect (conn); + dbi_conn->set_error (ERR_BACKEND_CONN_LOST, 1, true); + dbi_conn->retry_connection(msg); } else if (err_num == 2003) // Unable to connect { - if (dbi_conn->error_repeat >= DBI_MAX_CONN_ATTEMPTS) - { - PERR ("DBI error: %s - Giving up after %d consecutive attempts.\n", msg, - DBI_MAX_CONN_ATTEMPTS); - if (dbi_conn) - gnc_dbi_set_error (dbi_conn, ERR_BACKEND_CANT_CONNECT, 0, FALSE); - dbi_conn->conn_ok = FALSE; - } - else - { -#ifdef G_OS_WIN32 - Sleep (backoff_msecs * 2 << dbi_conn->error_repeat); -#else - usleep (backoff_usecs * 2 << dbi_conn->error_repeat); -#endif - PINFO ("DBI error: %s - Reconnecting...\n", msg); - if (dbi_conn) - gnc_dbi_set_error (dbi_conn, ERR_BACKEND_CANT_CONNECT, 1, TRUE); - dbi_conn->conn_ok = TRUE; - (void)dbi_conn_connect (conn); - } + dbi_conn->set_error (ERR_BACKEND_CANT_CONNECT, 1, true); + dbi_conn->retry_connection (msg); } else // Any other error { PERR ("DBI error: %s\n", msg); if (dbi_conn) - gnc_dbi_set_error (dbi_conn, ERR_BACKEND_MISC, 0, FALSE); + dbi_conn->set_error (ERR_BACKEND_MISC, 0, FALSE); } } @@ -1131,9 +1109,9 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, if (be->sql_be.conn != nullptr) { - gnc_sql_connection_dispose (be->sql_be.conn); + delete (be->sql_be.conn); } - be->sql_be.conn = create_dbi_connection (GNC_DBI_PROVIDER_MYSQL, qbe, + be->sql_be.conn = new GncDbiSqlConnection (GNC_DBI_PROVIDER_MYSQL, qbe, be->conn); } be->sql_be.timespec_format = MYSQL_TIMESPEC_STR_FORMAT; @@ -1226,13 +1204,9 @@ static void pgsql_error_fn (dbi_conn conn, void* user_data) { GncDbiBackend* be = (GncDbiBackend*)user_data; - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)be->sql_be.conn; + GncDbiSqlConnection* dbi_conn = + dynamic_cast(be->sql_be.conn); const gchar* msg; -#ifdef G_OS_WIN32 - const guint backoff_msecs = 1; -#else - const guint backoff_usecs = 1000; -#endif (void)dbi_conn_error (conn, &msg); if (g_str_has_prefix (msg, "FATAL: database") && @@ -1240,7 +1214,7 @@ pgsql_error_fn (dbi_conn conn, void* user_data) { PINFO ("DBI error: %s\n", msg); be->exists = FALSE; - gnc_dbi_set_error (dbi_conn, ERR_BACKEND_NO_SUCH_DB, 0, FALSE); + dbi_conn->set_error (ERR_BACKEND_NO_SUCH_DB, 0, FALSE); } else if (g_strrstr (msg, "server closed the connection unexpectedly")) // Connection lost @@ -1251,38 +1225,20 @@ pgsql_error_fn (dbi_conn conn, void* user_data) return; } PINFO ("DBI error: %s - Reconnecting...\n", msg); - gnc_dbi_set_error (dbi_conn, ERR_BACKEND_CONN_LOST, 1, TRUE); - dbi_conn->conn_ok = TRUE; - (void)dbi_conn_connect (conn); + dbi_conn->set_error (ERR_BACKEND_CONN_LOST, 1, true); + dbi_conn->retry_connection(msg); } else if (dbi_conn && (g_str_has_prefix (msg, "connection pointer is NULL") || g_str_has_prefix (msg, "could not connect to server"))) // No connection { - if (dbi_conn->error_repeat >= DBI_MAX_CONN_ATTEMPTS) - { - PERR ("DBI error: %s - Giving up after %d consecutive attempts.\n", msg, - DBI_MAX_CONN_ATTEMPTS); - gnc_dbi_set_error (dbi_conn, ERR_BACKEND_CANT_CONNECT, 0, FALSE); - dbi_conn->conn_ok = FALSE; - } - else - { -#ifdef G_OS_WIN32 - Sleep (backoff_msecs * 2 << dbi_conn->error_repeat); -#else - usleep (backoff_usecs * 2 << dbi_conn->error_repeat); -#endif - PINFO ("DBI error: %s - Reconnecting...\n", msg); - gnc_dbi_set_error (dbi_conn, ERR_BACKEND_CANT_CONNECT, 1, TRUE); - dbi_conn->conn_ok = TRUE; - (void)dbi_conn_connect (conn); - } + dbi_conn->set_error(ERR_BACKEND_CANT_CONNECT, 1, true); + dbi_conn->retry_connection (msg); } else { PERR ("DBI error: %s\n", msg); - gnc_dbi_set_error (dbi_conn, ERR_BACKEND_MISC, 0, FALSE); + dbi_conn->set_error (ERR_BACKEND_MISC, 0, false); } } @@ -1492,9 +1448,9 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, { if (be->sql_be.conn != nullptr) { - gnc_sql_connection_dispose (be->sql_be.conn); + delete (be->sql_be.conn); } - be->sql_be.conn = create_dbi_connection (GNC_DBI_PROVIDER_PGSQL, qbe, + be->sql_be.conn = new GncDbiSqlConnection (GNC_DBI_PROVIDER_PGSQL, qbe, be->conn); } be->sql_be.timespec_format = PGSQL_TIMESPEC_STR_FORMAT; @@ -1572,7 +1528,7 @@ gnc_dbi_session_end (QofBackend* be_start) } if (be->sql_be.conn != nullptr) { - gnc_sql_connection_dispose (be->sql_be.conn); + delete (be->sql_be.conn); be->sql_be.conn = nullptr; } gnc_sql_finalize_version_info (&be->sql_be); @@ -1673,31 +1629,30 @@ save_may_clobber_data (QofBackend* qbe) return retval; } -static dbi_result -conn_table_manage_backup (GncDbiSqlConnection* conn, - gchar* table_name, TableOpType op) +dbi_result +GncDbiSqlConnection::table_manage_backup (const std::string& table_name, + TableOpType op) { - gchar* new_name = g_strdup_printf ("%s_%s", table_name, "back"); + auto new_name = table_name + "_back"; dbi_result result = nullptr; switch (op) { case backup: - result = dbi_conn_queryf (conn->conn, "ALTER TABLE %s RENAME TO %s", - table_name, new_name); + result = dbi_conn_queryf (m_conn, "ALTER TABLE %s RENAME TO %s", + table_name.c_str(), new_name.c_str()); break; case rollback: - result = dbi_conn_queryf (conn->conn, + result = dbi_conn_queryf (m_conn, "ALTER TABLE %s RENAME TO %s", - new_name, table_name); + new_name.c_str(), table_name.c_str()); break; case drop_backup: - result = dbi_conn_queryf (conn->conn, "DROP TABLE %s", - new_name); + result = dbi_conn_queryf (m_conn, "DROP TABLE %s", + new_name.c_str()); break; default: break; } - g_free (new_name); return result; } @@ -1726,7 +1681,7 @@ conn_table_manage_backup (GncDbiSqlConnection* conn, * @return Success (TRUE) or failure. */ -static gboolean +gboolean conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, TableOpType op) { @@ -1734,12 +1689,12 @@ conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, gboolean result = TRUE; GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (sql_conn); GSList* full_table_name_list = nullptr; - const gchar* dbname = dbi_conn_get_option (conn->conn, "dbname"); + const gchar* dbname = dbi_conn_get_option (conn->m_conn, "dbname"); g_return_val_if_fail (table_name_list != nullptr, FALSE); if (op == rollback) full_table_name_list = - conn->provider->get_table_list (conn->conn, dbname); + conn->m_provider->get_table_list (conn->m_conn, dbname); for (node = table_name_list; node != nullptr && result; node = node->next) { @@ -1752,13 +1707,13 @@ conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, } do { - gnc_dbi_init_error (conn); + conn->init_error (); switch (op) { case rollback: if (g_slist_find (full_table_name_list, table_name)) { - result = dbi_conn_queryf (conn->conn, "DROP TABLE %s", + result = dbi_conn_queryf (conn->m_conn, "DROP TABLE %s", table_name); if (result) break; @@ -1766,20 +1721,20 @@ conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, /* Fall through */ case backup: case drop_backup: - result = conn_table_manage_backup (conn, table_name, op); + result = conn->table_manage_backup (table_name, op); break; case empty: - result = dbi_conn_queryf (conn->conn, "DELETE FROM TABLE %s", + result = dbi_conn_queryf (conn->m_conn, "DELETE FROM TABLE %s", table_name); break; case drop: default: - result = dbi_conn_queryf (conn->conn, "DROP TABLE %s", + result = dbi_conn_queryf (conn->m_conn, "DROP TABLE %s", table_name); break; } } - while (conn->retry); + while (conn->m_retry); if (result != nullptr) { if (dbi_result_free (result) < 0) @@ -1802,7 +1757,7 @@ conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, * @param qbe: QofBackend for the session. * @param book: QofBook to be saved in the database. */ -static void +void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) { GncDbiBackend* be = (GncDbiBackend*)qbe; @@ -1816,7 +1771,7 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) ENTER ("book=%p, primary=%p", book, be->primary_book); dbname = dbi_conn_get_option (be->conn, "dbname"); - table_list = conn->provider->get_table_list (conn->conn, dbname); + table_list = conn->m_provider->get_table_list (conn->m_conn, dbname); if (!conn_table_operation ((GncSqlConnection*)conn, table_list, backup)) { @@ -1827,12 +1782,12 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) gnc_table_slist_free (table_list); return; } - index_list = conn->provider->get_index_list (conn->conn); + index_list = conn->m_provider->get_index_list (conn->m_conn); for (iter = index_list; iter != nullptr; iter = g_slist_next (iter)) { const char* errmsg; - conn->provider->drop_index (conn->conn, static_cast (iter->data)); - if (DBI_ERROR_NONE != dbi_conn_error (conn->conn, &errmsg)) + conn->m_provider->drop_index (conn->m_conn, static_cast (iter->data)); + if (DBI_ERROR_NONE != dbi_conn_error (conn->m_conn, &errmsg)) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); gnc_table_slist_free (index_list); @@ -2166,7 +2121,7 @@ GncDbiSqlResult::IteratorImpl::operator++() if (error == DBI_ERROR_BADIDX || error == 0) //ran off the end of the results return m_inst->m_sentinel; PERR("Error %d incrementing results iterator.", error); - qof_backend_set_error (m_inst->m_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_inst->m_conn->qbe(), ERR_BACKEND_SERVER_ERR); return m_inst->m_sentinel; } @@ -2263,12 +2218,12 @@ GncDbiSqlResult::IteratorImpl::get_time64_at_col (const char* col) const GncDbiSqlResult::~GncDbiSqlResult() { int status = dbi_result_free (m_dbi_result); - + if (status == 0) return; PERR ("Error %d in dbi_result_free() result.", dberror() ); - qof_backend_set_error (m_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_conn->qbe(), ERR_BACKEND_SERVER_ERR); } GncSqlRow& @@ -2286,7 +2241,7 @@ GncDbiSqlResult::begin() if (error != DBI_ERROR_BADIDX) //otherwise just an empty result set { PERR ("Error %d in dbi_result_first_row()", dberror()); - qof_backend_set_error (m_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_conn->qbe(), ERR_BACKEND_SERVER_ERR); } return m_sentinel; } @@ -2294,7 +2249,7 @@ GncDbiSqlResult::begin() int GncDbiSqlResult::dberror() { - return dbi_conn_error(m_conn->conn, nullptr); + return dbi_conn_error(m_conn->conn(), nullptr); } uint64_t @@ -2307,14 +2262,14 @@ GncDbiSqlResult::size() const noexcept class GncDbiSqlStatement : public GncSqlStatement { public: - GncDbiSqlStatement(GncSqlConnection* conn, const std::string&& sql) : + GncDbiSqlStatement(const GncSqlConnection* conn, const std::string& sql) : m_conn{conn}, m_sql {sql} {} ~GncDbiSqlStatement() {} const char* to_sql() const override; void add_where_cond(QofIdTypeConst, const PairVec&) override; private: - GncSqlConnection* m_conn; + const GncSqlConnection* m_conn; std::string m_sql; }; @@ -2335,206 +2290,169 @@ GncDbiSqlStatement::add_where_cond(QofIdTypeConst type_name, if (colpair != *col_values.begin()) m_sql += " AND "; m_sql += colpair.first + " = " + - gnc_sql_connection_quote_string (m_conn, colpair.second.c_str()); + m_conn->quote_string (colpair.second.c_str()); } } /* --------------------------------------------------------- */ -static void -conn_dispose (GncSqlConnection* conn) +GncSqlResultPtr +GncDbiSqlConnection::execute_select_statement (const GncSqlStatementPtr& stmt) + noexcept { - //GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - - g_free (conn); -} - -static GncSqlResultPtr -conn_execute_select_statement (GncSqlConnection* conn, - const GncSqlStatementPtr& stmt) -{ - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; dbi_result result; DEBUG ("SQL: %s\n", stmt->to_sql()); gnc_push_locale (LC_NUMERIC, "C"); do { - gnc_dbi_init_error (dbi_conn); - result = dbi_conn_query (dbi_conn->conn, stmt->to_sql()); + init_error (); + result = dbi_conn_query (m_conn, stmt->to_sql()); } - while (dbi_conn->retry); + while (m_retry); if (result == nullptr) PERR ("Error executing SQL %s\n", stmt->to_sql()); gnc_pop_locale (LC_NUMERIC); - return GncSqlResultPtr(new GncDbiSqlResult (dbi_conn, result)); + return GncSqlResultPtr(new GncDbiSqlResult (this, result)); } -static gint -conn_execute_nonselect_statement (GncSqlConnection* conn, - const GncSqlStatementPtr& stmt) +int +GncDbiSqlConnection::execute_nonselect_statement (const GncSqlStatementPtr& stmt) + noexcept { - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; dbi_result result; - gint num_rows; - gint status; DEBUG ("SQL: %s\n", stmt->to_sql()); do { - gnc_dbi_init_error (dbi_conn); - result = dbi_conn_query (dbi_conn->conn, stmt->to_sql()); + init_error (); + result = dbi_conn_query (m_conn, stmt->to_sql()); } - while (dbi_conn->retry); - if (result == nullptr && dbi_conn->last_error) + while (m_retry); + if (result == nullptr && m_last_error) { PERR ("Error executing SQL %s\n", stmt->to_sql()); return -1; } - num_rows = (gint)dbi_result_get_numrows_affected (result); - status = dbi_result_free (result); + if (!result) + return 0; + auto num_rows = (gint)dbi_result_get_numrows_affected (result); + auto status = dbi_result_free (result); if (status < 0) { PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } return num_rows; } -static GncSqlStatementPtr -conn_create_statement_from_sql (GncSqlConnection* conn, const gchar* sql) +GncSqlStatementPtr +GncDbiSqlConnection::create_statement_from_sql (const std::string& sql) + const noexcept { - return std::unique_ptr(new GncDbiSqlStatement (conn, sql)); + return std::unique_ptr{new GncDbiSqlStatement (this, sql)}; } -static gboolean -conn_does_table_exist (GncSqlConnection* conn, const gchar* table_name) +bool +GncDbiSqlConnection::does_table_exist (const std::string& table_name) + const noexcept { - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - gint nTables; - dbi_result tables; - const gchar* dbname; - gint status; - - g_return_val_if_fail (conn != nullptr, FALSE); - g_return_val_if_fail (table_name != nullptr, FALSE); - - dbname = dbi_conn_get_option (dbi_conn->conn, "dbname"); - tables = dbi_conn_get_table_list (dbi_conn->conn, dbname, table_name); - nTables = (gint)dbi_result_get_numrows (tables); - status = dbi_result_free (tables); + auto dbname = dbi_conn_get_option (m_conn, "dbname"); + auto tables = dbi_conn_get_table_list (m_conn, dbname, table_name.c_str()); + auto nTables = dbi_result_get_numrows (tables); + auto status = dbi_result_free (tables); if (status < 0) { PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } - if (nTables == 1) - { - return TRUE; - } - else - { - return FALSE; - } + return nTables == 1; } -static gboolean -conn_begin_transaction (GncSqlConnection* conn) +bool +GncDbiSqlConnection::begin_transaction () noexcept { - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; dbi_result result; - gint status; - gboolean success = FALSE; DEBUG ("BEGIN\n"); - if (!gnc_dbi_verify_conn (dbi_conn)) + if (!verify ()) { PERR ("gnc_dbi_verify_conn() failed\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); return FALSE; } do { - gnc_dbi_init_error (dbi_conn); - result = dbi_conn_queryf (dbi_conn->conn, "BEGIN"); + init_error (); + result = dbi_conn_queryf (m_conn, "BEGIN"); } - while (dbi_conn->retry); + while (m_retry); - success = (result != nullptr); - status = dbi_result_free (result); + auto success = (result != nullptr); + auto status = dbi_result_free (result); if (status < 0) { PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } if (!success) { PERR ("BEGIN transaction failed()\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } return success; } -static gboolean -conn_rollback_transaction (GncSqlConnection* conn) +bool +GncDbiSqlConnection::rollback_transaction () const noexcept { - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - dbi_result result; - gint status; - gboolean success = FALSE; - DEBUG ("ROLLBACK\n"); const char* command = "ROLLBACK"; - result = dbi_conn_query (dbi_conn->conn, command); - success = (result != nullptr); + auto result = dbi_conn_query (m_conn, command); + auto success = (result != nullptr); - status = dbi_result_free (result); + auto status = dbi_result_free (result); if (status < 0) { PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } if (!success) { PERR ("Error in conn_rollback_transaction()\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } return success; } -static gboolean -conn_commit_transaction (GncSqlConnection* conn) +bool +GncDbiSqlConnection::commit_transaction () const noexcept { - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - dbi_result result; - gint status; - gboolean success = FALSE; - DEBUG ("COMMIT\n"); - result = dbi_conn_queryf (dbi_conn->conn, "COMMIT"); - success = (result != nullptr); + auto result = dbi_conn_queryf (m_conn, "COMMIT"); + auto success = (result != nullptr); - status = dbi_result_free (result); + auto status = dbi_result_free (result); if (status < 0) { PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } if (!success) { PERR ("Error in conn_commit_transaction()\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } return success; } static gchar* -create_index_ddl (GncSqlConnection* conn, const char* index_name, +create_index_ddl (const GncSqlConnection* conn, const char* index_name, const char* table_name, const EntryVec& col_table) { GString* ddl; @@ -2558,8 +2476,8 @@ create_index_ddl (GncSqlConnection* conn, const char* index_name, return g_string_free (ddl, FALSE); } -static gchar* -add_columns_ddl(GncSqlConnection* conn, +gchar* +add_columns_ddl(const GncSqlConnection* conn, const gchar* table_name, const ColVec& info_vec) { @@ -2578,7 +2496,7 @@ add_columns_ddl(GncSqlConnection* conn, (void)g_string_append (ddl, ", "); } g_string_append (ddl, "ADD COLUMN "); - dbi_conn->provider->append_col_def (ddl, info); + dbi_conn->m_provider->append_col_def (ddl, info); } return g_string_free (ddl, FALSE); @@ -2631,7 +2549,7 @@ append_sqlite3_col_def(GString* ddl, const GncSqlColumnInfo& info) } static gchar* -conn_create_table_ddl_sqlite3 (GncSqlConnection* conn, +conn_create_table_ddl_sqlite3 (const GncSqlConnection* conn, const gchar* table_name, const ColVec& info_vec) { @@ -2714,8 +2632,8 @@ append_mysql_col_def (GString* ddl, const GncSqlColumnInfo& info) } static gchar* -conn_create_table_ddl_mysql (GncSqlConnection* conn, const gchar* table_name, - const ColVec& info_vec) +conn_create_table_ddl_mysql (const GncSqlConnection* conn, + const gchar* table_name, const ColVec& info_vec) { GString* ddl; unsigned int col_num = 0; @@ -2796,7 +2714,7 @@ append_pgsql_col_def (GString* ddl, const GncSqlColumnInfo& info) } static gchar* -conn_create_table_ddl_pgsql (GncSqlConnection* conn, const gchar* table_name, +conn_create_table_ddl_pgsql (const GncSqlConnection* conn, const gchar* table_name, const ColVec& info_vec) { GString* ddl; @@ -2820,129 +2738,106 @@ conn_create_table_ddl_pgsql (GncSqlConnection* conn, const gchar* table_name, return g_string_free (ddl, FALSE); } -static gboolean -conn_create_table (GncSqlConnection* conn, const gchar* table_name, - const ColVec& info_vec) +bool +GncDbiSqlConnection::create_table (const std::string& table_name, + const ColVec& info_vec) const noexcept { - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - gchar* ddl; - dbi_result result; - - g_return_val_if_fail (conn != nullptr, FALSE); - g_return_val_if_fail (table_name != nullptr, FALSE); - - ddl = dbi_conn->provider->create_table_ddl(conn, table_name, info_vec); + auto ddl = m_provider->create_table_ddl(this, table_name.c_str(), info_vec); if (ddl != nullptr) { - gint status; DEBUG ("SQL: %s\n", ddl); - result = dbi_conn_query (dbi_conn->conn, ddl); + auto result = dbi_conn_query (m_conn, ddl); g_free (ddl); - status = dbi_result_free (result); + auto status = dbi_result_free (result); if (status < 0) { PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } } else { - return FALSE; + return false; } - return TRUE; + return true; } -static gboolean -conn_create_index(GncSqlConnection* conn, const char* index_name, - const char* table_name, const EntryVec& col_table) +bool +GncDbiSqlConnection::create_index(const std::string& index_name, + const std::string& table_name, + const EntryVec& col_table) const noexcept { - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - gchar* ddl; - dbi_result result; - - g_return_val_if_fail (conn != nullptr, FALSE); - g_return_val_if_fail (index_name != nullptr, FALSE); - g_return_val_if_fail (table_name != nullptr, FALSE); - - ddl = create_index_ddl (conn, index_name, table_name, col_table); + auto ddl = create_index_ddl (this, index_name.c_str(), table_name.c_str(), + col_table); if (ddl != nullptr) { - gint status; - DEBUG ("SQL: %s\n", ddl); - result = dbi_conn_query (dbi_conn->conn, ddl); + auto result = dbi_conn_query (m_conn, ddl); g_free (ddl); - status = dbi_result_free (result); + auto status = dbi_result_free (result); if (status < 0) { PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (dbi_conn->qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } } else { - return FALSE; + return false; } - return TRUE; + return true; } -static gboolean -conn_add_columns_to_table(GncSqlConnection* conn, const char* table_name, - const ColVec& info_vec) +bool +GncDbiSqlConnection::add_columns_to_table(const std::string& table_name, + const ColVec& info_vec) + const noexcept { - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; - gchar* ddl; - dbi_result result; - - g_return_val_if_fail (conn != nullptr, FALSE); - g_return_val_if_fail (table_name != nullptr, FALSE); - - ddl = add_columns_ddl(conn, table_name, info_vec); + auto ddl = add_columns_ddl(this, table_name.c_str(), info_vec); if (ddl == nullptr) return FALSE; DEBUG ("SQL: %s\n", ddl); - result = dbi_conn_query (dbi_conn->conn, ddl); + auto result = dbi_conn_query (m_conn, ddl); g_free (ddl); - int status = dbi_result_free (result); + auto status = dbi_result_free (result); if (status < 0) { PERR( "Error in dbi_result_free() result\n" ); - qof_backend_set_error( dbi_conn->qbe, ERR_BACKEND_SERVER_ERR ); + qof_backend_set_error(m_qbe, ERR_BACKEND_SERVER_ERR ); } - return TRUE; + return true; } -static gchar* -conn_quote_string (const GncSqlConnection* conn, const char* unquoted_str) +std::string +GncDbiSqlConnection::quote_string (const std::string& unquoted_str) + const noexcept { - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; gchar* quoted_str; size_t size; - size = dbi_conn_quote_string_copy (dbi_conn->conn, unquoted_str, + size = dbi_conn_quote_string_copy (m_conn, unquoted_str.c_str(), "ed_str); if (size != 0) { - return quoted_str; + return std::string{quoted_str}; } else { - return nullptr; + return std::string{""}; } } static GSList* conn_get_table_list (dbi_conn conn, const gchar* dbname) { - dbi_result tables; GSList* list = nullptr; - tables = dbi_conn_get_table_list (conn, dbname, nullptr); + auto tables = dbi_conn_get_table_list (conn, dbname, nullptr); while (dbi_result_next_row (tables) != 0) { const gchar* table_name; @@ -3068,7 +2963,7 @@ conn_test_dbi_library (dbi_conn conn) dbi_conn_error (conn, &errmsg); PWARN ("Test_DBI_Library: Failed to retrieve test row into table: %s", errmsg); - result = dbi_conn_query (conn, "DROP TABLE numtest"); + dbi_conn_query (conn, "DROP TABLE numtest"); gnc_pop_locale (LC_NUMERIC); return GNC_DBI_FAIL_SETUP; } @@ -3105,35 +3000,4 @@ conn_test_dbi_library (dbi_conn conn) } -static GncSqlConnection* -create_dbi_connection (provider_functions_t* provider, - QofBackend* qbe, - dbi_conn conn) -{ - GncDbiSqlConnection* dbi_conn; - - dbi_conn = g_new0 (GncDbiSqlConnection, 1); - g_assert (dbi_conn != nullptr); - - dbi_conn->base.dispose = conn_dispose; - dbi_conn->base.executeSelectStatement = conn_execute_select_statement; - dbi_conn->base.executeNonSelectStatement = conn_execute_nonselect_statement; - dbi_conn->base.createStatementFromSql = conn_create_statement_from_sql; - dbi_conn->base.doesTableExist = conn_does_table_exist; - dbi_conn->base.beginTransaction = conn_begin_transaction; - dbi_conn->base.rollbackTransaction = conn_rollback_transaction; - dbi_conn->base.commitTransaction = conn_commit_transaction; - dbi_conn->base.createTable = conn_create_table; - dbi_conn->base.createIndex = conn_create_index; - dbi_conn->base.addColumnsToTable = conn_add_columns_to_table; - dbi_conn->base.quoteString = conn_quote_string; - dbi_conn->qbe = qbe; - dbi_conn->conn = conn; - dbi_conn->provider = provider; - dbi_conn->conn_ok = TRUE; - gnc_dbi_init_error (dbi_conn); - - return (GncSqlConnection*)dbi_conn; -} - /* ========================== END OF FILE ===================== */ diff --git a/src/backend/dbi/test/test-backend-dbi-basic.cpp b/src/backend/dbi/test/test-backend-dbi-basic.cpp index 03e1bd7869..41c4f8c7c1 100644 --- a/src/backend/dbi/test/test-backend-dbi-basic.cpp +++ b/src/backend/dbi/test/test-backend-dbi-basic.cpp @@ -359,16 +359,16 @@ test_conn_index_functions (QofBackend* qbe) GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (be->sql_be.conn); GSList* index_list, *iter; - index_list = conn->provider->get_index_list (be->conn); + index_list = conn->provider()->get_index_list (be->conn); g_test_message ("Returned from index list\n"); g_assert (index_list != NULL); g_assert_cmpint (g_slist_length (index_list), == , 4); for (iter = index_list; iter != NULL; iter = g_slist_next (iter)) { const char* errmsg; - conn->provider->drop_index (be->conn, + conn->provider()->drop_index (be->conn, static_cast (iter->data)); - g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn, &errmsg)); + g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn(), &errmsg)); } g_slist_free (index_list); diff --git a/src/backend/dbi/test/test-dbi-stuff.cpp b/src/backend/dbi/test/test-dbi-stuff.cpp index 58526afe2f..c04af87822 100644 --- a/src/backend/dbi/test/test-dbi-stuff.cpp +++ b/src/backend/dbi/test/test-dbi-stuff.cpp @@ -218,16 +218,16 @@ test_conn_index_functions (QofBackend* qbe) GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (be->sql_be.conn); GSList* index_list, *iter; - index_list = conn->provider->get_index_list (be->conn); + index_list = conn->provider()->get_index_list (be->conn); g_test_message ("Returned from index list\n"); g_assert (index_list != NULL); g_assert_cmpint (g_slist_length (index_list), == , 4); for (iter = index_list; iter != NULL; iter = g_slist_next (iter)) { const char* errmsg; - conn->provider->drop_index (be->conn, + conn->provider()->drop_index (be->conn, static_cast (iter->data)); - g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn, &errmsg)); + g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn(), &errmsg)); } g_slist_free (index_list); diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 58cf98d45f..ba0da85f68 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -462,7 +462,7 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) be->obj_total += gnc_book_count_transactions (book); be->operations_done = 0; - is_ok = gnc_sql_connection_begin_transaction (be->conn); + is_ok = be->conn->begin_transaction (); // FIXME: should write the set of commodities that are used //write_commodities( be, book ); @@ -494,7 +494,7 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) } if (is_ok) { - is_ok = gnc_sql_connection_commit_transaction (be->conn); + is_ok = be->conn->commit_transaction (); } if (is_ok) { @@ -509,7 +509,7 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) { if (!qof_backend_check_error ((QofBackend*)be)) qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_SERVER_ERR); - is_ok = gnc_sql_connection_rollback_transaction (be->conn); + is_ok = be->conn->rollback_transaction (); } finish_progress (be); LEAVE ("book=%p", book); @@ -573,7 +573,7 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) if (qof_book_is_readonly (be->book)) { qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_READONLY); - (void)gnc_sql_connection_rollback_transaction (be->conn); + (void)be->conn->rollback_transaction (); return; } /* During initial load where objects are being created, don't commit @@ -608,7 +608,7 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) return; } - if (!gnc_sql_connection_begin_transaction (be->conn)) + if (!be->conn->begin_transaction ()) { PERR ("gnc_sql_commit_edit(): begin_transaction failed\n"); LEAVE ("Rolled back - database transaction begin error"); @@ -626,7 +626,7 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) if (!be_data.is_known) { PERR ("gnc_sql_commit_edit(): Unknown object type '%s'\n", inst->e_type); - (void)gnc_sql_connection_rollback_transaction (be->conn); + (void)be->conn->rollback_transaction (); // Don't let unknown items still mark the book as being dirty qof_book_mark_session_saved (be->book); @@ -637,14 +637,14 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) if (!be_data.is_ok) { // Error - roll it back - (void)gnc_sql_connection_rollback_transaction (be->conn); + (void)be->conn->rollback_transaction (); // This *should* leave things marked dirty LEAVE ("Rolled back - database error"); return; } - (void)gnc_sql_connection_commit_transaction (be->conn); + (void)be->conn->commit_transaction (); qof_book_mark_session_saved (be->book); qof_instance_mark_clean (inst); @@ -1869,7 +1869,7 @@ gnc_sql_execute_select_statement (GncSqlBackend* be, g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (stmt != NULL, NULL); - auto result = gnc_sql_connection_execute_select_statement (be->conn, stmt); + auto result = be->conn->execute_select_statement (stmt); if (result == NULL) { PERR ("SQL error: %s\n", stmt->to_sql()); @@ -1886,8 +1886,8 @@ gnc_sql_create_statement_from_sql (GncSqlBackend* be, const gchar* sql) g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (sql != NULL, NULL); - auto stmt = gnc_sql_connection_create_statement_from_sql (be->conn, sql); - if (stmt == NULL) + auto stmt = be->conn->create_statement_from_sql (sql); + if (stmt == nullptr) { PERR ("SQL error: %s\n", sql); if (!qof_backend_check_error(&be->be)) @@ -1908,8 +1908,8 @@ gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) { return nullptr; } - auto result = gnc_sql_connection_execute_select_statement (be->conn, stmt); - if (result == NULL) + auto result = be->conn->execute_select_statement (stmt); + if (result == nullptr) { PERR ("SQL error: %s\n", sql); if (!qof_backend_check_error(&be->be)) @@ -1930,8 +1930,7 @@ gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql) { return -1; } - auto result = gnc_sql_connection_execute_nonselect_statement (be->conn, - stmt); + auto result = be->conn->execute_nonselect_statement (stmt); return result; } @@ -2041,9 +2040,7 @@ gnc_sql_do_db_operation (GncSqlBackend* be, } if (stmt != nullptr) { - gint result; - - result = gnc_sql_connection_execute_nonselect_statement (be->conn, stmt); + auto result = be->conn->execute_nonselect_statement (stmt); if (result == -1) { PERR ("SQL error: %s\n", stmt->to_sql()); @@ -2088,13 +2085,11 @@ build_insert_statement (GncSqlBackend* be, { if (col_value != *values.begin()) sql << ","; - sql << - gnc_sql_connection_quote_string(be->conn, col_value.second.c_str()); + sql << be->conn->quote_string(col_value.second); } sql << ")"; - stmt = gnc_sql_connection_create_statement_from_sql(be->conn, - sql.str().c_str()); + stmt = be->conn->create_statement_from_sql(sql.str()); return stmt; } @@ -2123,10 +2118,10 @@ build_update_statement (GncSqlBackend* be, if (col_value != *values.begin()) sql << ","; sql << col_value.first << "=" << - gnc_sql_connection_quote_string(be->conn, col_value.second.c_str()); + be->conn->quote_string(col_value.second); } - stmt = gnc_sql_connection_create_statement_from_sql(be->conn, sql.str().c_str()); + stmt = be->conn->create_statement_from_sql(sql.str()); /* We want our where condition to be just the first column and * value, i.e. the guid of the object. */ @@ -2149,8 +2144,7 @@ build_delete_statement (GncSqlBackend* be, g_return_val_if_fail (pObject != NULL, NULL); sql << "DELETE FROM " << table_name; - auto stmt = gnc_sql_connection_create_statement_from_sql (be->conn, - sql.str().c_str()); + auto stmt = be->conn->create_statement_from_sql (sql.str()); /* WHERE */ PairVec values; @@ -2219,7 +2213,7 @@ do_create_table (const GncSqlBackend* be, const gchar* table_name, { table_row->add_to_table (be, info_vec); } - ok = gnc_sql_connection_create_table (be->conn, table_name, info_vec); + ok = be->conn->create_table (table_name, info_vec); return ok; } @@ -2276,8 +2270,7 @@ gnc_sql_create_index (const GncSqlBackend* be, const gchar* index_name, g_return_val_if_fail (index_name != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - ok = gnc_sql_connection_create_index (be->conn, index_name, table_name, - col_table); + ok = be->conn->create_index (index_name, table_name, col_table); return ok; } @@ -2342,7 +2335,7 @@ gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const gchar* table_nam { table_row->add_to_table (be, info_vec); } - ok = gnc_sql_connection_add_columns_to_table(be->conn, table_name, info_vec); + ok = be->conn->add_columns_to_table(table_name, info_vec); return ok; } @@ -2376,7 +2369,7 @@ gnc_sql_init_version_info (GncSqlBackend* be) } be->versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - if (gnc_sql_connection_does_table_exist (be->conn, VERSION_TABLE_NAME)) + if (be->conn->does_table_exist (VERSION_TABLE_NAME)) { auto sql = g_strdup_printf ("SELECT * FROM %s", VERSION_TABLE_NAME); auto result = gnc_sql_execute_select_sql (be, sql); diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 5df615bd49..7f145bc8fd 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -58,7 +58,7 @@ using EntryVec = std::vector; using ColVec = std::vector; using StrVec = std::vector; using PairVec = std::vector>; -typedef struct GncSqlConnection GncSqlConnection; +class GncSqlConnection; /** * @struct GncSqlBackend @@ -158,49 +158,40 @@ public: using GncSqlStatementPtr = std::unique_ptr; /** - * @struct GncSqlConnection - * - * Struct which represents the connection to an SQL database. SQL backends - * must provide a structure which implements all of the functions. + * Encapsulate the connection to the database. */ -struct GncSqlConnection +class GncSqlConnection { - void (*dispose) (GncSqlConnection*); - GncSqlResultPtr (*executeSelectStatement) (GncSqlConnection*, const GncSqlStatementPtr&); /**< Returns NULL if error */ - gint (*executeNonSelectStatement) (GncSqlConnection*, const GncSqlStatementPtr&); /**< Returns -1 if error */ - GncSqlStatementPtr (*createStatementFromSql) (GncSqlConnection*, const gchar*); - gboolean (*doesTableExist) (GncSqlConnection*, const gchar*); /**< Returns true if successful */ - gboolean (*beginTransaction) (GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*rollbackTransaction) (GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*commitTransaction) (GncSqlConnection*); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*createTable) (GncSqlConnection*, const gchar*, const ColVec&); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*createIndex) (GncSqlConnection*, const gchar*, const gchar*, const EntryVec&); /**< Returns TRUE if successful, FALSE if error */ - gboolean (*addColumnsToTable) (GncSqlConnection*, const gchar* table, const ColVec&); /**< Returns TRUE if successful, FALSE if error */ - gchar* (*quoteString) (const GncSqlConnection*, const char*); +public: + /** Returns NULL if error */ + virtual ~GncSqlConnection() = default; + virtual GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr&) + noexcept = 0; + /** Returns false if error */ + virtual int execute_nonselect_statement (const GncSqlStatementPtr&) + noexcept = 0; + virtual GncSqlStatementPtr create_statement_from_sql (const std::string&) + const noexcept = 0; + /** Returns true if successful */ + virtual bool does_table_exist (const std::string&) const noexcept = 0; + /** Returns TRUE if successful, false if error */ + virtual bool begin_transaction () noexcept = 0; + /** Returns TRUE if successful, FALSE if error */ + virtual bool rollback_transaction () const noexcept = 0; + /** Returns TRUE if successful, FALSE if error */ + virtual bool commit_transaction () const noexcept = 0; + /** Returns TRUE if successful, FALSE if error */ + virtual bool create_table (const std::string&, const ColVec&) + const noexcept = 0; + /** Returns TRUE if successful, FALSE if error */ + virtual bool create_index (const std::string&, const std::string&, + const EntryVec&) const noexcept = 0; + /** Returns TRUE if successful, FALSE if error */ + virtual bool add_columns_to_table (const std::string&, const ColVec&) + const noexcept = 0; + virtual std::string quote_string (const std::string&) + const noexcept = 0; }; -#define gnc_sql_connection_dispose(CONN) (CONN)->dispose(CONN) -#define gnc_sql_connection_execute_select_statement(CONN,STMT) \ - (CONN)->executeSelectStatement(CONN,STMT) -#define gnc_sql_connection_execute_nonselect_statement(CONN,STMT) \ - (CONN)->executeNonSelectStatement(CONN,STMT) -#define gnc_sql_connection_create_statement_from_sql(CONN,SQL) \ - (CONN)->createStatementFromSql(CONN,SQL) -#define gnc_sql_connection_does_table_exist(CONN,NAME) \ - (CONN)->doesTableExist(CONN,NAME) -#define gnc_sql_connection_begin_transaction(CONN) \ - (CONN)->beginTransaction(CONN) -#define gnc_sql_connection_rollback_transaction(CONN) \ - (CONN)->rollbackTransaction(CONN) -#define gnc_sql_connection_commit_transaction(CONN) \ - (CONN)->commitTransaction(CONN) -#define gnc_sql_connection_create_table(CONN,NAME,COLLIST) \ - (CONN)->createTable(CONN,NAME,COLLIST) -#define gnc_sql_connection_create_index(CONN,INDEXNAME,TABLENAME,COLTABLE) \ - (CONN)->createIndex(CONN,INDEXNAME,TABLENAME,COLTABLE) -#define gnc_sql_connection_add_columns_to_table(CONN,TABLENAME,COLLIST) \ - (CONN)->addColumnsToTable(CONN,TABLENAME,COLLIST) -#define gnc_sql_connection_quote_string(CONN,STR) \ - (CONN)->quoteString(CONN,STR) /** * Struct used to represent a row in the result of an SQL SELECT statement. diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index 3f61d9b78c..28cb6b27ee 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -284,31 +284,20 @@ GncSqlBillTermBackend::load_all (GncSqlBackend* be) } /* ================================================================= */ -typedef struct -{ - GncSqlBackend* be; - GncSqlBillTermBackend* btbe; - bool is_ok; -} write_billterms_t; static void -do_save_billterm (QofInstance* inst, gpointer p2) +do_save_billterm (QofInstance* inst, void* p2) { - write_billterms_t* data = (write_billterms_t*)p2; - - if (data->is_ok) - { - data->is_ok = data->btbe->commit (data->be, inst); - } + auto data = static_cast(p2); + data->commit(inst); } bool GncSqlBillTermBackend::write (GncSqlBackend* be) { - write_billterms_t data {be, this, true}; - g_return_val_if_fail (be != NULL, FALSE); + write_objects_t data {be, true, this}; qof_object_foreach (GNC_ID_BILLTERM, be->book, do_save_billterm, &data); return data.is_ok; } diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index ce923fda08..43bce7f309 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -198,9 +198,9 @@ write_single_customer (QofInstance* term_p, gpointer data_p) g_return_if_fail (GNC_IS_CUSTOMER (term_p)); g_return_if_fail (data_p != NULL); - if (customer_should_be_saved (GNC_CUSTOMER (term_p)) && data->is_ok) + if (customer_should_be_saved (GNC_CUSTOMER (term_p))) { - data->is_ok = data->obe->commit (data->be, term_p); + data->commit (term_p); } } diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index 112bcabd1c..10d1a817a7 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -321,7 +321,7 @@ gnc_sql_set_recurrences_from_db (GncSqlBackend* be, const GncGUID* guid) (void)guid_to_string_buff (guid, guid_buf); buf = g_strdup_printf ("SELECT * FROM %s WHERE obj_guid='%s'", TABLE_NAME, guid_buf); - auto stmt = gnc_sql_connection_create_statement_from_sql (be->conn, buf); + auto stmt = be->conn->create_statement_from_sql (buf); g_free (buf); auto result = gnc_sql_execute_select_statement (be, stmt); return result; diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index ca22a60f3f..415f76612a 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -237,7 +237,7 @@ load_taxtable_entries (GncSqlBackend* be, GncTaxTable* tt) g_value_set_string (&value, guid_buf); buf = g_strdup_printf ("SELECT * FROM %s WHERE taxtable='%s'", TTENTRIES_TABLE_NAME, guid_buf); - auto stmt = gnc_sql_connection_create_statement_from_sql (be->conn, buf); + auto stmt = be->conn->create_statement_from_sql (buf); g_free (buf); auto result = gnc_sql_execute_select_statement (be, stmt); for (auto row : *result) diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index 699119f271..fbbe460319 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -32,6 +32,81 @@ extern "C" static const gchar* suitename = "/backend/sql/gnc-backend-sql"; void test_suite_gnc_backend_sql (void); +class GncMockSqlConnection; + +class GncMockSqlResult : public GncSqlResult +{ +public: + GncMockSqlResult(const GncMockSqlConnection* conn) : + m_conn{conn}, m_iter{this}, m_row{&m_iter} {} + uint64_t size() const noexcept { return 1; } + GncSqlRow& begin() { return m_row; } + GncSqlRow& end() { return m_row; } +protected: + class IteratorImpl : public GncSqlResult::IteratorImpl + { + public: + ~IteratorImpl() = default; + IteratorImpl(GncMockSqlResult* inst) : m_inst{inst} {} + virtual GncSqlRow& operator++() { return m_inst->m_row; } + virtual GncSqlRow& operator++(int) { return ++(*this); }; + virtual GncSqlResult* operator*() { return m_inst; } + virtual int64_t get_int_at_col (const char* col) const + { return 1LL; } + virtual float get_float_at_col (const char* col) const + { return 1.0; } + virtual double get_double_at_col (const char* col) const + { return 1.0; } + virtual std::string get_string_at_col (const char* col)const + { return std::string{"foo"}; } + virtual time64 get_time64_at_col (const char* col) const + { return 1466270857LL; } + virtual bool is_col_null(const char* col) const noexcept + { return false; } + private: + GncMockSqlResult* m_inst; + }; +private: + const GncMockSqlConnection* m_conn; + IteratorImpl m_iter; + GncSqlRow m_row; +}; + +class GncMockSqlStatement : public GncSqlStatement +{ +public: + const char* to_sql() const { return "SELECT * FROM foo"; } + void add_where_cond (QofIdTypeConst, const PairVec&) {} +}; + + +class GncMockSqlConnection : public GncSqlConnection +{ +public: + GncMockSqlConnection() : m_result{this} {} + GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr&) + noexcept override { return &m_result; } + int execute_nonselect_statement (const GncSqlStatementPtr&) + noexcept override { return 1; } + GncSqlStatementPtr create_statement_from_sql (const std::string&) + const noexcept override { + return std::unique_ptr(new GncMockSqlStatement); } + bool does_table_exist (const std::string&) const noexcept override { + return true; } + bool begin_transaction () noexcept override { return true;} + bool rollback_transaction () const noexcept override { return true; } + bool commit_transaction () const noexcept override { return true; } + bool create_table (const std::string&, const ColVec&) + const noexcept override { return false; } + bool create_index (const std::string&, const std::string&, + const EntryVec&) const noexcept override { return false; } + bool add_columns_to_table (const std::string&, const ColVec&) + const noexcept override { return false; } + virtual std::string quote_string (const std::string& str) + const noexcept override { return std::string{str}; } +private: + GncMockSqlResult m_result; +}; /* gnc_sql_init void @@ -185,19 +260,13 @@ test_dirty_cb (QofBook* book, gboolean dirty, gpointer data) --* (guint*)data; } -static gboolean -fake_connection_function (GncSqlConnection* conn) -{ - return TRUE; -} - static void test_gnc_sql_commit_edit (void) { GncSqlBackend be; QofInstance* inst; guint dirty_called = 0; - GncSqlConnection conn; + GncMockSqlConnection conn; const char* msg1 = "[gnc_sql_commit_edit()] gnc_sql_commit_edit(): Unknown object type 'null'\n"; const char* msg2 = @@ -222,9 +291,6 @@ test_gnc_sql_commit_edit (void) qof_object_initialize (); be.book = qof_book_new (); be.conn = &conn; - conn.beginTransaction = fake_connection_function; - conn.rollbackTransaction = fake_connection_function; - conn.commitTransaction = fake_connection_function; inst = static_cast (g_object_new (QOF_TYPE_INSTANCE, NULL)); qof_instance_init_data (inst, QOF_ID_NULL, be.book); be.loading = FALSE; From 7fe404808ade6e8ea74aae55e2ddabd903857282 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 3 Jul 2016 17:06:19 -0700 Subject: [PATCH 20/63] Delete some no-longer (or in some cases never) used functions. --- src/backend/sql/gnc-backend-sql.cpp | 79 ++----------------- src/backend/sql/gnc-backend-sql.h | 43 ---------- .../sql/test/utest-gnc-backend-sql.cpp | 34 -------- 3 files changed, 6 insertions(+), 150 deletions(-) diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index ba0da85f68..be0338d6d6 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -193,15 +193,9 @@ create_tables(const OBEEntry& entry, GncSqlBackend* be) static const StrVec fixed_load_order { GNC_ID_BOOK, GNC_ID_COMMODITY, GNC_ID_ACCOUNT, GNC_ID_LOT }; - -/* Load order for objects from other modules */ -static StrVec other_load_order; - -void -gnc_sql_set_load_order(const StrVec& load_order) -{ - other_load_order = load_order; -} +/* Order in which business objects need to be loaded */ +static const StrVec business_fixed_load_order = +{ GNC_ID_BILLTERM, GNC_ID_TAXTABLE, GNC_ID_INVOICE }; static void initial_load(const OBEEntry& entry, GncSqlBackend* be) @@ -216,8 +210,8 @@ initial_load(const OBEEntry& entry, GncSqlBackend* be) */ if (std::find(fixed_load_order.begin(), fixed_load_order.end(), type) != fixed_load_order.end()) return; - if (std::find(other_load_order.begin(), other_load_order.end(), - type) != other_load_order.end()) return; + if (std::find(business_fixed_load_order.begin(), business_fixed_load_order.end(), + type) != business_fixed_load_order.end()) return; obe->load_all (be); } @@ -263,7 +257,7 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) obe->load_all (be); } } - for (auto type : other_load_order) + for (auto type : business_fixed_load_order) { auto obe = gnc_sql_get_object_backend(type); if (obe) @@ -1031,9 +1025,6 @@ gnc_sql_run_query (QofBackend* pBEnd, gpointer pQuery) } #endif //if 0: query creation isn't used yet, code never tested. /* ================================================================= */ -/* Order in which business objects need to be loaded */ -static const StrVec business_fixed_load_order = -{ GNC_ID_BILLTERM, GNC_ID_TAXTABLE, GNC_ID_INVOICE }; static void business_core_sql_init (void) @@ -1048,8 +1039,6 @@ business_core_sql_init (void) gnc_order_sql_initialize (); gnc_taxtable_sql_initialize (); gnc_vendor_sql_initialize (); - - gnc_sql_set_load_order (business_fixed_load_order); } static void @@ -1071,49 +1060,6 @@ gnc_sql_init_object_handlers (void) } /* ================================================================= */ - -gint64 -gnc_sql_get_integer_value (const GValue* value) -{ - g_return_val_if_fail (value != NULL, 0); - - if (G_VALUE_HOLDS_INT (value)) - { - return (gint64)g_value_get_int (value); - } - else if (G_VALUE_HOLDS_UINT (value)) - { - return (gint64)g_value_get_uint (value); - } - else if (G_VALUE_HOLDS_LONG (value)) - { - return (gint64)g_value_get_long (value); - } - else if (G_VALUE_HOLDS_ULONG (value)) - { - return (gint64)g_value_get_ulong (value); - } - else if (G_VALUE_HOLDS_INT64 (value)) - { - return g_value_get_int64 (value); - } - else if (G_VALUE_HOLDS_UINT64 (value)) - { - return (gint64)g_value_get_uint64 (value); - } - else if (G_VALUE_HOLDS_STRING (value)) - { - return g_ascii_strtoll (g_value_get_string (value), NULL, 10); - } - else - { - PWARN ("Unknown type: %s", G_VALUE_TYPE_NAME (value)); - } - - return 0; -} - -/* ----------------------------------------------------------------- */ static gpointer get_autoinc_id (void* object, const QofParam* param) { @@ -1805,19 +1751,6 @@ static EntryVec tx_guid_table gnc_sql_make_table_entry("tx_guid", 0, 0, nullptr, _retrieve_guid_) }; - -const GncGUID* -gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow& row) -{ - static GncGUID guid; - - g_return_val_if_fail (be != NULL, NULL); - - gnc_sql_load_object (be, row, NULL, &guid, tx_guid_table); - - return &guid; -} - void gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow& row, QofIdTypeConst obj_name, gpointer pObject, diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 7f145bc8fd..39b73d3930 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -881,16 +881,6 @@ gboolean gnc_sql_create_index (const GncSqlBackend* be, const char* index_name, const GncGUID* gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow& row); -/** - * Loads the transaction guid from a database row. The table must have a column - * named "tx_guid" with type CT_GUID. - * - * @param be SQL backend struct - * @param row Database row - * @return GncGUID - */ - -const GncGUID* gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow& row); /** * Creates a basic SELECT statement for a table. @@ -927,30 +917,6 @@ void gnc_sql_init_version_info (GncSqlBackend* be); */ void gnc_sql_finalize_version_info (GncSqlBackend* be); -/** - * Commits a "standard" item to the database. In most cases, a commit of one - * object vs another differs only in the table name and column table. - * - * @param be SQL backend - * @param inst Instance - * @param tableName SQL table name - * @param obj_name QOF object type name - * @param col_table Column table - * @return TRUE if successful, FALSE if not - */ -gboolean gnc_sql_commit_standard_item (GncSqlBackend* be, QofInstance* inst, - const gchar* tableName, - QofIdTypeConst obj_name, - const EntryVec& col_table); - -/** - * Gets an integer value (of any size) from a GValue. - * - * @param value Source value - * @return Integer value - */ -gint64 gnc_sql_get_integer_value (const GValue* value); - /** * Converts a Timespec value to a string value for the database. * @@ -986,15 +952,6 @@ void gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name, gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const char* table_name, const EntryVec& new_col_table); -/** - * Specifies the load order for a set of objects. When loading from a database, - * the objects will be loaded in this order, so that when later objects have - * references to objects, those objects will already have been loaded. - * - * @param load_order NULL-terminated array of object type ID strings - */ -void gnc_sql_set_load_order(StrVec&& load_order); - void _retrieve_guid_ (gpointer pObject, gpointer pValue); gpointer gnc_sql_compile_query (QofBackend* pBEnd, QofQuery* pQuery); diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index fbbe460319..3dc7ea4959 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -123,14 +123,6 @@ create_tables_cb (const gchar* type, gpointer data_p, gpointer be_p)// 2 test_create_tables_cb (Fixture *fixture, gconstpointer pData) { }*/ -/* gnc_sql_set_load_order -void -gnc_sql_set_load_order (const gchar** load_order)// 2 -*/ -/* static void -test_gnc_sql_set_load_order (Fixture *fixture, gconstpointer pData) -{ -}*/ /* initial_load_cb static void initial_load_cb (const gchar* type, gpointer data_p, gpointer be_p)// 2 @@ -428,13 +420,6 @@ gnc_sql_init_object_handlers (void)// 3 test_gnc_sql_init_object_handlers (Fixture *fixture, gconstpointer pData) { }*/ -/* gnc_sql_get_integer_value -gint64 -gnc_sql_get_integer_value (const GValue* value)// C: 1 */ -/* static void -test_gnc_sql_get_integer_value (Fixture *fixture, gconstpointer pData) -{ -}*/ // Make Static /* get_autoinc_id get_autoinc_id()// 2 @@ -784,15 +769,6 @@ gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow& row)// C: 15 in 14 */ test_gnc_sql_load_guid (Fixture *fixture, gconstpointer pData) { }*/ -// Not Used -/* gnc_sql_load_tx_guid -const GncGUID* -gnc_sql_load_tx_guid (const GncSqlBackend* be, GncSqlRow& row)// 1 -*/ -/* static void -test_gnc_sql_load_tx_guid (Fixture *fixture, gconstpointer pData) -{ -}*/ /* gnc_sql_load_object void gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow& row,// C: 29 in 19 */ @@ -915,13 +891,6 @@ build_delete_statement (GncSqlBackend* be,// 3 test_build_delete_statement (Fixture *fixture, gconstpointer pData) { }*/ -/* gnc_sql_commit_standard_item -gboolean -gnc_sql_commit_standard_item (GncSqlBackend* be, QofInstance* inst, const gchar* tableName,// C: 7 in 7 */ -/* static void -test_gnc_sql_commit_standard_item (Fixture *fixture, gconstpointer pData) -{ -}*/ /* do_create_table static gboolean do_create_table (const GncSqlBackend* be, const gchar* table_name,// 5 @@ -1010,7 +979,6 @@ test_suite_gnc_backend_sql (void) // GNC_TEST_ADD (suitename, "gnc sql init", Fixture, nullptr, test_gnc_sql_init, teardown); // GNC_TEST_ADD (suitename, "create tables cb", Fixture, nullptr, test_create_tables_cb, teardown); -// GNC_TEST_ADD (suitename, "gnc sql set load order", Fixture, nullptr, test_gnc_sql_set_load_order, teardown); // GNC_TEST_ADD (suitename, "initial load cb", Fixture, nullptr, test_initial_load_cb, teardown); // GNC_TEST_ADD (suitename, "gnc sql load", Fixture, nullptr, test_gnc_sql_load, teardown); // GNC_TEST_ADD (suitename, "write account tree", Fixture, nullptr, test_write_account_tree, teardown); @@ -1038,7 +1006,6 @@ test_suite_gnc_backend_sql (void) // GNC_TEST_ADD (suitename, "gnc sql run query", Fixture, nullptr, test_gnc_sql_run_query, teardown); // GNC_TEST_ADD (suitename, "business core sql init", Fixture, nullptr, test_business_core_sql_init, teardown); // GNC_TEST_ADD (suitename, "gnc sql init object handlers", Fixture, nullptr, test_gnc_sql_init_object_handlers, teardown); -// GNC_TEST_ADD (suitename, "gnc sql get integer value", Fixture, nullptr, test_gnc_sql_get_integer_value, teardown); // GNC_TEST_ADD (suitename, "get autoinc id", Fixture, nullptr, test_get_autoinc_id, teardown); // GNC_TEST_ADD (suitename, "set autoinc id", Fixture, nullptr, test_set_autoinc_id, teardown); // GNC_TEST_ADD (suitename, "gnc sql get getter", Fixture, nullptr, test_gnc_sql_get_getter, teardown); @@ -1098,7 +1065,6 @@ test_suite_gnc_backend_sql (void) // GNC_TEST_ADD (suitename, "build insert statement", Fixture, nullptr, test_build_insert_statement, teardown); // GNC_TEST_ADD (suitename, "build update statement", Fixture, nullptr, test_build_update_statement, teardown); // GNC_TEST_ADD (suitename, "build delete statement", Fixture, nullptr, test_build_delete_statement, teardown); -// GNC_TEST_ADD (suitename, "gnc sql commit standard item", Fixture, nullptr, test_gnc_sql_commit_standard_item, teardown); // GNC_TEST_ADD (suitename, "do create table", Fixture, nullptr, test_do_create_table, teardown); // GNC_TEST_ADD (suitename, "gnc sql create table", Fixture, nullptr, test_gnc_sql_create_table, teardown); // GNC_TEST_ADD (suitename, "gnc sql create temp table", Fixture, nullptr, test_gnc_sql_create_temp_table, teardown); From faf59964e4e4b92a422dd50305c24874de975d63 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 16 Jul 2016 12:12:03 -0700 Subject: [PATCH 21/63] Rename gnc-backend-dbi-priv.h to gnc-backend-dbi.hpp. Also remove "#ifdef __cplusplus" from both gnc-backend-dbi.hpp and gnc-backend-dbi.h, these files are always C++. --- src/backend/dbi/gnc-backend-dbi.h | 4 ---- .../{gnc-backend-dbi-priv.h => gnc-backend-dbi.hpp} | 12 ++++-------- src/backend/dbi/test/test-backend-dbi-basic.cpp | 2 +- src/backend/dbi/test/test-dbi-stuff.cpp | 2 +- 4 files changed, 6 insertions(+), 14 deletions(-) rename src/backend/dbi/{gnc-backend-dbi-priv.h => gnc-backend-dbi.hpp} (97%) diff --git a/src/backend/dbi/gnc-backend-dbi.h b/src/backend/dbi/gnc-backend-dbi.h index d836d6e1dc..7d769ae551 100644 --- a/src/backend/dbi/gnc-backend-dbi.h +++ b/src/backend/dbi/gnc-backend-dbi.h @@ -28,10 +28,8 @@ #ifndef GNC_BACKEND_DBI_H_ #define GNC_BACKEND_DBI_H_ -#ifdef __cplusplus extern "C" { -#endif #include /** Initialization function which can be used when this module is @@ -48,7 +46,5 @@ void gnc_module_finalize_backend_dbi (void); G_MODULE_EXPORT void qof_backend_module_init (void); G_MODULE_EXPORT void qof_backend_module_finalize (void); #endif -#ifdef __cplusplus } -#endif #endif /* GNC_BACKEND_DBI_H_ */ diff --git a/src/backend/dbi/gnc-backend-dbi-priv.h b/src/backend/dbi/gnc-backend-dbi.hpp similarity index 97% rename from src/backend/dbi/gnc-backend-dbi-priv.h rename to src/backend/dbi/gnc-backend-dbi.hpp index 41d46f13d1..d265bb3c28 100644 --- a/src/backend/dbi/gnc-backend-dbi-priv.h +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -1,5 +1,5 @@ /******************************************************************** - * gnc-backend-dbi-priv.h: load and save data to SQL via libdbi * + * gnc-backend-dbi.hpp: load and save data to SQL via libdbi * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * @@ -20,16 +20,12 @@ \********************************************************************/ /* Private structures and variables for gnc-backend-dbi.c and its unit tests */ -#ifndef GNC_BACKEND_DBI_PRIV_H -#define GNC_BACKEND_DBI_PRIV_H -#ifdef __cplusplus +#ifndef GNC_BACKEND_DBI_HPP +#define GNC_BACKEND_DBI_HPP extern "C" { -#endif #include -#ifdef __cplusplus } -#endif #include "gnc-backend-sql.h" enum class DbType @@ -239,4 +235,4 @@ private: }; -#endif //GNC_BACKEND_DBI_PRIV_H +#endif //GNC_BACKEND_DBI_HPP diff --git a/src/backend/dbi/test/test-backend-dbi-basic.cpp b/src/backend/dbi/test/test-backend-dbi-basic.cpp index 41c4f8c7c1..e09489e7ab 100644 --- a/src/backend/dbi/test/test-backend-dbi-basic.cpp +++ b/src/backend/dbi/test/test-backend-dbi-basic.cpp @@ -51,7 +51,7 @@ extern "C" #include } /* For test_conn_index_functions */ -#include "../gnc-backend-dbi-priv.h" +#include "../gnc-backend-dbi.hpp" extern "C" { #include diff --git a/src/backend/dbi/test/test-dbi-stuff.cpp b/src/backend/dbi/test/test-dbi-stuff.cpp index c04af87822..ad5e81dc9f 100644 --- a/src/backend/dbi/test/test-dbi-stuff.cpp +++ b/src/backend/dbi/test/test-dbi-stuff.cpp @@ -39,7 +39,7 @@ extern "C" } #include -#include "../gnc-backend-dbi-priv.h" +#include "../gnc-backend-dbi.hpp" G_GNUC_UNUSED static QofLogModule log_module = "test-dbi"; From 3894a2e8b76d766b881111688454b2ed262ab5e9 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 16 Jul 2016 16:39:09 -0700 Subject: [PATCH 22/63] Convert struct provider_functions_t into virtual class GncDbiProvider. Implementation templated as template GncDbiProviderImpl. Converted GSLists to std::vectors and GStrings to std::strings. --- src/backend/dbi/CMakeLists.txt | 2 +- src/backend/dbi/Makefile.am | 2 +- src/backend/dbi/gnc-backend-dbi.cpp | 598 +++++++----------- src/backend/dbi/gnc-backend-dbi.hpp | 60 +- .../dbi/test/test-backend-dbi-basic.cpp | 12 +- src/backend/dbi/test/test-dbi-stuff.cpp | 15 +- src/backend/sql/gnc-backend-sql.h | 1 - 7 files changed, 250 insertions(+), 440 deletions(-) diff --git a/src/backend/dbi/CMakeLists.txt b/src/backend/dbi/CMakeLists.txt index 2a3d4a0af4..711a65d810 100644 --- a/src/backend/dbi/CMakeLists.txt +++ b/src/backend/dbi/CMakeLists.txt @@ -8,7 +8,7 @@ SET (backend_dbi_SOURCES gnc-backend-dbi.cpp ) SET (backend_dbi_noinst_HEADERS - gnc-backend-dbi.h gnc-backend-dbi-priv.h + gnc-backend-dbi.h gnc-backend-dbi.hpp ) # Add dependency on config.h diff --git a/src/backend/dbi/Makefile.am b/src/backend/dbi/Makefile.am index aab8c0fb95..ac07b8d2e5 100644 --- a/src/backend/dbi/Makefile.am +++ b/src/backend/dbi/Makefile.am @@ -25,7 +25,7 @@ libgncmod_backend_dbi_la_SOURCES = \ noinst_HEADERS = \ gnc-backend-dbi.h \ - gnc-backend-dbi-priv.h + gnc-backend-dbi.hpp libgncmod_backend_dbi_la_LDFLAGS = -shared -avoid-version libgncmod_backend_dbi_la_LIBADD = \ diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index cabd8a4354..95ba20338b 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -86,7 +86,7 @@ extern "C" #include #include #include "gnc-backend-dbi.h" -#include "gnc-backend-dbi-priv.h" +#include "gnc-backend-dbi.hpp" #if PLATFORM(WINDOWS) #ifdef __STRICT_ANSI_UNSET__ @@ -157,73 +157,43 @@ static gchar lock_table[] = "gnclock"; #define SQLITE3_URI_PREFIX (SQLITE3_URI_TYPE "://") #define PGSQL_DEFAULT_PORT 5432 -static gchar* conn_create_table_ddl_sqlite3 (const GncSqlConnection* conn, - const gchar* table_name, - const ColVec& info_vec); -static GSList* conn_get_table_list (dbi_conn conn, const gchar* dbname); -static GSList* conn_get_table_list_sqlite3 (dbi_conn conn, const gchar* dbname); -static void append_sqlite3_col_def (GString* ddl, const GncSqlColumnInfo& info); -static GSList *conn_get_index_list_sqlite3 (dbi_conn conn); -static void conn_drop_index_sqlite3 (dbi_conn conn, const gchar *index); -static provider_functions_t provider_sqlite3 = -{ - conn_create_table_ddl_sqlite3, - conn_get_table_list_sqlite3, - append_sqlite3_col_def, - conn_get_index_list_sqlite3, - conn_drop_index_sqlite3 -}; #define SQLITE3_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" - -static gchar* conn_create_table_ddl_mysql (const GncSqlConnection* conn, - const gchar* table_name, - const ColVec& info_vec); -static void append_mysql_col_def (GString* ddl, const GncSqlColumnInfo& info); -static GSList *conn_get_index_list_mysql (dbi_conn conn); -static void conn_drop_index_mysql (dbi_conn conn, const gchar *index); -static provider_functions_t provider_mysql = -{ - conn_create_table_ddl_mysql, - conn_get_table_list, - append_mysql_col_def, - conn_get_index_list_mysql, - conn_drop_index_mysql -}; #define MYSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" - -static gchar* conn_create_table_ddl_pgsql (const GncSqlConnection* conn, - const gchar* table_name, - const ColVec& info_vec ); -static GSList* conn_get_table_list_pgsql (dbi_conn conn, const gchar* dbname); -static void append_pgsql_col_def (GString* ddl, const GncSqlColumnInfo& info); -static GSList *conn_get_index_list_pgsql (dbi_conn conn); -static void conn_drop_index_pgsql (dbi_conn conn, const gchar *index); - -static provider_functions_t provider_pgsql = -{ - conn_create_table_ddl_pgsql, - conn_get_table_list_pgsql, - append_pgsql_col_def, - conn_get_index_list_pgsql, - conn_drop_index_pgsql -}; #define PGSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d %02d%02d%02d" static gboolean gnc_dbi_lock_database (QofBackend *qbe, gboolean ignore_lock); static void gnc_dbi_unlock (QofBackend *qbe); static gboolean save_may_clobber_data (QofBackend* qbe); -static gchar* create_index_ddl (const GncSqlConnection* conn, - const gchar* index_name, - const gchar* table_name, - const EntryVec& col_table); +static std::string create_index_ddl (const GncSqlConnection* conn, + const std::string& index_name, + const std::string& table_name, + const EntryVec& col_table); static GncDbiTestResult conn_test_dbi_library (dbi_conn conn); -#define GNC_DBI_PROVIDER_SQLITE (&provider_sqlite3) -#define GNC_DBI_PROVIDER_MYSQL (&provider_mysql) -#define GNC_DBI_PROVIDER_PGSQL (&provider_pgsql) - #define DBI_MAX_CONN_ATTEMPTS 5 +enum class DbType +{ + DBI_SQLITE, + DBI_MYSQL, + DBI_PGSQL +}; + + +template +class GncDbiProviderImpl : public GncDbiProvider +{ +public: + std::string create_table_ddl(const GncSqlConnection* conn, + const std::string& table_name, + const ColVec& info_vec); + std::vector get_table_list(dbi_conn conn, + const std::string& dbname); + void append_col_def(std::string& ddl, const GncSqlColumnInfo& info); + std::vector get_index_list (dbi_conn conn); + void drop_index(dbi_conn conn, const std::string& index); +}; + /* ================================================================= */ @@ -454,8 +424,8 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, { delete (be->sql_be.conn); } - be->sql_be.conn = new GncDbiSqlConnection (GNC_DBI_PROVIDER_SQLITE, qbe, - be->conn); + be->sql_be.conn = new GncDbiSqlConnection (new GncDbiProviderImpl, + qbe, be->conn); be->sql_be.timespec_format = SQLITE3_TIMESPEC_STR_FORMAT; /* We should now have a proper session set up. @@ -470,33 +440,31 @@ exit: LEAVE ("%s", msg); } -static GSList* -conn_get_index_list_sqlite3 (dbi_conn conn) +template<> std::vector +GncDbiProviderImpl::get_index_list (dbi_conn conn) { - GSList* list = nullptr; - const gchar* errmsg; + std::vector retval; + const char* errmsg; dbi_result result = dbi_conn_query (conn, "SELECT name FROM sqlite_master WHERE type = 'index' AND name NOT LIKE 'sqlite_autoindex%'"); if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) { - g_print ("Index Table Retrieval Error: %s\n", errmsg); - return nullptr; + PWARN ("Index Table Retrieval Error: %s\n", errmsg); + return retval; } while (dbi_result_next_row (result) != 0) { - const gchar* index_name; - - index_name = dbi_result_get_string_idx (result, 1); - list = g_slist_prepend (list, strdup (index_name)); + std::string index_name {dbi_result_get_string_idx (result, 1)}; + retval.push_back(index_name); } dbi_result_free (result); - return list; + return retval; } -static void -conn_drop_index_sqlite3 (dbi_conn conn, const gchar* index) +template void +GncDbiProviderImpl

::drop_index(dbi_conn conn, const std::string& index) { - dbi_result result = dbi_conn_queryf (conn, "DROP INDEX %s", index); + dbi_result result = dbi_conn_queryf (conn, "DROP INDEX %s", index.c_str()); if (result) dbi_result_free (result); } @@ -1111,8 +1079,8 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, { delete (be->sql_be.conn); } - be->sql_be.conn = new GncDbiSqlConnection (GNC_DBI_PROVIDER_MYSQL, qbe, - be->conn); + be->sql_be.conn = new GncDbiSqlConnection (new GncDbiProviderImpl, + qbe, be->conn); } be->sql_be.timespec_format = MYSQL_TIMESPEC_STR_FORMAT; @@ -1135,69 +1103,60 @@ exit: LEAVE (" "); } -static GSList* -conn_get_index_list_mysql (dbi_conn conn) +template<> std::vector +GncDbiProviderImpl::get_index_list (dbi_conn conn) { - GSList* index_list = nullptr; - dbi_result table_list; + std::vector retval; const char* errmsg; - const gchar* dbname = dbi_conn_get_option (conn, "dbname"); - g_return_val_if_fail (conn != nullptr, nullptr); - table_list = dbi_conn_get_table_list (conn, dbname, nullptr); + auto dbname = dbi_conn_get_option (conn, "dbname"); + auto table_list = dbi_conn_get_table_list (conn, dbname, nullptr); if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) { - g_print ("Table Retrieval Error: %s\n", errmsg); - return nullptr; + PWARN ("Table Retrieval Error: %s\n", errmsg); + return retval; } while (dbi_result_next_row (table_list) != 0) { - dbi_result result; - const gchar* table_name = dbi_result_get_string_idx (table_list, 1); - result = dbi_conn_queryf (conn, - "SHOW INDEXES IN %s WHERE Key_name != 'PRIMARY'", - table_name); + auto table_name = dbi_result_get_string_idx (table_list, 1); + auto result = dbi_conn_queryf (conn, + "SHOW INDEXES IN %s WHERE Key_name != 'PRIMARY'", + table_name); if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) { - g_print ("Index Table Retrieval Error: %s\n", errmsg); + PWARN ("Index Table Retrieval Error: %s on table %s\n", + errmsg, table_name); continue; } while (dbi_result_next_row (result) != 0) { - const gchar* index_name = dbi_result_get_string_idx (result, 3); - index_list = g_slist_prepend (index_list, g_strjoin (" ", index_name, - table_name, nullptr)); + std::string index_name {dbi_result_get_string_idx (result, 3)}; + retval.push_back(index_name + " " + table_name); } dbi_result_free (result); } - return index_list; + return retval; } -static void -conn_drop_index_mysql (dbi_conn conn, const gchar* index) +template<> void +GncDbiProviderImpl::drop_index (dbi_conn conn, const std::string& index) { - dbi_result result; - gchar** index_table_split = g_strsplit (index, " ", 2); - int splitlen = -1; - - /* Check if the index split can be valid */ - while (index_table_split[++splitlen] != nullptr) - { /* do nothing, just count split members */ } - - if (splitlen != 2) + unsigned int sep{0}, count{0}; + while ((sep = index.find(' ', sep)) != std::string::npos) + ++count; + if (count != 1) { - g_print ("Drop index error: invalid MySQL index format ( ): %s", - index); + PWARN("Drop index error: invalid MySQL index format (
): %s", + index.c_str()); return; } - result = dbi_conn_queryf (conn, "DROP INDEX %s ON %s", - index_table_split[0], index_table_split[1]); + auto result = dbi_conn_queryf (conn, "DROP INDEX %s ON %s", + index.substr(0, sep).c_str(), + index.substr(sep + 1).c_str()); if (result) dbi_result_free (result); - - g_strfreev (index_table_split); } static void @@ -1450,8 +1409,8 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, { delete (be->sql_be.conn); } - be->sql_be.conn = new GncDbiSqlConnection (GNC_DBI_PROVIDER_PGSQL, qbe, - be->conn); + be->sql_be.conn = new GncDbiSqlConnection (new GncDbiProviderImpl, + qbe, be->conn); } be->sql_be.timespec_format = PGSQL_TIMESPEC_STR_FORMAT; @@ -1475,40 +1434,28 @@ exit: LEAVE (" "); } -static GSList* -conn_get_index_list_pgsql (dbi_conn conn) +template<> std::vector +GncDbiProviderImpl::get_index_list (dbi_conn conn) { - GSList* list = nullptr; - const gchar* errmsg; - dbi_result result; + std::vector retval; + const char* errmsg; PINFO ("Retrieving postgres index list\n"); - result = dbi_conn_query (conn, - "SELECT relname FROM pg_class AS a INNER JOIN pg_index AS b ON (b.indexrelid = a.oid) INNER JOIN pg_namespace AS c ON (a.relnamespace = c.oid) WHERE reltype = '0' AND indisprimary = 'f' AND nspname = 'public'"); + auto result = dbi_conn_query (conn, + "SELECT relname FROM pg_class AS a INNER JOIN pg_index AS b ON (b.indexrelid = a.oid) INNER JOIN pg_namespace AS c ON (a.relnamespace = c.oid) WHERE reltype = '0' AND indisprimary = 'f' AND nspname = 'public'"); if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) { - g_print ("Index Table Retrieval Error: %s\n", errmsg); - return nullptr; + PWARN("Index Table Retrieval Error: %s\n", errmsg); + return retval; } while (dbi_result_next_row (result) != 0) { - const gchar* index_name; - - index_name = dbi_result_get_string_idx (result, 1); - list = g_slist_prepend (list, strdup (index_name)); + std::string index_name {dbi_result_get_string_idx (result, 1)}; + retval.push_back(index_name); } dbi_result_free (result); - return list; + return retval; } -static void -conn_drop_index_pgsql (dbi_conn conn, const gchar* index) -{ - dbi_result result = dbi_conn_queryf (conn, "DROP INDEX %s", index); - if (result) - dbi_result_free (result); -} - - /* ================================================================= */ static void @@ -1682,24 +1629,20 @@ GncDbiSqlConnection::table_manage_backup (const std::string& table_name, */ gboolean -conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, +conn_table_operation (GncSqlConnection* sql_conn, + std::vector table_name_list, TableOpType op) { - GSList* node; gboolean result = TRUE; GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (sql_conn); - GSList* full_table_name_list = nullptr; const gchar* dbname = dbi_conn_get_option (conn->m_conn, "dbname"); - g_return_val_if_fail (table_name_list != nullptr, FALSE); - if (op == rollback) - full_table_name_list = - conn->m_provider->get_table_list (conn->m_conn, dbname); + g_return_val_if_fail (!table_name_list.empty(), FALSE); - for (node = table_name_list; node != nullptr && result; node = node->next) + for (auto table : table_name_list) { - gchar* table_name = (gchar*)node->data; dbi_result result; + auto table_name = table.c_str(); /* Ignore the lock table */ if (g_strcmp0 (table_name, lock_table) == 0) { @@ -1711,14 +1654,20 @@ conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, switch (op) { case rollback: - if (g_slist_find (full_table_name_list, table_name)) + { + auto full_table_name_list = + conn->m_provider->get_table_list (conn->m_conn, dbname); + if (std::find (full_table_name_list.begin(), + full_table_name_list.end(), + table_name) != full_table_name_list.end()) { result = dbi_conn_queryf (conn->m_conn, "DROP TABLE %s", table_name); if (result) break; } - /* Fall through */ + } + /* Fall through */ case backup: case drop_backup: result = conn->table_manage_backup (table_name, op); @@ -1744,7 +1693,6 @@ conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, } } } - gnc_table_slist_free (full_table_name_list); return result; } @@ -1763,7 +1711,6 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) GncDbiBackend* be = (GncDbiBackend*)qbe; GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (((GncSqlBackend*) be)->conn); - GSList* table_list, *index_list, *iter; const gchar* dbname = nullptr; g_return_if_fail (be != nullptr); @@ -1771,49 +1718,38 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) ENTER ("book=%p, primary=%p", book, be->primary_book); dbname = dbi_conn_get_option (be->conn, "dbname"); - table_list = conn->m_provider->get_table_list (conn->m_conn, dbname); - if (!conn_table_operation ((GncSqlConnection*)conn, table_list, - backup)) + auto table_list = conn->m_provider->get_table_list (conn->m_conn, dbname); + if (!conn_table_operation (conn, table_list, backup)) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - conn_table_operation ((GncSqlConnection*)conn, table_list, - rollback); + conn_table_operation (conn, table_list, rollback); LEAVE ("Failed to rename tables"); - gnc_table_slist_free (table_list); return; } - index_list = conn->m_provider->get_index_list (conn->m_conn); - for (iter = index_list; iter != nullptr; iter = g_slist_next (iter)) + auto index_list = conn->m_provider->get_index_list (conn->m_conn); + for (auto index : index_list) { const char* errmsg; - conn->m_provider->drop_index (conn->m_conn, static_cast (iter->data)); + conn->m_provider->drop_index (conn->m_conn, index); if (DBI_ERROR_NONE != dbi_conn_error (conn->m_conn, &errmsg)) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - gnc_table_slist_free (index_list); - conn_table_operation ((GncSqlConnection*)conn, table_list, - rollback); - gnc_table_slist_free (table_list); + conn_table_operation (conn, table_list, rollback); LEAVE ("Failed to drop indexes %s", errmsg); return; } } - gnc_table_slist_free (index_list); - be->is_pristine_db = TRUE; be->primary_book = book; gnc_sql_sync_all (&be->sql_be, book); if (qof_backend_check_error (qbe)) { - conn_table_operation ((GncSqlConnection*)conn, table_list, - rollback); + conn_table_operation (conn, table_list, rollback); LEAVE ("Failed to create new database tables"); return; } - conn_table_operation ((GncSqlConnection*)conn, table_list, - drop_backup); - gnc_table_slist_free (table_list); + conn_table_operation (conn, table_list, drop_backup); LEAVE ("book=%p", book); } /* ================================================================= */ @@ -2451,59 +2387,49 @@ GncDbiSqlConnection::commit_transaction () const noexcept return success; } -static gchar* -create_index_ddl (const GncSqlConnection* conn, const char* index_name, - const char* table_name, const EntryVec& col_table) +static std::string +create_index_ddl (const GncSqlConnection* conn, const std::string& index_name, + const std::string& table_name, const EntryVec& col_table) { - GString* ddl; - - g_return_val_if_fail (conn != nullptr, nullptr); - g_return_val_if_fail (index_name != nullptr, nullptr); - g_return_val_if_fail (table_name != nullptr, nullptr); - - ddl = g_string_new (""); - g_string_printf (ddl, "CREATE INDEX %s ON %s (", index_name, table_name); + std::string ddl; + ddl += "CREATE INDEX " + index_name + " ON " + table_name + "("; for (auto const table_row : col_table) { if (table_row != *col_table.begin()) { - (void)g_string_append (ddl, ", "); + ddl =+ ", "; } - g_string_append_printf (ddl, "%s", table_row->name()); + ddl += table_row->name(); } - (void)g_string_append (ddl, ")"); - - return g_string_free (ddl, FALSE); + ddl += ")"; + return ddl; } -gchar* +std::string add_columns_ddl(const GncSqlConnection* conn, - const gchar* table_name, + const std::string& table_name, const ColVec& info_vec) { - GString* ddl; - GncDbiSqlConnection* dbi_conn = (GncDbiSqlConnection*)conn; + std::string ddl; + const GncDbiSqlConnection* dbi_conn = dynamic_cast(conn); g_return_val_if_fail (conn != nullptr, nullptr); - g_return_val_if_fail (table_name != nullptr, nullptr); - - ddl = g_string_new (""); - g_string_printf (ddl, "ALTER TABLE %s ", table_name); + ddl += "ALTER TABLE " + table_name; for (auto const& info : info_vec) { if (info != *info_vec.begin()) { - (void)g_string_append (ddl, ", "); + ddl += ", "; } - g_string_append (ddl, "ADD COLUMN "); + ddl += "ADD COLUMN "; dbi_conn->m_provider->append_col_def (ddl, info); } - - return g_string_free (ddl, FALSE); + return ddl; } -static void -append_sqlite3_col_def(GString* ddl, const GncSqlColumnInfo& info) +template<> void +GncDbiProviderImpl::append_col_def(std::string& ddl, + const GncSqlColumnInfo& info) { const char* type_name = nullptr; @@ -2529,53 +2455,51 @@ append_sqlite3_col_def(GString* ddl, const GncSqlColumnInfo& info) PERR ("Unknown column type: %d\n", info.m_type); type_name = ""; } - g_string_append_printf (ddl, "%s %s", info.m_name.c_str(), type_name); + ddl += (info.m_name + " " + type_name); if (info.m_size != 0) { - (void)g_string_append_printf (ddl, "(%d)", info.m_size); + ddl += "(" + std::to_string(info.m_size) + ")"; } if (info.m_primary_key) { - (void)g_string_append (ddl, " PRIMARY KEY"); + ddl += " PRIMARY KEY"; } if (info.m_autoinc) { - (void)g_string_append (ddl, " AUTOINCREMENT"); + ddl += " AUTOINCREMENT"; } if (info.m_not_null) { - (void)g_string_append (ddl, " NOT NULL"); + ddl += " NOT NULL"; } } -static gchar* -conn_create_table_ddl_sqlite3 (const GncSqlConnection* conn, - const gchar* table_name, - const ColVec& info_vec) +template std::string +GncDbiProviderImpl

::create_table_ddl (const GncSqlConnection* conn, + const std::string& table_name, + const ColVec& info_vec) { - GString* ddl; + std::string ddl; unsigned int col_num = 0; - g_return_val_if_fail (conn != nullptr, nullptr); - g_return_val_if_fail (table_name != nullptr, nullptr); - - ddl = g_string_new (""); - g_string_printf (ddl, "CREATE TABLE %s (", table_name); + g_return_val_if_fail (conn != nullptr, ddl); + ddl += "CREATE TABLE " + table_name + "("; for (auto const& info : info_vec) { if (col_num++ != 0) { - (void)g_string_append (ddl, ", "); + ddl += ", "; } - append_sqlite3_col_def (ddl, info); + append_col_def (ddl, info); } - (void)g_string_append (ddl, ")"); + ddl += ")"; - return g_string_free (ddl, FALSE); + return ddl; } -static void -append_mysql_col_def (GString* ddl, const GncSqlColumnInfo& info) +template<> void +GncDbiProviderImpl::append_col_def (std::string& ddl, + const GncSqlColumnInfo& info) { const char* type_name = nullptr; @@ -2608,56 +2532,33 @@ append_mysql_col_def (GString* ddl, const GncSqlColumnInfo& info) PERR ("Unknown column type: %d\n", info.m_type); type_name = ""; } - g_string_append_printf (ddl, "%s %s", info.m_name.c_str(), type_name); + ddl += info.m_name + " " + type_name; if (info.m_size != 0 && info.m_type == BCT_STRING) { - g_string_append_printf (ddl, "(%d)", info.m_size); + ddl += std::to_string(info.m_size); } if (info.m_unicode) { - (void)g_string_append (ddl, " CHARACTER SET utf8"); + ddl += " CHARACTER SET utf8"; } if (info.m_primary_key) { - (void)g_string_append (ddl, " PRIMARY KEY"); + ddl += " PRIMARY KEY"; } if (info.m_autoinc) { - (void)g_string_append (ddl, " AUTO_INCREMENT"); + ddl += " AUTO_INCREMENT"; } if (info.m_not_null) { - (void)g_string_append (ddl, " NOT NULL"); + ddl += " NOT NULL"; } } -static gchar* -conn_create_table_ddl_mysql (const GncSqlConnection* conn, - const gchar* table_name, const ColVec& info_vec) -{ - GString* ddl; - unsigned int col_num = 0; - g_return_val_if_fail (conn != nullptr, nullptr); - g_return_val_if_fail (table_name != nullptr, nullptr); - - ddl = g_string_new (""); - g_string_printf (ddl, "CREATE TABLE %s (", table_name); - for (auto const& info : info_vec) - { - if (col_num++ != 0) - { - (void)g_string_append (ddl, ", "); - } - append_mysql_col_def (ddl, info); - } - (void)g_string_append (ddl, ")"); - - return g_string_free (ddl, FALSE); -} - -static void -append_pgsql_col_def (GString* ddl, const GncSqlColumnInfo& info) +template<> void +GncDbiProviderImpl::append_col_def (std::string& ddl, + const GncSqlColumnInfo& info) { const char* type_name = nullptr; @@ -2698,67 +2599,36 @@ append_pgsql_col_def (GString* ddl, const GncSqlColumnInfo& info) PERR ("Unknown column type: %d\n", info.m_type); type_name = ""; } - g_string_append_printf (ddl, "%s %s", info.m_name.c_str(), type_name); + ddl += info.m_name + " " + type_name; if (info.m_size != 0 && info.m_type == BCT_STRING) { - g_string_append_printf (ddl, "(%d)", info.m_size); + ddl += "(" + std::to_string(info.m_size) + ")"; } if (info.m_primary_key) { - (void)g_string_append (ddl, " PRIMARY KEY"); + ddl += " PRIMARY KEY"; } if (info.m_not_null) { - (void)g_string_append (ddl, " NOT NULL"); + ddl += " NOT NULL"; } } -static gchar* -conn_create_table_ddl_pgsql (const GncSqlConnection* conn, const gchar* table_name, - const ColVec& info_vec) -{ - GString* ddl; - unsigned int col_num = 0; - - g_return_val_if_fail (conn != nullptr, nullptr); - g_return_val_if_fail (table_name != nullptr, nullptr); - - ddl = g_string_new (""); - g_string_printf (ddl, "CREATE TABLE %s (", table_name); - for (auto const& info : info_vec) - { - if (col_num++ != 0) - { - (void)g_string_append (ddl, ", "); - } - append_pgsql_col_def (ddl, info); - } - (void)g_string_append (ddl, ")"); - - return g_string_free (ddl, FALSE); -} - bool GncDbiSqlConnection::create_table (const std::string& table_name, const ColVec& info_vec) const noexcept { - auto ddl = m_provider->create_table_ddl(this, table_name.c_str(), info_vec); - if (ddl != nullptr) - { - - DEBUG ("SQL: %s\n", ddl); - auto result = dbi_conn_query (m_conn, ddl); - g_free (ddl); - auto status = dbi_result_free (result); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - } - else - { + auto ddl = m_provider->create_table_ddl(this, table_name, info_vec); + if (ddl.empty()) return false; + + DEBUG ("SQL: %s\n", ddl.c_str()); + auto result = dbi_conn_query (m_conn, ddl.c_str()); + auto status = dbi_result_free (result); + if (status < 0) + { + PERR ("Error in dbi_result_free() result\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } return true; @@ -2769,23 +2639,16 @@ GncDbiSqlConnection::create_index(const std::string& index_name, const std::string& table_name, const EntryVec& col_table) const noexcept { - auto ddl = create_index_ddl (this, index_name.c_str(), table_name.c_str(), - col_table); - if (ddl != nullptr) - { - DEBUG ("SQL: %s\n", ddl); - auto result = dbi_conn_query (m_conn, ddl); - g_free (ddl); - auto status = dbi_result_free (result); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - } - else - { + auto ddl = create_index_ddl (this, index_name, table_name, col_table); + if (ddl.empty()) return false; + DEBUG ("SQL: %s\n", ddl.c_str()); + auto result = dbi_conn_query (m_conn, ddl.c_str()); + auto status = dbi_result_free (result); + if (status < 0) + { + PERR ("Error in dbi_result_free() result\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); } return true; @@ -2796,13 +2659,12 @@ GncDbiSqlConnection::add_columns_to_table(const std::string& table_name, const ColVec& info_vec) const noexcept { - auto ddl = add_columns_ddl(this, table_name.c_str(), info_vec); - if (ddl == nullptr) - return FALSE; + auto ddl = add_columns_ddl(this, table_name, info_vec); + if (ddl.empty()) + return false; - DEBUG ("SQL: %s\n", ddl); - auto result = dbi_conn_query (m_conn, ddl); - g_free (ddl); + DEBUG ("SQL: %s\n", ddl.c_str()); + auto result = dbi_conn_query (m_conn, ddl.c_str()); auto status = dbi_result_free (result); if (status < 0) { @@ -2832,85 +2694,55 @@ GncDbiSqlConnection::quote_string (const std::string& unquoted_str) } } -static GSList* -conn_get_table_list (dbi_conn conn, const gchar* dbname) +static std::vector +conn_get_table_list (dbi_conn conn, const std::string& dbname) { - GSList* list = nullptr; - - auto tables = dbi_conn_get_table_list (conn, dbname, nullptr); + std::vector retval; + auto tables = dbi_conn_get_table_list (conn, dbname.c_str(), nullptr); while (dbi_result_next_row (tables) != 0) { - const gchar* table_name; - - table_name = dbi_result_get_string_idx (tables, 1); - list = g_slist_prepend (list, strdup (table_name)); + std::string table_name {dbi_result_get_string_idx (tables, 1)}; + retval.push_back(table_name); } dbi_result_free (tables); - return list; + return retval; } -static GSList* -conn_get_table_list_sqlite3 (dbi_conn conn, const gchar* dbname) +template<> std::vector +GncDbiProviderImpl::get_table_list (dbi_conn conn, + const std::string& dbname) { - gboolean change_made; - /* Return the list, but remove the tables that sqlite3 adds for * its own use. */ - GSList* list = conn_get_table_list (conn, dbname); - change_made = TRUE; - while (list != nullptr && change_made) - { - GSList* node; - - change_made = FALSE; - for (node = list; node != nullptr; node = node->next) - { - const gchar* table_name = (const gchar*)node->data; - - if (strcmp (table_name, "sqlite_sequence") == 0) - { - g_free (node->data); - list = g_slist_delete_link (list, node); - change_made = TRUE; - break; - } - } - } + auto list = conn_get_table_list (conn, dbname); + auto end = std::remove(list.begin(), list.end(), "sqlite_sequence"); + list.erase(end, list.end()); return list; } -static GSList* -conn_get_table_list_pgsql (dbi_conn conn, const gchar* dbname) +template<> std::vector +GncDbiProviderImpl::get_table_list (dbi_conn conn, + const std::string& dbname) { - gboolean change_made; + return conn_get_table_list (conn, dbname); +} - /* Return the list, but remove the tables that postgresql adds from the information schema. */ - GSList* list = conn_get_table_list (conn, dbname); - change_made = TRUE; - while (list != nullptr && change_made) - { - GSList* node; - - change_made = FALSE; - for (node = list; node != nullptr; node = node->next) - { - const gchar* table_name = (const gchar*)node->data; - - if (strcmp (table_name, "sql_features") == 0 || - strcmp (table_name, "sql_implementation_info") == 0 || - strcmp (table_name, "sql_languages") == 0 || - strcmp (table_name, "sql_packages") == 0 || - strcmp (table_name, "sql_parts") == 0 || - strcmp (table_name, "sql_sizing") == 0 || - strcmp (table_name, "sql_sizing_profiles") == 0) - { - g_free (node->data); - list = g_slist_delete_link (list, node); - change_made = TRUE; - break; - } - } - } +template<> std::vector +GncDbiProviderImpl::get_table_list (dbi_conn conn, + const std::string& dbname) +{ + auto list = conn_get_table_list (conn, dbname); + auto end = std::remove_if (list.begin(), list.end(), + [](std::string& table_name){ + return table_name == "sql_features" || + table_name == "sql_implementation_info" || + table_name == "sql_languages" || + table_name == "sql_packages" || + table_name == "sql_parts" || + table_name == "sql_sizing" || + table_name == "sql_sizing_profiles"; + }); + list.erase(end, list.end()); return list; } diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index d265bb3c28..cba87329b9 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -28,13 +28,6 @@ extern "C" } #include "gnc-backend-sql.h" -enum class DbType -{ - DBI_SQLITE, - DBI_MYSQL, - DBI_PGSQL -}; - /** * Options to conn_table_operation * @var drop Drop (remove without recourse) the table from the database @@ -65,27 +58,25 @@ typedef enum GNC_DBI_FAIL_TEST } GncDbiTestResult; -typedef gchar* (*CREATE_TABLE_DDL_FN) (const GncSqlConnection* conn, - const gchar* table_name, - const ColVec& info_vec); -typedef GSList* (*GET_TABLE_LIST_FN) (dbi_conn conn, const gchar* dbname); -typedef void (*APPEND_COLUMN_DEF_FN) (GString* ddl, - const GncSqlColumnInfo& info); -typedef GSList* (*GET_INDEX_LIST_FN) (dbi_conn conn); -typedef void (*DROP_INDEX_FN) (dbi_conn conn, const gchar* index); -typedef struct +class GncDbiProvider { - CREATE_TABLE_DDL_FN create_table_ddl; - GET_TABLE_LIST_FN get_table_list; - APPEND_COLUMN_DEF_FN append_col_def; - GET_INDEX_LIST_FN get_index_list; - DROP_INDEX_FN drop_index; -} provider_functions_t; +public: + virtual ~GncDbiProvider() = default; + virtual std::string create_table_ddl(const GncSqlConnection* conn, + const std::string& table_name, + const ColVec& info_vec) = 0; + virtual std::vector get_table_list(dbi_conn conn, + const std::string& dbname) = 0; + virtual void append_col_def(std::string& ddl, + const GncSqlColumnInfo& info) = 0; + virtual std::vector get_index_list (dbi_conn conn) = 0; + virtual void drop_index(dbi_conn conn, const std::string& index) = 0; +}; /** * Implementations of GncSqlBackend. */ -struct GncDbiBackend_struct +struct GncDbiBackend { GncSqlBackend sql_be; @@ -103,16 +94,14 @@ struct GncDbiBackend_struct // GHashTable* versions; // Version number for each table }; -typedef struct GncDbiBackend_struct GncDbiBackend; - class GncDbiSqlConnection : public GncSqlConnection { public: - GncDbiSqlConnection (provider_functions_t* provider, QofBackend* qbe, + GncDbiSqlConnection (GncDbiProvider* provider, QofBackend* qbe, dbi_conn conn) : m_qbe{qbe}, m_conn{conn}, m_provider{provider}, m_conn_ok{true}, m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, m_retry{false} {} - ~GncDbiSqlConnection() override = default; + ~GncDbiSqlConnection() override { delete m_provider; }; GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr&) noexcept override; int execute_nonselect_statement (const GncSqlStatementPtr&) @@ -131,7 +120,7 @@ public: std::string quote_string (const std::string&) const noexcept override; QofBackend* qbe () const noexcept { return m_qbe; } dbi_conn conn() const noexcept { return m_conn; } - provider_functions_t* provider() { return m_provider; } + GncDbiProvider* provider() { return m_provider; } inline void set_error (int error, int repeat, bool retry) noexcept { m_last_error = error; @@ -151,17 +140,17 @@ public: /* FIXME: These three friend functions should really be members, but doing * that is too invasive just yet. */ friend gboolean conn_table_operation (GncSqlConnection* sql_conn, - GSList* table_name_list, + std::vector table_name_list, TableOpType op); friend void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book); - friend gchar* add_columns_ddl(const GncSqlConnection* conn, - const gchar* table_name, - const ColVec& info_vec); + friend std::string add_columns_ddl(const GncSqlConnection* conn, + const std::string& table_name, + const ColVec& info_vec); private: QofBackend* m_qbe; dbi_conn m_conn; - provider_functions_t* m_provider; + GncDbiProvider* m_provider; /** Used by the error handler routines to flag if the connection is ok to * use */ @@ -186,8 +175,9 @@ private: gboolean conn_table_operation (GncSqlConnection* sql_conn, GSList* table_name_list, TableOpType op); void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book); -gchar* add_columns_ddl(const GncSqlConnection* conn, const gchar* table_name, - const ColVec& info_vec); +std::string add_columns_ddl(const GncSqlConnection* conn, + const std::string& table_name, + const ColVec& info_vec); /* external access required for tests */ std::string adjust_sql_options_string(const std::string&); diff --git a/src/backend/dbi/test/test-backend-dbi-basic.cpp b/src/backend/dbi/test/test-backend-dbi-basic.cpp index e09489e7ab..73f60d6adb 100644 --- a/src/backend/dbi/test/test-backend-dbi-basic.cpp +++ b/src/backend/dbi/test/test-backend-dbi-basic.cpp @@ -357,21 +357,17 @@ test_conn_index_functions (QofBackend* qbe) { GncDbiBackend* be = (GncDbiBackend*)qbe; GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (be->sql_be.conn); - GSList* index_list, *iter; - index_list = conn->provider()->get_index_list (be->conn); + auto index_list = conn->provider()->get_index_list (be->conn); g_test_message ("Returned from index list\n"); - g_assert (index_list != NULL); - g_assert_cmpint (g_slist_length (index_list), == , 4); - for (iter = index_list; iter != NULL; iter = g_slist_next (iter)) + g_assert_cmpint (index_list.size(), == , 4); + for (auto index : index_list) { const char* errmsg; - conn->provider()->drop_index (be->conn, - static_cast (iter->data)); + conn->provider()->drop_index (be->conn, index); g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn(), &errmsg)); } - g_slist_free (index_list); } /* Given a synthetic session, use the same logic as diff --git a/src/backend/dbi/test/test-dbi-stuff.cpp b/src/backend/dbi/test/test-dbi-stuff.cpp index ad5e81dc9f..38950399d8 100644 --- a/src/backend/dbi/test/test-dbi-stuff.cpp +++ b/src/backend/dbi/test/test-dbi-stuff.cpp @@ -216,23 +216,16 @@ test_conn_index_functions (QofBackend* qbe) { GncDbiBackend* be = (GncDbiBackend*)qbe; GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (be->sql_be.conn); - GSList* index_list, *iter; - index_list = conn->provider()->get_index_list (be->conn); + auto index_list = conn->provider()->get_index_list (be->conn); g_test_message ("Returned from index list\n"); - g_assert (index_list != NULL); - g_assert_cmpint (g_slist_length (index_list), == , 4); - for (iter = index_list; iter != NULL; iter = g_slist_next (iter)) + g_assert_cmpint (index_list.size(), == , 4); + for (auto index : index_list) { const char* errmsg; - conn->provider()->drop_index (be->conn, - static_cast (iter->data)); + conn->provider()->drop_index (be->conn, index); g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn(), &errmsg)); } - - g_slist_free (index_list); - - } static void diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 39b73d3930..334199dedc 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -78,7 +78,6 @@ struct GncSqlBackend GHashTable* versions; /**< Version number for each table */ const gchar* timespec_format; /**< Format string for SQL for timespec values */ }; -typedef struct GncSqlBackend GncSqlBackend; /** * Initialize the SQL backend. From 1f52839271e5ebb981a793706bc5db3be6fdec42 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 16 Jul 2016 17:21:25 -0700 Subject: [PATCH 23/63] Templatize QofDbiBackendProvider. --- src/backend/dbi/gnc-backend-dbi.cpp | 80 ++++++++++------------------- 1 file changed, 27 insertions(+), 53 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 95ba20338b..6f25037f0a 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -95,46 +95,6 @@ extern "C" #endif #endif -struct QofSQLITEBackendProvider : public QofBackendProvider -{ - QofSQLITEBackendProvider (const char* name, const char* type) : - QofBackendProvider {name, type} {} - QofSQLITEBackendProvider(QofSQLITEBackendProvider&) = delete; - QofSQLITEBackendProvider operator=(QofSQLITEBackendProvider&) = delete; - QofSQLITEBackendProvider(QofSQLITEBackendProvider&&) = delete; - QofSQLITEBackendProvider operator=(QofSQLITEBackendProvider&&) = delete; - ~QofSQLITEBackendProvider () = default; - QofBackend* create_backend(void); - bool type_check(const char* type); -}; - -struct QofMYSQLBackendProvider : public QofBackendProvider -{ - QofMYSQLBackendProvider (const char* name, const char* type) : - QofBackendProvider {name, type} {} - QofMYSQLBackendProvider(QofMYSQLBackendProvider&) = delete; - QofMYSQLBackendProvider operator=(QofMYSQLBackendProvider&) = delete; - QofMYSQLBackendProvider(QofMYSQLBackendProvider&&) = delete; - QofMYSQLBackendProvider operator=(QofMYSQLBackendProvider&&) = delete; - ~QofMYSQLBackendProvider () = default; - QofBackend* create_backend(void); - bool type_check(const char* type) { return true; } -}; - -struct QofPGSQLBackendProvider : public QofBackendProvider -{ - QofPGSQLBackendProvider (const char* name, const char* type) : - QofBackendProvider {name, type} {} - QofPGSQLBackendProvider(QofPGSQLBackendProvider&) = delete; - QofPGSQLBackendProvider operator=(QofPGSQLBackendProvider&) = delete; - QofPGSQLBackendProvider(QofPGSQLBackendProvider&&) = delete; - QofPGSQLBackendProvider operator=(QofPGSQLBackendProvider&&) = delete; - ~QofPGSQLBackendProvider () = default; - QofBackend* create_backend(void); - bool type_check(const char* type) { return true; } - -}; - #if LIBDBI_VERSION >= 900 #define HAVE_LIBDBI_R 1 #define HAVE_LIBDBI_TO_LONGLONG 1 @@ -194,6 +154,20 @@ public: void drop_index(dbi_conn conn, const std::string& index); }; +template +class QofDbiBackendProvider : public QofBackendProvider +{ +public: + QofDbiBackendProvider (const char* name, const char* type) : + QofBackendProvider {name, type} {} + QofDbiBackendProvider(QofDbiBackendProvider&) = delete; + QofDbiBackendProvider operator=(QofDbiBackendProvider&) = delete; + QofDbiBackendProvider(QofDbiBackendProvider&&) = delete; + QofDbiBackendProvider operator=(QofDbiBackendProvider&&) = delete; + ~QofDbiBackendProvider () = default; + QofBackend* create_backend(void); + bool type_check(const char* type) { return true; } +}; /* ================================================================= */ @@ -1850,20 +1824,20 @@ new_backend (void (*session_begin) (QofBackend*, QofSession*, const gchar*, return be; } -QofBackend* -QofSQLITEBackendProvider::create_backend() +template<> QofBackend* +QofDbiBackendProvider::create_backend() { return new_backend (gnc_dbi_sqlite3_session_begin); } -QofBackend* -QofMYSQLBackendProvider::create_backend() +template<> QofBackend* +QofDbiBackendProvider::create_backend() { return new_backend (gnc_dbi_mysql_session_begin); } -QofBackend* -QofPGSQLBackendProvider::create_backend() +template<> QofBackend* +QofDbiBackendProvider::create_backend() { return new_backend (gnc_dbi_postgres_session_begin); } @@ -1871,10 +1845,10 @@ QofPGSQLBackendProvider::create_backend() /* * Checks to see whether the file is an sqlite file or not - * + *1980 */ -bool -QofSQLITEBackendProvider::type_check(const char *uri) +template<> bool +QofDbiBackendProvider::type_check(const char *uri) { FILE* f; gchar buf[50]; @@ -1993,23 +1967,23 @@ gnc_module_init_backend_dbi (void) if (have_sqlite3_driver) { const char* name = "GnuCash Libdbi (SQLITE3) Backend"; - auto prov = QofBackendProvider_ptr(new QofSQLITEBackendProvider{name, FILE_URI_TYPE}); + auto prov = QofBackendProvider_ptr(new QofDbiBackendProvider{name, FILE_URI_TYPE}); qof_backend_register_provider(std::move(prov)); - prov = QofBackendProvider_ptr(new QofSQLITEBackendProvider{name, SQLITE3_URI_TYPE}); + prov = QofBackendProvider_ptr(new QofDbiBackendProvider{name, SQLITE3_URI_TYPE}); qof_backend_register_provider(std::move(prov)); } if (have_mysql_driver) { const char *name = "GnuCash Libdbi (MYSQL) Backend"; - auto prov = QofBackendProvider_ptr(new QofMYSQLBackendProvider{name, "mysql"}); + auto prov = QofBackendProvider_ptr(new QofDbiBackendProvider{name, "mysql"}); qof_backend_register_provider(std::move(prov)); } if (have_pgsql_driver) { const char* name = "GnuCash Libdbi (POSTGRESQL) Backend"; - auto prov = QofBackendProvider_ptr(new QofPGSQLBackendProvider{name, "postgres"}); + auto prov = QofBackendProvider_ptr(new QofDbiBackendProvider{name, "postgres"}); qof_backend_register_provider(std::move(prov)); } From eed4a012c3d73b8d1364282dde5531702e887258 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 16 Jul 2016 17:22:29 -0700 Subject: [PATCH 24/63] Remove no-longer-needed gnc_table_slist_free. --- src/backend/dbi/gnc-backend-dbi.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 6f25037f0a..e396559e50 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -171,19 +171,6 @@ public: /* ================================================================= */ -/* Free the contents of a GSList, then free the list. Don't use this - * if the elements of the list weren't created with g_new! */ -static void -gnc_table_slist_free (GSList* table_list) -{ - GSList* list; - for (list = table_list; list != nullptr; list = g_slist_next (list)) - { - g_free (list->data); - } - g_slist_free (table_list); -} - /* Check if the dbi connection is valid. If not attempt to re-establish it * Returns TRUE is there is a valid connection in the end or FALSE otherwise */ From c0a193c593d5e28d403373186e06a773ee397441 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 18 Jul 2016 09:49:41 -0700 Subject: [PATCH 25/63] Remove unused/never implemented QofBackend functions. Note that the QofQuery functions that sort-of used them are ifdefed out instead of deleted to serve as place-holders since we'll be bringing back backend querying later. --- src/backend/dbi/gnc-backend-dbi.cpp | 13 +------ .../sql/test/utest-gnc-backend-sql.cpp | 4 +- src/backend/xml/gnc-backend-xml.cpp | 9 ----- src/libqof/qof/qofbackend-p.h | 30 ++------------ src/libqof/qof/qofbackend.cpp | 11 +----- src/libqof/qof/qofquery.cpp | 12 ++++-- src/libqof/qof/qofsession.cpp | 10 +---- src/libqof/qof/test/test-qofsession-old.cpp | 39 ------------------- src/libqof/qof/test/test-qofsession.cpp | 6 --- 9 files changed, 18 insertions(+), 116 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index e396559e50..ebb0fc572f 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -1766,22 +1766,11 @@ init_sql_backend (GncDbiBackend* dbi_be) be->commit = gnc_dbi_commit_edit; be->rollback = gnc_dbi_rollback_edit; - /* The gda backend will not be multi-user (for now)... */ - be->events_pending = nullptr; - be->process_events = nullptr; - /* The SQL/DBI backend doesn't need to be synced until it is * configured for multiuser access. */ be->sync = gnc_dbi_safe_sync_all; be->safe_sync = gnc_dbi_safe_sync_all; - -// be->compile_query = gnc_sql_compile_query; -// be->run_query = gnc_sql_run_query; -// be->free_query = gnc_sql_free_query; - be->compile_query = nullptr; - be->run_query = nullptr; - be->free_query = nullptr; - + /* CoA Export function not implemented for the SQL backend. */ be->export_fn = nullptr; gnc_sql_init (&dbi_be->sql_be); diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index 3dc7ea4959..f418c1990a 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -634,8 +634,8 @@ test_gnc_sql_convert_timespec_to_string () { GncSqlBackend be = {{ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, ERR_BACKEND_NO_ERR, nullptr, 0, nullptr, nullptr + nullptr, nullptr, nullptr, nullptr, ERR_BACKEND_NO_ERR, nullptr, + 0, nullptr }, nullptr, nullptr, FALSE, FALSE, FALSE, 0, 0, nullptr, "%4d-%02d-%02d %02d:%02d:%02d" diff --git a/src/backend/xml/gnc-backend-xml.cpp b/src/backend/xml/gnc-backend-xml.cpp index 3fc61e149d..40ab3cfa35 100644 --- a/src/backend/xml/gnc-backend-xml.cpp +++ b/src/backend/xml/gnc-backend-xml.cpp @@ -1243,15 +1243,6 @@ QofXmlBackendProvider::create_backend(void) be->commit = NULL; be->rollback = xml_rollback_edit; - /* The file backend always loads all data ... */ - be->compile_query = NULL; - be->free_query = NULL; - be->run_query = NULL; - - /* The file backend will never be multi-user... */ - be->events_pending = NULL; - be->process_events = NULL; - be->sync = xml_sync_all; be->export_fn = gnc_xml_be_write_accounts_to_file; diff --git a/src/libqof/qof/qofbackend-p.h b/src/libqof/qof/qofbackend-p.h index d8f0a6804c..9eb0e6545f 100644 --- a/src/libqof/qof/qofbackend-p.h +++ b/src/libqof/qof/qofbackend-p.h @@ -259,16 +259,12 @@ struct QofBackend_s void (*commit) (QofBackend *, QofInstance *); void (*rollback) (QofBackend *, QofInstance *); - gpointer (*compile_query) (QofBackend *, QofQuery *); - void (*free_query) (QofBackend *, gpointer); - void (*run_query) (QofBackend *, gpointer); - void (*sync) (QofBackend *, /*@ dependent @*/ QofBook *); void (*safe_sync) (QofBackend *, /*@ dependent @*/ QofBook *); - - gboolean (*events_pending) (QofBackend *); - gboolean (*process_events) (QofBackend *); - + /* This is implented only in the XML backend where it exports only a chart + * of accounts. + */ + void (*export_fn) (QofBackend *, QofBook *); QofBePercentageFunc percentage; QofBackendError last_err; @@ -279,24 +275,6 @@ struct QofBackend_s * This holds the filepath and communicates it to the frontends. */ char * fullpath; - - /** \deprecated price_lookup should be removed during the redesign - * of the SQL backend... prices can now be queried using - * the generic query mechanism. - * - * Note the correct signature for this call is - * void (*price_lookup) (QofBackend *, GNCPriceLookup *); - * we use gpointer to avoid an unwanted include file dependency. - */ - void (*price_lookup) (QofBackend *, gpointer); - - /** \deprecated Export should really _NOT_ be here, but is left here for now. - * I'm not sure where this should be going to. It should be - * removed ASAP. This is a temporary hack-around until period-closing - * is fully implemented. - */ - void (*export_fn) (QofBackend *, QofBook *); - }; #ifdef __cplusplus diff --git a/src/libqof/qof/qofbackend.cpp b/src/libqof/qof/qofbackend.cpp index 4076df50f1..6613feda6b 100644 --- a/src/libqof/qof/qofbackend.cpp +++ b/src/libqof/qof/qofbackend.cpp @@ -150,24 +150,15 @@ qof_backend_init(QofBackend *be) be->commit = NULL; be->rollback = NULL; - be->compile_query = NULL; - be->free_query = NULL; - be->run_query = NULL; - be->sync = NULL; be->safe_sync = NULL; - be->events_pending = NULL; - be->process_events = NULL; + be->export_fn = NULL; be->last_err = ERR_BACKEND_NO_ERR; if (be->error_msg) g_free (be->error_msg); be->error_msg = NULL; be->percentage = NULL; - - /* to be removed */ - be->price_lookup = NULL; - be->export_fn = NULL; } void diff --git a/src/libqof/qof/qofquery.cpp b/src/libqof/qof/qofquery.cpp index 1129971763..c6cad34a66 100644 --- a/src/libqof/qof/qofquery.cpp +++ b/src/libqof/qof/qofquery.cpp @@ -548,7 +548,7 @@ static void compile_terms (QofQuery *q) compile_sort (&(q->tertiary_sort), q->search_for); q->defaultSort = qof_class_get_default_sort (q->search_for); - +#ifdef QOF_BACKEND_QUERY /* Now compile the backend instances */ for (node = q->books; node; node = node->next) { @@ -561,7 +561,9 @@ static void compile_terms (QofQuery *q) if (result) g_hash_table_insert (q->be_compiled, book, result); } + } +#endif LEAVE (" query=%p", q); } @@ -621,12 +623,13 @@ static GList * merge_books (GList *l1, GList *l2) static gboolean query_free_compiled (gpointer key, gpointer value, gpointer not_used) { +#ifdef QOF_BACKEND_QUERY QofBook* book = static_cast(key); QofBackend* be = book->backend; if (be && be->free_query) (be->free_query)(be, value); - +#endif return TRUE; } @@ -822,9 +825,10 @@ static void qof_query_run_cb(QofQueryCB* qcb, gpointer cb_arg) for (node = qcb->query->books; node; node = node->next) { QofBook* book = static_cast(node->data); +#ifdef QOF_BACKEND_QUERY QofBackend* be = book->backend; - /* run the query in the backend */ + if (be) { gpointer compiled_query = g_hash_table_lookup (qcb->query->be_compiled, @@ -835,7 +839,7 @@ static void qof_query_run_cb(QofQueryCB* qcb, gpointer cb_arg) (be->run_query) (be, compiled_query); } } - +#endif /* And then iterate over all the objects */ qof_object_foreach (qcb->query->search_for, book, (QofInstanceForeachCB) check_item_cb, qcb); diff --git a/src/libqof/qof/qofsession.cpp b/src/libqof/qof/qofsession.cpp index d6f7d6e12a..cf9c31fa81 100644 --- a/src/libqof/qof/qofsession.cpp +++ b/src/libqof/qof/qofsession.cpp @@ -538,19 +538,13 @@ QofSessionImpl::swap_books (QofSessionImpl & other) noexcept bool QofSessionImpl::events_pending () const noexcept { - auto backend = qof_book_get_backend (m_book); - if (!backend) return false; - if (!backend->events_pending) return false; - return backend->events_pending (backend); + return false; } bool QofSessionImpl::process_events () const noexcept { - auto backend = qof_book_get_backend (m_book); - if (!backend) return false; - if (!backend->process_events) return false; - return backend->process_events (backend); + return false; } /* XXX This exports the list of accounts to a file. It does not diff --git a/src/libqof/qof/test/test-qofsession-old.cpp b/src/libqof/qof/test/test-qofsession-old.cpp index f61baaae16..0369c7abb4 100644 --- a/src/libqof/qof/test/test-qofsession-old.cpp +++ b/src/libqof/qof/test/test-qofsession-old.cpp @@ -681,44 +681,6 @@ mock_events_fn (QofBackend *be) return TRUE; } -static void -test_qof_session_events (Fixture *fixture, gconstpointer pData) -{ - QofBackend *be = NULL; - - g_test_message ("Test pending events null checks"); - g_assert (!qof_session_events_pending (NULL)); - g_assert (!qof_book_get_backend (qof_session_get_book (fixture->session))); - g_assert (!qof_session_events_pending (fixture->session)); - be = g_new0 (QofBackend, 1); - g_assert (be); - be->events_pending = NULL; - qof_book_set_backend (qof_session_get_book (fixture->session), be); - g_assert (!qof_session_events_pending (fixture->session)); - - g_test_message ("Test pending events callback"); - be->events_pending = mock_events_fn; - events_struct.called = FALSE; - events_struct.be = be; - g_assert (qof_session_events_pending (fixture->session)); - g_assert (events_struct.called); - - g_test_message ("Test process events null checks"); - g_assert (!qof_session_process_events (NULL)); - qof_book_set_backend (qof_session_get_book (fixture->session), NULL); - g_assert (!qof_session_process_events (fixture->session)); - be->process_events = NULL; - qof_book_set_backend (qof_session_get_book (fixture->session), be); - g_assert (!qof_session_process_events (fixture->session)); - - g_test_message ("Test process events callback"); - be->process_events = mock_events_fn; - events_struct.called = FALSE; - events_struct.be = be; - g_assert (qof_session_process_events (fixture->session)); - g_assert (events_struct.called); -} - static struct { QofBackend *be; @@ -854,7 +816,6 @@ test_suite_qofsession ( void ) GNC_TEST_ADD (suitename, "qof session end", Fixture, NULL, setup, test_qof_session_end, teardown); GNC_TEST_ADD (suitename, "qof session export", Fixture, NULL, setup, test_qof_session_export, teardown); GNC_TEST_ADD (suitename, "qof session swap data", Fixture, NULL, setup, test_qof_session_swap_data, teardown); - GNC_TEST_ADD (suitename, "qof session events", Fixture, NULL, setup, test_qof_session_events, teardown); GNC_TEST_ADD (suitename, "qof session data loaded", Fixture, NULL, setup, test_qof_session_data_loaded, teardown); GNC_TEST_ADD (suitename, "qof session get book", Fixture, NULL, setup, test_qof_session_get_book, teardown); GNC_TEST_ADD (suitename, "qof session get error", Fixture, NULL, setup, test_qof_session_get_error, teardown); diff --git a/src/libqof/qof/test/test-qofsession.cpp b/src/libqof/qof/test/test-qofsession.cpp index 0b5cd22e7b..7a30cde46e 100644 --- a/src/libqof/qof/test/test-qofsession.cpp +++ b/src/libqof/qof/test/test-qofsession.cpp @@ -77,14 +77,8 @@ QofBackend * test_backend_factory () ret->begin = nullptr; ret->commit = nullptr; ret->rollback = nullptr; - ret->compile_query = nullptr; - ret->free_query = nullptr; - ret->run_query = nullptr; - ret->events_pending = nullptr; - ret->process_events = nullptr; ret->percentage = nullptr; ret->config_count = 0; - ret->price_lookup = nullptr; return ret; } From ccbfb69cf1419e100c7b83c1f54b4b2c73024804 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 18 Jul 2016 10:31:20 -0700 Subject: [PATCH 26/63] Delete unused or duplicated member variables from GncSqlBackend & GncDbiBackend. --- src/backend/dbi/gnc-backend-dbi.cpp | 7 ++----- src/backend/dbi/gnc-backend-dbi.hpp | 9 --------- src/backend/sql/gnc-backend-sql.cpp | 6 ------ src/backend/sql/gnc-backend-sql.h | 2 -- src/backend/sql/test/utest-gnc-backend-sql.cpp | 2 +- 5 files changed, 3 insertions(+), 23 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index ebb0fc572f..8f559d99e9 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -1480,8 +1480,7 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) if (loadType == LOAD_TYPE_INITIAL_LOAD) { - g_assert (be->primary_book == nullptr); - be->primary_book = book; + g_assert (be->sql_be.book == nullptr); // Set up table version information gnc_sql_init_version_info (&be->sql_be); @@ -1677,7 +1676,7 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) g_return_if_fail (be != nullptr); g_return_if_fail (book != nullptr); - ENTER ("book=%p, primary=%p", book, be->primary_book); + ENTER ("book=%p, primary=%p", book, be->sql_be.book); dbname = dbi_conn_get_option (be->conn, "dbname"); auto table_list = conn->m_provider->get_table_list (conn->m_conn, dbname); if (!conn_table_operation (conn, table_list, backup)) @@ -1700,8 +1699,6 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) return; } } - be->is_pristine_db = TRUE; - be->primary_book = book; gnc_sql_sync_all (&be->sql_be, book); if (qof_backend_check_error (qbe)) diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index cba87329b9..d07fe26e75 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -82,16 +82,7 @@ struct GncDbiBackend dbi_conn conn; - QofBook* primary_book; /* The primary, main open book */ - gboolean loading; /* We are performing an initial load */ - gboolean in_query; - gboolean supports_transactions; - gboolean is_pristine_db; // Are we saving to a new pristine db? gboolean exists; // Does the database exist? - - gint obj_total; // Total # of objects (for percentage calculation) - gint operations_done; // Number of operations (save/load) done -// GHashTable* versions; // Version number for each table }; class GncDbiSqlConnection : public GncSqlConnection diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index be0338d6d6..f51a3a83da 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -450,12 +450,6 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) /* Save all contents */ be->book = book; - be->obj_total = 0; - be->obj_total += 1 + gnc_account_n_descendants (gnc_book_get_root_account ( - book)); - be->obj_total += gnc_book_count_transactions (book); - be->operations_done = 0; - is_ok = be->conn->begin_transaction (); // FIXME: should write the set of commodities that are used diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 334199dedc..0a79551227 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -73,8 +73,6 @@ struct GncSqlBackend gboolean loading; /**< We are performing an initial load */ gboolean in_query; /**< We are processing a query */ gboolean is_pristine_db; /**< Are we saving to a new pristine db? */ - gint obj_total; /**< Total # of objects (for percentage calculation) */ - gint operations_done; /**< Number of operations (save/load) done */ GHashTable* versions; /**< Version number for each table */ const gchar* timespec_format; /**< Format string for SQL for timespec values */ }; diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index f418c1990a..509af0e140 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -637,7 +637,7 @@ test_gnc_sql_convert_timespec_to_string () nullptr, nullptr, nullptr, nullptr, ERR_BACKEND_NO_ERR, nullptr, 0, nullptr }, - nullptr, nullptr, FALSE, FALSE, FALSE, 0, 0, nullptr, + nullptr, nullptr, FALSE, FALSE, FALSE, nullptr, "%4d-%02d-%02d %02d:%02d:%02d" }; const char* date[numtests] = {"1995-03-11 19:17:26", From 5823bf0d9ab327ce7725649f7fcc0a3d9f11f4b8 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 18 Jul 2016 15:01:55 -0700 Subject: [PATCH 27/63] Move GncDbiSqlConnection into a separate file. The declaration stays in gnc-backend-dbi.h because the dependencies are still a little too tangled to be able to separate it. --- src/backend/dbi/CMakeLists.txt | 2 +- src/backend/dbi/Makefile.am | 3 +- src/backend/dbi/gnc-backend-dbi.cpp | 380 +-------------------- src/backend/dbi/gnc-dbisqlconnection.cpp | 405 +++++++++++++++++++++++ src/backend/dbi/test/CMakeLists.txt | 1 + src/backend/dbi/test/Makefile.am | 1 + 6 files changed, 413 insertions(+), 379 deletions(-) create mode 100644 src/backend/dbi/gnc-dbisqlconnection.cpp diff --git a/src/backend/dbi/CMakeLists.txt b/src/backend/dbi/CMakeLists.txt index 711a65d810..be5fc155d5 100644 --- a/src/backend/dbi/CMakeLists.txt +++ b/src/backend/dbi/CMakeLists.txt @@ -5,7 +5,7 @@ ADD_SUBDIRECTORY(test) # Source file gncmod-backend-dbi.c does not appear to be use in Makefile.in, so not included here. SET (backend_dbi_SOURCES - gnc-backend-dbi.cpp + gnc-backend-dbi.cpp gnc-dbisqlconnection.cpp ) SET (backend_dbi_noinst_HEADERS gnc-backend-dbi.h gnc-backend-dbi.hpp diff --git a/src/backend/dbi/Makefile.am b/src/backend/dbi/Makefile.am index ac07b8d2e5..a2a2baaed2 100644 --- a/src/backend/dbi/Makefile.am +++ b/src/backend/dbi/Makefile.am @@ -21,7 +21,8 @@ AM_CPPFLAGS = \ ${WARN_CFLAGS} libgncmod_backend_dbi_la_SOURCES = \ - gnc-backend-dbi.cpp + gnc-backend-dbi.cpp \ + gnc-dbisqlconnection.cpp noinst_HEADERS = \ gnc-backend-dbi.h \ diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 8f559d99e9..087266f431 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -125,13 +125,8 @@ static gboolean gnc_dbi_lock_database (QofBackend *qbe, gboolean ignore_lock); static void gnc_dbi_unlock (QofBackend *qbe); static gboolean save_may_clobber_data (QofBackend* qbe); -static std::string create_index_ddl (const GncSqlConnection* conn, - const std::string& index_name, - const std::string& table_name, - const EntryVec& col_table); static GncDbiTestResult conn_test_dbi_library (dbi_conn conn); -#define DBI_MAX_CONN_ATTEMPTS 5 enum class DbType { DBI_SQLITE, @@ -170,57 +165,6 @@ public: }; /* ================================================================= */ - -/* Check if the dbi connection is valid. If not attempt to re-establish it - * Returns TRUE is there is a valid connection in the end or FALSE otherwise - */ -bool -GncDbiSqlConnection::verify () noexcept -{ - if (m_conn_ok) - return true; - - /* We attempt to connect only once here. The error function will - * automatically re-attempt up until DBI_MAX_CONN_ATTEMPTS time to connect - * if this call fails. After all these attempts, conn_ok will indicate if - * there is a valid connection or not. - */ - init_error (); - m_conn_ok = true; - (void)dbi_conn_connect (m_conn); - - return m_conn_ok; -} - -bool -GncDbiSqlConnection::retry_connection(const char* msg) - noexcept -{ - while (m_retry && m_error_repeat <= DBI_MAX_CONN_ATTEMPTS) - { - m_conn_ok = false; - if (dbi_conn_connect(m_conn) == 0) - { - init_error(); - m_conn_ok = true; - return true; - } -#ifdef G_OS_WIN32 - const guint backoff_msecs = 1; - Sleep (backoff_msecs * 2 << ++m_error_repeat); -#else - const guint backoff_usecs = 1000; - usleep (backoff_usecs * 2 << ++m_error_repeat); -#endif - PINFO ("DBI error: %s - Reconnecting...\n", msg); - - } - PERR ("DBI error: %s - Giving up after %d consecutive attempts.\n", msg, - DBI_MAX_CONN_ATTEMPTS); - m_conn_ok = false; - return false; -} - /* ================================================================= */ static void @@ -1103,10 +1047,8 @@ GncDbiProviderImpl::get_index_list (dbi_conn conn) template<> void GncDbiProviderImpl::drop_index (dbi_conn conn, const std::string& index) { - unsigned int sep{0}, count{0}; - while ((sep = index.find(' ', sep)) != std::string::npos) - ++count; - if (count != 1) + auto sep = index.find(' ', 0); + if (index.find(' ', sep + 1) != std::string::npos) { PWARN("Drop index error: invalid MySQL index format (

): %s", index.c_str()); @@ -1536,33 +1478,6 @@ save_may_clobber_data (QofBackend* qbe) return retval; } -dbi_result -GncDbiSqlConnection::table_manage_backup (const std::string& table_name, - TableOpType op) -{ - auto new_name = table_name + "_back"; - dbi_result result = nullptr; - switch (op) - { - case backup: - result = dbi_conn_queryf (m_conn, "ALTER TABLE %s RENAME TO %s", - table_name.c_str(), new_name.c_str()); - break; - case rollback: - result = dbi_conn_queryf (m_conn, - "ALTER TABLE %s RENAME TO %s", - new_name.c_str(), table_name.c_str()); - break; - case drop_backup: - result = dbi_conn_queryf (m_conn, "DROP TABLE %s", - new_name.c_str()); - break; - default: - break; - } - return result; -} - /** * Perform a specified SQL operation on every table in a * database. Possible operations are: @@ -2142,215 +2057,6 @@ GncDbiSqlResult::size() const noexcept } /* --------------------------------------------------------- */ -class GncDbiSqlStatement : public GncSqlStatement -{ -public: - GncDbiSqlStatement(const GncSqlConnection* conn, const std::string& sql) : - m_conn{conn}, m_sql {sql} {} - ~GncDbiSqlStatement() {} - const char* to_sql() const override; - void add_where_cond(QofIdTypeConst, const PairVec&) override; - -private: - const GncSqlConnection* m_conn; - std::string m_sql; -}; - - -const char* -GncDbiSqlStatement::to_sql() const -{ - return m_sql.c_str(); -} - -void -GncDbiSqlStatement::add_where_cond(QofIdTypeConst type_name, - const PairVec& col_values) -{ - m_sql += " WHERE "; - for (auto colpair : col_values) - { - if (colpair != *col_values.begin()) - m_sql += " AND "; - m_sql += colpair.first + " = " + - m_conn->quote_string (colpair.second.c_str()); - } -} - -/* --------------------------------------------------------- */ -GncSqlResultPtr -GncDbiSqlConnection::execute_select_statement (const GncSqlStatementPtr& stmt) - noexcept -{ - dbi_result result; - - DEBUG ("SQL: %s\n", stmt->to_sql()); - gnc_push_locale (LC_NUMERIC, "C"); - do - { - init_error (); - result = dbi_conn_query (m_conn, stmt->to_sql()); - } - while (m_retry); - if (result == nullptr) - PERR ("Error executing SQL %s\n", stmt->to_sql()); - gnc_pop_locale (LC_NUMERIC); - return GncSqlResultPtr(new GncDbiSqlResult (this, result)); -} - -int -GncDbiSqlConnection::execute_nonselect_statement (const GncSqlStatementPtr& stmt) - noexcept -{ - dbi_result result; - - DEBUG ("SQL: %s\n", stmt->to_sql()); - do - { - init_error (); - result = dbi_conn_query (m_conn, stmt->to_sql()); - } - while (m_retry); - if (result == nullptr && m_last_error) - { - PERR ("Error executing SQL %s\n", stmt->to_sql()); - return -1; - } - if (!result) - return 0; - auto num_rows = (gint)dbi_result_get_numrows_affected (result); - auto status = dbi_result_free (result); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - return num_rows; -} - -GncSqlStatementPtr -GncDbiSqlConnection::create_statement_from_sql (const std::string& sql) - const noexcept -{ - return std::unique_ptr{new GncDbiSqlStatement (this, sql)}; -} - -bool -GncDbiSqlConnection::does_table_exist (const std::string& table_name) - const noexcept -{ - auto dbname = dbi_conn_get_option (m_conn, "dbname"); - auto tables = dbi_conn_get_table_list (m_conn, dbname, table_name.c_str()); - auto nTables = dbi_result_get_numrows (tables); - auto status = dbi_result_free (tables); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - - return nTables == 1; -} - -bool -GncDbiSqlConnection::begin_transaction () noexcept -{ - dbi_result result; - - DEBUG ("BEGIN\n"); - - if (!verify ()) - { - PERR ("gnc_dbi_verify_conn() failed\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - return FALSE; - } - - do - { - init_error (); - result = dbi_conn_queryf (m_conn, "BEGIN"); - } - while (m_retry); - - auto success = (result != nullptr); - auto status = dbi_result_free (result); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - if (!success) - { - PERR ("BEGIN transaction failed()\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - - return success; -} - -bool -GncDbiSqlConnection::rollback_transaction () const noexcept -{ - DEBUG ("ROLLBACK\n"); - const char* command = "ROLLBACK"; - auto result = dbi_conn_query (m_conn, command); - auto success = (result != nullptr); - - auto status = dbi_result_free (result); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - if (!success) - { - PERR ("Error in conn_rollback_transaction()\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - - return success; -} - -bool -GncDbiSqlConnection::commit_transaction () const noexcept -{ - DEBUG ("COMMIT\n"); - auto result = dbi_conn_queryf (m_conn, "COMMIT"); - auto success = (result != nullptr); - - auto status = dbi_result_free (result); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - if (!success) - { - PERR ("Error in conn_commit_transaction()\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - - return success; -} - -static std::string -create_index_ddl (const GncSqlConnection* conn, const std::string& index_name, - const std::string& table_name, const EntryVec& col_table) -{ - std::string ddl; - ddl += "CREATE INDEX " + index_name + " ON " + table_name + "("; - for (auto const table_row : col_table) - { - if (table_row != *col_table.begin()) - { - ddl =+ ", "; - } - ddl += table_row->name(); - } - ddl += ")"; - return ddl; -} std::string add_columns_ddl(const GncSqlConnection* conn, @@ -2482,7 +2188,7 @@ GncDbiProviderImpl::append_col_def (std::string& ddl, ddl += info.m_name + " " + type_name; if (info.m_size != 0 && info.m_type == BCT_STRING) { - ddl += std::to_string(info.m_size); + ddl += "(" + std::to_string(info.m_size) + ")"; } if (info.m_unicode) { @@ -2561,86 +2267,6 @@ GncDbiProviderImpl::append_col_def (std::string& ddl, } } -bool -GncDbiSqlConnection::create_table (const std::string& table_name, - const ColVec& info_vec) const noexcept -{ - auto ddl = m_provider->create_table_ddl(this, table_name, info_vec); - if (ddl.empty()) - return false; - - DEBUG ("SQL: %s\n", ddl.c_str()); - auto result = dbi_conn_query (m_conn, ddl.c_str()); - auto status = dbi_result_free (result); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - - return true; -} - -bool -GncDbiSqlConnection::create_index(const std::string& index_name, - const std::string& table_name, - const EntryVec& col_table) const noexcept -{ - auto ddl = create_index_ddl (this, index_name, table_name, col_table); - if (ddl.empty()) - return false; - DEBUG ("SQL: %s\n", ddl.c_str()); - auto result = dbi_conn_query (m_conn, ddl.c_str()); - auto status = dbi_result_free (result); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - - return true; -} - -bool -GncDbiSqlConnection::add_columns_to_table(const std::string& table_name, - const ColVec& info_vec) - const noexcept -{ - auto ddl = add_columns_ddl(this, table_name, info_vec); - if (ddl.empty()) - return false; - - DEBUG ("SQL: %s\n", ddl.c_str()); - auto result = dbi_conn_query (m_conn, ddl.c_str()); - auto status = dbi_result_free (result); - if (status < 0) - { - PERR( "Error in dbi_result_free() result\n" ); - qof_backend_set_error(m_qbe, ERR_BACKEND_SERVER_ERR ); - } - - return true; -} - -std::string -GncDbiSqlConnection::quote_string (const std::string& unquoted_str) - const noexcept -{ - gchar* quoted_str; - size_t size; - - size = dbi_conn_quote_string_copy (m_conn, unquoted_str.c_str(), - "ed_str); - if (size != 0) - { - return std::string{quoted_str}; - } - else - { - return std::string{""}; - } -} - static std::vector conn_get_table_list (dbi_conn conn, const std::string& dbname) { diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp new file mode 100644 index 0000000000..e95e26feb4 --- /dev/null +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -0,0 +1,405 @@ +/******************************************************************** + * gnc-dbisqlconnection.cpp: Encapsulate libdbi dbi_conn * + * * + * Copyright 2016 John Ralls * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ + +#include +extern "C" +{ +#include +#include +#include +} +#include "gnc-backend-dbi.hpp" + +static QofLogModule log_module = G_LOG_DOMAIN; + +static const unsigned int DBI_MAX_CONN_ATTEMPTS = 5; + + +/* --------------------------------------------------------- */ +class GncDbiSqlStatement : public GncSqlStatement +{ +public: + GncDbiSqlStatement(const GncSqlConnection* conn, const std::string& sql) : + m_conn{conn}, m_sql {sql} {} + ~GncDbiSqlStatement() {} + const char* to_sql() const override; + void add_where_cond(QofIdTypeConst, const PairVec&) override; + +private: + const GncSqlConnection* m_conn; + std::string m_sql; +}; + + +const char* +GncDbiSqlStatement::to_sql() const +{ + return m_sql.c_str(); +} + +void +GncDbiSqlStatement::add_where_cond(QofIdTypeConst type_name, + const PairVec& col_values) +{ + m_sql += " WHERE "; + for (auto colpair : col_values) + { + if (colpair != *col_values.begin()) + m_sql += " AND "; + m_sql += colpair.first + " = " + + m_conn->quote_string (colpair.second.c_str()); + } +} + +GncSqlResultPtr +GncDbiSqlConnection::execute_select_statement (const GncSqlStatementPtr& stmt) + noexcept +{ + dbi_result result; + + DEBUG ("SQL: %s\n", stmt->to_sql()); + gnc_push_locale (LC_NUMERIC, "C"); + do + { + init_error (); + result = dbi_conn_query (m_conn, stmt->to_sql()); + } + while (m_retry); + if (result == nullptr) + PERR ("Error executing SQL %s\n", stmt->to_sql()); + gnc_pop_locale (LC_NUMERIC); + return GncSqlResultPtr(new GncDbiSqlResult (this, result)); +} + +int +GncDbiSqlConnection::execute_nonselect_statement (const GncSqlStatementPtr& stmt) + noexcept +{ + dbi_result result; + + DEBUG ("SQL: %s\n", stmt->to_sql()); + do + { + init_error (); + result = dbi_conn_query (m_conn, stmt->to_sql()); + } + while (m_retry); + if (result == nullptr && m_last_error) + { + PERR ("Error executing SQL %s\n", stmt->to_sql()); + return -1; + } + if (!result) + return 0; + auto num_rows = (gint)dbi_result_get_numrows_affected (result); + auto status = dbi_result_free (result); + if (status < 0) + { + PERR ("Error in dbi_result_free() result\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + } + return num_rows; +} + +GncSqlStatementPtr +GncDbiSqlConnection::create_statement_from_sql (const std::string& sql) + const noexcept +{ + return std::unique_ptr{new GncDbiSqlStatement (this, sql)}; +} + +bool +GncDbiSqlConnection::does_table_exist (const std::string& table_name) + const noexcept +{ + auto dbname = dbi_conn_get_option (m_conn, "dbname"); + auto tables = dbi_conn_get_table_list (m_conn, dbname, table_name.c_str()); + auto nTables = dbi_result_get_numrows (tables); + auto status = dbi_result_free (tables); + if (status < 0) + { + PERR ("Error in dbi_result_free() result\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + } + + return nTables == 1; +} + +bool +GncDbiSqlConnection::begin_transaction () noexcept +{ + dbi_result result; + + DEBUG ("BEGIN\n"); + + if (!verify ()) + { + PERR ("gnc_dbi_verify_conn() failed\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + return FALSE; + } + + do + { + init_error (); + result = dbi_conn_queryf (m_conn, "BEGIN"); + } + while (m_retry); + + auto success = (result != nullptr); + auto status = dbi_result_free (result); + if (status < 0) + { + PERR ("Error in dbi_result_free() result\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + } + if (!success) + { + PERR ("BEGIN transaction failed()\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + } + + return success; +} + +bool +GncDbiSqlConnection::rollback_transaction () const noexcept +{ + DEBUG ("ROLLBACK\n"); + const char* command = "ROLLBACK"; + auto result = dbi_conn_query (m_conn, command); + auto success = (result != nullptr); + + auto status = dbi_result_free (result); + if (status < 0) + { + PERR ("Error in dbi_result_free() result\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + } + if (!success) + { + PERR ("Error in conn_rollback_transaction()\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + } + + return success; +} + +bool +GncDbiSqlConnection::commit_transaction () const noexcept +{ + DEBUG ("COMMIT\n"); + auto result = dbi_conn_queryf (m_conn, "COMMIT"); + auto success = (result != nullptr); + + auto status = dbi_result_free (result); + if (status < 0) + { + PERR ("Error in dbi_result_free() result\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + } + if (!success) + { + PERR ("Error in conn_commit_transaction()\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + } + + return success; +} + + +bool +GncDbiSqlConnection::create_table (const std::string& table_name, + const ColVec& info_vec) const noexcept +{ + auto ddl = m_provider->create_table_ddl(this, table_name, info_vec); + if (ddl.empty()) + return false; + + DEBUG ("SQL: %s\n", ddl.c_str()); + auto result = dbi_conn_query (m_conn, ddl.c_str()); + auto status = dbi_result_free (result); + if (status < 0) + { + PERR ("Error in dbi_result_free() result\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + } + + return true; +} + +static std::string +create_index_ddl (const GncSqlConnection* conn, const std::string& index_name, + const std::string& table_name, const EntryVec& col_table) +{ + std::string ddl; + ddl += "CREATE INDEX " + index_name + " ON " + table_name + "("; + for (auto const table_row : col_table) + { + if (table_row != *col_table.begin()) + { + ddl =+ ", "; + } + ddl += table_row->name(); + } + ddl += ")"; + return ddl; +} + +bool +GncDbiSqlConnection::create_index(const std::string& index_name, + const std::string& table_name, + const EntryVec& col_table) const noexcept +{ + auto ddl = create_index_ddl (this, index_name, table_name, col_table); + if (ddl.empty()) + return false; + DEBUG ("SQL: %s\n", ddl.c_str()); + auto result = dbi_conn_query (m_conn, ddl.c_str()); + auto status = dbi_result_free (result); + if (status < 0) + { + PERR ("Error in dbi_result_free() result\n"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + } + + return true; +} + +bool +GncDbiSqlConnection::add_columns_to_table(const std::string& table_name, + const ColVec& info_vec) + const noexcept +{ + auto ddl = add_columns_ddl(this, table_name, info_vec); + if (ddl.empty()) + return false; + + DEBUG ("SQL: %s\n", ddl.c_str()); + auto result = dbi_conn_query (m_conn, ddl.c_str()); + auto status = dbi_result_free (result); + if (status < 0) + { + PERR( "Error in dbi_result_free() result\n" ); + qof_backend_set_error(m_qbe, ERR_BACKEND_SERVER_ERR ); + } + + return true; +} + +std::string +GncDbiSqlConnection::quote_string (const std::string& unquoted_str) + const noexcept +{ + gchar* quoted_str; + size_t size; + + size = dbi_conn_quote_string_copy (m_conn, unquoted_str.c_str(), + "ed_str); + if (size != 0) + { + return std::string{quoted_str}; + } + else + { + return std::string{""}; + } +} + +/* Check if the dbi connection is valid. If not attempt to re-establish it + * Returns TRUE is there is a valid connection in the end or FALSE otherwise + */ +bool +GncDbiSqlConnection::verify () noexcept +{ + if (m_conn_ok) + return true; + + /* We attempt to connect only once here. The error function will + * automatically re-attempt up until DBI_MAX_CONN_ATTEMPTS time to connect + * if this call fails. After all these attempts, conn_ok will indicate if + * there is a valid connection or not. + */ + init_error (); + m_conn_ok = true; + (void)dbi_conn_connect (m_conn); + + return m_conn_ok; +} + +bool +GncDbiSqlConnection::retry_connection(const char* msg) + noexcept +{ + while (m_retry && m_error_repeat <= DBI_MAX_CONN_ATTEMPTS) + { + m_conn_ok = false; + if (dbi_conn_connect(m_conn) == 0) + { + init_error(); + m_conn_ok = true; + return true; + } +#ifdef G_OS_WIN32 + const guint backoff_msecs = 1; + Sleep (backoff_msecs * 2 << ++m_error_repeat); +#else + const guint backoff_usecs = 1000; + usleep (backoff_usecs * 2 << ++m_error_repeat); +#endif + PINFO ("DBI error: %s - Reconnecting...\n", msg); + + } + PERR ("DBI error: %s - Giving up after %d consecutive attempts.\n", msg, + DBI_MAX_CONN_ATTEMPTS); + m_conn_ok = false; + return false; +} + + +dbi_result +GncDbiSqlConnection::table_manage_backup (const std::string& table_name, + TableOpType op) +{ + auto new_name = table_name + "_back"; + dbi_result result = nullptr; + switch (op) + { + case backup: + result = dbi_conn_queryf (m_conn, "ALTER TABLE %s RENAME TO %s", + table_name.c_str(), new_name.c_str()); + break; + case rollback: + result = dbi_conn_queryf (m_conn, + "ALTER TABLE %s RENAME TO %s", + new_name.c_str(), table_name.c_str()); + break; + case drop_backup: + result = dbi_conn_queryf (m_conn, "DROP TABLE %s", + new_name.c_str()); + break; + default: + break; + } + return result; +} diff --git a/src/backend/dbi/test/CMakeLists.txt b/src/backend/dbi/test/CMakeLists.txt index 11a6bfe2d6..cc09d9dfe0 100644 --- a/src/backend/dbi/test/CMakeLists.txt +++ b/src/backend/dbi/test/CMakeLists.txt @@ -19,6 +19,7 @@ SET(test_dbi_backend_SOURCES test-dbi-business-stuff.cpp test-dbi-stuff.cpp ../gnc-backend-dbi.cpp + ../gnc-dbisqlconnection.cpp ) # This test does not work on Win32 diff --git a/src/backend/dbi/test/Makefile.am b/src/backend/dbi/test/Makefile.am index ae2f057db8..cd6a5f44a4 100644 --- a/src/backend/dbi/test/Makefile.am +++ b/src/backend/dbi/test/Makefile.am @@ -61,6 +61,7 @@ test_backend_dbi_SOURCES = \ test-backend-dbi-basic.cpp \ test-dbi-stuff.cpp \ test-dbi-business-stuff.cpp \ + ../gnc-dbisqlconnection.cpp \ ../gnc-backend-dbi.cpp test_backend_dbi_CPPFLAGS = \ From 583c951adcab34f74447b41e5f9a886ba053bc15 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 18 Jul 2016 15:04:41 -0700 Subject: [PATCH 28/63] Use the right include delineators, it's not in the current source dir. --- src/backend/dbi/gnc-backend-dbi.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index d07fe26e75..c3c2f1237f 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -26,7 +26,7 @@ extern "C" { #include } -#include "gnc-backend-sql.h" +#include /** * Options to conn_table_operation From e0d5cc5b0bb0020e9f61eca12de425028a2679fc Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 18 Jul 2016 15:11:35 -0700 Subject: [PATCH 29/63] New function GncSqlConnection::dberror(). GncDbiSqlResult::dberror() just calls it instead of retrieving the dbi_conn to call dbi_conn_error() itself. --- src/backend/dbi/gnc-backend-dbi.cpp | 6 ------ src/backend/dbi/gnc-backend-dbi.hpp | 4 +++- src/backend/sql/gnc-backend-sql.h | 4 ++++ src/backend/sql/test/utest-gnc-backend-sql.cpp | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 087266f431..13dc291fbf 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -2044,12 +2044,6 @@ GncDbiSqlResult::begin() return m_sentinel; } -int -GncDbiSqlResult::dberror() -{ - return dbi_conn_error(m_conn->conn(), nullptr); -} - uint64_t GncDbiSqlResult::size() const noexcept { diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index c3c2f1237f..a357bf0b71 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -109,6 +109,8 @@ public: bool add_columns_to_table (const std::string&, const ColVec&) const noexcept override; std::string quote_string (const std::string&) const noexcept override; + int dberror() const noexcept override { + return dbi_conn_error(m_conn, nullptr); } QofBackend* qbe () const noexcept { return m_qbe; } dbi_conn conn() const noexcept { return m_conn; } GncDbiProvider* provider() { return m_provider; } @@ -181,8 +183,8 @@ public: m_conn{conn}, m_dbi_result{result}, m_iter{this}, m_row{&m_iter}, m_sentinel{nullptr} {} ~GncDbiSqlResult(); - int dberror(); uint64_t size() const noexcept; + int dberror() { return m_conn->dberror(); } GncSqlRow& begin(); GncSqlRow& end() { return m_sentinel; } protected: diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 0a79551227..734cbb7e02 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -188,6 +188,10 @@ public: const noexcept = 0; virtual std::string quote_string (const std::string&) const noexcept = 0; + /** Get the connection error value. + * If not 0 will normally be meaningless outside of implementation code. + */ + virtual int dberror() const noexcept = 0; }; /** diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index 509af0e140..46bec746d5 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -104,6 +104,7 @@ public: const noexcept override { return false; } virtual std::string quote_string (const std::string& str) const noexcept override { return std::string{str}; } + int dberror() const noexcept override { return 0; } private: GncMockSqlResult m_result; }; From 97b6e3a6c6cf0c7389e120cae2d47e926293408c Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 18 Jul 2016 15:28:08 -0700 Subject: [PATCH 30/63] Pass ownership of the dbi_conn to GncDbiSqlConnection. --- src/backend/dbi/gnc-backend-dbi.cpp | 1 - src/backend/dbi/gnc-backend-dbi.hpp | 2 +- src/backend/dbi/gnc-dbisqlconnection.cpp | 10 ++++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 13dc291fbf..02c736bea7 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -1373,7 +1373,6 @@ gnc_dbi_session_end (QofBackend* be_start) if (be->conn != nullptr) { gnc_dbi_unlock (be_start); - dbi_conn_close (be->conn); be->conn = nullptr; } if (be->sql_be.conn != nullptr) diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index a357bf0b71..bc97d76b66 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -92,7 +92,7 @@ public: dbi_conn conn) : m_qbe{qbe}, m_conn{conn}, m_provider{provider}, m_conn_ok{true}, m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, m_retry{false} {} - ~GncDbiSqlConnection() override { delete m_provider; }; + ~GncDbiSqlConnection() override; GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr&) noexcept override; int execute_nonselect_statement (const GncSqlStatementPtr&) diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index e95e26feb4..aaa33fea10 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -71,6 +71,16 @@ GncDbiSqlStatement::add_where_cond(QofIdTypeConst type_name, } } +GncDbiSqlConnection::~GncDbiSqlConnection() +{ + if (m_conn) + { + dbi_conn_close(m_conn); + m_conn = nullptr; + } + delete m_provider; +} + GncSqlResultPtr GncDbiSqlConnection::execute_select_statement (const GncSqlStatementPtr& stmt) noexcept From d1063463163645ba3c55fdf72bd4c1807e34843b Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 18 Jul 2016 15:28:37 -0700 Subject: [PATCH 31/63] Minimally document GncDbiResult. --- src/backend/dbi/gnc-backend-dbi.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index bc97d76b66..bbfabb64e9 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -175,7 +175,9 @@ std::string add_columns_ddl(const GncSqlConnection* conn, /* external access required for tests */ std::string adjust_sql_options_string(const std::string&); - +/** + * An iterable wrapper for dbi_result; allows using C++11 range for. + */ class GncDbiSqlResult : public GncSqlResult { public: From 6f67e2dd1a52b5ddacab1178d93c1ae761197561 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Thu, 21 Jul 2016 16:21:59 -0700 Subject: [PATCH 32/63] Convert GncSqlBackend and GncDbiBackend into a class hierarchy. This is a rather complex change, because it also begins to separate the responsibilities of the backends and GncSqlConnection. --- src/backend/dbi/gnc-backend-dbi.cpp | 444 +++++------- src/backend/dbi/gnc-backend-dbi.hpp | 54 +- src/backend/dbi/gnc-dbisqlconnection.cpp | 92 ++- src/backend/dbi/gnc-dbisqlconnection.hpp | 29 + .../dbi/test/test-backend-dbi-basic.cpp | 28 +- src/backend/dbi/test/test-dbi-stuff.cpp | 5 +- src/backend/sql/gnc-account-sql.cpp | 14 +- src/backend/sql/gnc-backend-sql.cpp | 636 +++++++++--------- src/backend/sql/gnc-backend-sql.h | 71 +- src/backend/sql/gnc-bill-term-sql.cpp | 10 +- src/backend/sql/gnc-book-sql.cpp | 8 +- src/backend/sql/gnc-budget-sql.cpp | 12 +- src/backend/sql/gnc-commodity-sql.cpp | 8 +- src/backend/sql/gnc-customer-sql.cpp | 8 +- src/backend/sql/gnc-employee-sql.cpp | 10 +- src/backend/sql/gnc-entry-sql.cpp | 8 +- src/backend/sql/gnc-invoice-sql.cpp | 12 +- src/backend/sql/gnc-job-sql.cpp | 6 +- src/backend/sql/gnc-lots-sql.cpp | 8 +- src/backend/sql/gnc-order-sql.cpp | 8 +- src/backend/sql/gnc-owner-sql.cpp | 2 +- src/backend/sql/gnc-price-sql.cpp | 10 +- src/backend/sql/gnc-recurrence-sql.cpp | 4 +- src/backend/sql/gnc-schedxaction-sql.cpp | 6 +- src/backend/sql/gnc-slots-sql.cpp | 6 +- src/backend/sql/gnc-tax-table-sql.cpp | 16 +- src/backend/sql/gnc-transaction-sql.cpp | 34 +- src/backend/sql/gnc-vendor-sql.cpp | 8 +- .../sql/test/utest-gnc-backend-sql.cpp | 54 +- 29 files changed, 839 insertions(+), 772 deletions(-) create mode 100644 src/backend/dbi/gnc-dbisqlconnection.hpp diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 02c736bea7..c45288dbff 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -68,14 +68,6 @@ extern "C" #include "splint-defs.h" #endif -#ifdef G_OS_WIN32 -#include -#define GETPID() GetCurrentProcessId() -#else -#include -#include -#define GETPID() getpid() -#endif /* For direct access to dbi data structs, sadly needed for datetime */ #include @@ -104,7 +96,6 @@ static dbi_inst dbi_instance = nullptr; #define HAVE_LIBDBI_TO_LONGLONG 0 #endif -#define GNC_HOST_NAME_MAX 255 #define TRANSACTION_NAME "trans" static QofLogModule log_module = G_LOG_DOMAIN; @@ -118,11 +109,10 @@ static gchar lock_table[] = "gnclock"; #define PGSQL_DEFAULT_PORT 5432 #define SQLITE3_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" -#define MYSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" -#define PGSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d %02d%02d%02d" +#define MYSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" +#define PGSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d %02d%02d%02d" -static gboolean gnc_dbi_lock_database (QofBackend *qbe, gboolean ignore_lock); -static void gnc_dbi_unlock (QofBackend *qbe); +static gboolean gnc_dbi_lock_database (QofBackend*, dbi_conn, gboolean); static gboolean save_may_clobber_data (QofBackend* qbe); static GncDbiTestResult conn_test_dbi_library (dbi_conn conn); @@ -175,23 +165,21 @@ create_tables(const OBEEntry& entry, GncDbiBackend* be) std::tie(type, obe) = entry; g_return_if_fail(obe->is_version (GNC_SQL_BACKEND_VERSION)); - obe->create_tables (&be->sql_be); + obe->create_tables (be); } -static void +void sqlite3_error_fn (dbi_conn conn, void* user_data) { const gchar* msg; GncDbiBackend *be = static_cast(user_data); -/* FIXME: GncSqlConnection doesn't have the error calls so we have to dynamic_cast from the connection stored in GncSqlBackend. Yuck. */ - GncDbiSqlConnection *dbi_conn = - dynamic_cast(be->sql_be.conn); int errnum = dbi_conn_error (conn, &msg); PERR ("DBI error: %s\n", msg); - dbi_conn->set_error (ERR_BACKEND_MISC, 0, false); + if (be->connected()) + be->set_error (ERR_BACKEND_MISC, 0, false); } -static void +void gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, const gchar* book_id, gboolean ignore_lock, gboolean create, gboolean force) @@ -232,22 +220,18 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, goto exit; } - - if (be->conn != nullptr) - { - dbi_conn_close (be->conn); - } - + be->connect(nullptr); + dbi_conn conn; #if HAVE_LIBDBI_R if (dbi_instance) - be->conn = dbi_conn_new_r ("sqlite3", dbi_instance); + conn = dbi_conn_new_r ("sqlite3", dbi_instance); else PERR ("Attempt to connect with an uninitialized dbi_instance"); #else - be->conn = dbi_conn_new ("sqlite3"); + conn = dbi_conn_new ("sqlite3"); #endif - if (be->conn == nullptr) + if (conn == nullptr) { PERR ("Unable to create sqlite3 dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); @@ -256,30 +240,30 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, dirname = g_path_get_dirname (filepath); basename = g_path_get_basename (filepath); - dbi_conn_error_handler (be->conn, sqlite3_error_fn, be); + dbi_conn_error_handler (conn, sqlite3_error_fn, be); /* dbi-sqlite3 documentation says that sqlite3 doesn't take a "host" option */ - result = dbi_conn_set_option (be->conn, "host", "localhost"); + result = dbi_conn_set_option (conn, "host", "localhost"); if (result < 0) { PERR ("Error setting 'host' option\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - result = dbi_conn_set_option (be->conn, "dbname", basename); + result = dbi_conn_set_option (conn, "dbname", basename); if (result < 0) { PERR ("Error setting 'dbname' option\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - result = dbi_conn_set_option (be->conn, "sqlite3_dbdir", dirname); + result = dbi_conn_set_option (conn, "sqlite3_dbdir", dirname); if (result < 0) { PERR ("Error setting 'sqlite3_dbdir' option\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - result = dbi_conn_connect (be->conn); + result = dbi_conn_connect (conn); if (result < 0) { @@ -288,7 +272,7 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, goto exit; } - dbi_test_result = conn_test_dbi_library (be->conn); + dbi_test_result = conn_test_dbi_library (conn); switch (dbi_test_result) { case GNC_DBI_PASS: @@ -311,27 +295,24 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, if (create && !file_exists) /* File didn't exist before, but it */ { /* does now, and we don't want to */ - dbi_conn_close (be->conn); /* leave it lying around. */ - be->conn = nullptr; + dbi_conn_close (conn); /* leave it lying around. */ + conn = nullptr; g_unlink (filepath); } msg = "Bad DBI Library"; goto exit; } - if (!gnc_dbi_lock_database (qbe, ignore_lock)) + if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) { qof_backend_set_error (qbe, ERR_BACKEND_LOCKED); msg = "Locked"; goto exit; } - if (be->sql_be.conn != nullptr) - { - delete (be->sql_be.conn); - } - be->sql_be.conn = new GncDbiSqlConnection (new GncDbiProviderImpl, - qbe, be->conn); - be->sql_be.timespec_format = SQLITE3_TIMESPEC_STR_FORMAT; + be->connect(nullptr); + be->connect( + new GncDbiSqlConnection (new GncDbiProviderImpl, + qbe, conn, lock_table)); /* We should now have a proper session set up. * Let's start logging */ @@ -378,8 +359,6 @@ static void mysql_error_fn (dbi_conn conn, void* user_data) { GncDbiBackend* be = (GncDbiBackend*)user_data; - GncDbiSqlConnection* dbi_conn = - dynamic_cast(be->sql_be.conn); const char* msg; auto err_num = dbi_conn_error (conn, &msg); @@ -394,7 +373,7 @@ mysql_error_fn (dbi_conn conn, void* user_data) if (err_num == 1049) // Database doesn't exist { PINFO ("DBI error: %s\n", msg); - be->exists = FALSE; + be->set_exists(false); return; } @@ -402,7 +381,7 @@ mysql_error_fn (dbi_conn conn, void* user_data) * has been initialized. So let's assert it exits here, otherwise * simply return. */ - if (!dbi_conn) + if (!be->connected()) { PINFO ("DBI error: %s\n", msg); PINFO ("Note: GbcDbiSqlConnection not yet initialized. Skipping further error processing."); @@ -413,20 +392,18 @@ mysql_error_fn (dbi_conn conn, void* user_data) if (err_num == 2006) // Server has gone away { PINFO ("DBI error: %s - Reconnecting...\n", msg); - if (dbi_conn) - dbi_conn->set_error (ERR_BACKEND_CONN_LOST, 1, true); - dbi_conn->retry_connection(msg); + be->set_error (ERR_BACKEND_CONN_LOST, 1, true); + be->retry_connection(msg); } else if (err_num == 2003) // Unable to connect { - dbi_conn->set_error (ERR_BACKEND_CANT_CONNECT, 1, true); - dbi_conn->retry_connection (msg); + be->set_error (ERR_BACKEND_CANT_CONNECT, 1, true); + be->retry_connection (msg); } else // Any other error { PERR ("DBI error: %s\n", msg); - if (dbi_conn) - dbi_conn->set_error (ERR_BACKEND_MISC, 0, FALSE); + be->set_error (ERR_BACKEND_MISC, 0, FALSE); } } @@ -496,17 +473,17 @@ set_standard_connection_options (QofBackend* qbe, dbi_conn conn, return TRUE; } - +/* FIXME: Move to GncDbiSqlConnection. */ static gboolean -gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) +gnc_dbi_lock_database (QofBackend* qbe, dbi_conn conn, gboolean ignore_lock) { GncDbiBackend* qe = (GncDbiBackend*)qbe; - dbi_conn dcon = qe->conn; + dbi_result result; - const gchar* dbname = dbi_conn_get_option (dcon, "dbname"); + const gchar* dbname = dbi_conn_get_option (conn, "dbname"); /* Create the table if it doesn't exist */ - result = dbi_conn_get_table_list (dcon, dbname, lock_table); + result = dbi_conn_get_table_list (conn, dbname, lock_table); if (! (result && dbi_result_get_numrows (result))) { if (result) @@ -514,13 +491,13 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) dbi_result_free (result); result = nullptr; } - result = dbi_conn_queryf (dcon, + result = dbi_conn_queryf (conn, "CREATE TABLE %s ( Hostname varchar(%d), PID int )", lock_table, GNC_HOST_NAME_MAX); - if (dbi_conn_error (dcon, nullptr)) + if (dbi_conn_error (conn, nullptr)) { const gchar* errstr; - dbi_conn_error (dcon, &errstr); + dbi_conn_error (conn, &errstr); PERR ("Error %s creating lock table", errstr); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); if (result) @@ -543,7 +520,7 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) } /* Protect everything with a single transaction to prevent races */ - if ((result = dbi_conn_query (dcon, "BEGIN"))) + if ((result = dbi_conn_query (conn, "BEGIN"))) { /* Check for an existing entry; delete it if ignore_lock is true, otherwise fail */ gchar hostname[ GNC_HOST_NAME_MAX + 1 ]; @@ -552,7 +529,7 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) dbi_result_free (result); result = nullptr; } - result = dbi_conn_queryf (dcon, "SELECT * FROM %s", lock_table); + result = dbi_conn_queryf (conn, "SELECT * FROM %s", lock_table); if (result && dbi_result_get_numrows (result)) { dbi_result_free (result); @@ -561,15 +538,15 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) { qof_backend_set_error (qbe, ERR_BACKEND_LOCKED); /* FIXME: After enhancing the qof_backend_error mechanism, report in the dialog what is the hostname of the machine holding the lock. */ - dbi_conn_query (dcon, "ROLLBACK"); + dbi_conn_query (conn, "ROLLBACK"); return FALSE; } - result = dbi_conn_queryf (dcon, "DELETE FROM %s", lock_table); + result = dbi_conn_queryf (conn, "DELETE FROM %s", lock_table); if (!result) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); qof_backend_set_message (qbe, "Failed to delete lock record"); - result = dbi_conn_query (dcon, "ROLLBACK"); + result = dbi_conn_query (conn, "ROLLBACK"); if (result) { dbi_result_free (result); @@ -586,14 +563,14 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) /* Add an entry and commit the transaction */ memset (hostname, 0, sizeof (hostname)); gethostname (hostname, GNC_HOST_NAME_MAX); - result = dbi_conn_queryf (dcon, + result = dbi_conn_queryf (conn, "INSERT INTO %s VALUES ('%s', '%d')", lock_table, hostname, (int)GETPID ()); if (!result) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); qof_backend_set_message (qbe, "Failed to create lock record"); - result = dbi_conn_query (dcon, "ROLLBACK"); + result = dbi_conn_query (conn, "ROLLBACK"); if (result) { dbi_result_free (result); @@ -606,7 +583,7 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) dbi_result_free (result); result = nullptr; } - result = dbi_conn_query (dcon, "COMMIT"); + result = dbi_conn_query (conn, "COMMIT"); if (result) { dbi_result_free (result); @@ -624,96 +601,6 @@ gnc_dbi_lock_database (QofBackend* qbe, gboolean ignore_lock) } return FALSE; } -static void -gnc_dbi_unlock (QofBackend* qbe) -{ - GncDbiBackend* qe = (GncDbiBackend*)qbe; - dbi_conn dcon = qe->conn; - dbi_result result; - const gchar* dbname = nullptr; - - g_return_if_fail (dcon != nullptr); - g_return_if_fail (dbi_conn_error (dcon, nullptr) == 0); - - dbname = dbi_conn_get_option (dcon, "dbname"); - /* Check if the lock table exists */ - g_return_if_fail (dbname != nullptr); - result = dbi_conn_get_table_list (dcon, dbname, lock_table); - if (! (result && dbi_result_get_numrows (result))) - { - if (result) - { - dbi_result_free (result); - result = nullptr; - } - PWARN ("No lock table in database, so not unlocking it."); - return; - } - dbi_result_free (result); - - result = dbi_conn_query (dcon, "BEGIN"); - if (result) - { - /* Delete the entry if it's our hostname and PID */ - gchar hostname[ GNC_HOST_NAME_MAX + 1 ]; - - dbi_result_free (result); - result = nullptr; - memset (hostname, 0, sizeof (hostname)); - gethostname (hostname, GNC_HOST_NAME_MAX); - result = dbi_conn_queryf (dcon, - "SELECT * FROM %s WHERE Hostname = '%s' AND PID = '%d'", lock_table, hostname, - (int)GETPID ()); - if (result && dbi_result_get_numrows (result)) - { - if (result) - { - dbi_result_free (result); - result = nullptr; - } - result = dbi_conn_queryf (dcon, "DELETE FROM %s", lock_table); - if (!result) - { - PERR ("Failed to delete the lock entry"); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - result = dbi_conn_query (dcon, "ROLLBACK"); - if (result) - { - dbi_result_free (result); - result = nullptr; - } - return; - } - else - { - dbi_result_free (result); - result = nullptr; - } - result = dbi_conn_query (dcon, "COMMIT"); - if (result) - { - dbi_result_free (result); - result = nullptr; - } - return; - } - result = dbi_conn_query (dcon, "ROLLBACK"); - if (result) - { - dbi_result_free (result); - result = nullptr; - } - PWARN ("There was no lock entry in the Lock table"); - return; - } - if (result) - { - dbi_result_free (result); - result = nullptr; - } - PWARN ("Unable to get a lock on LOCK, so failed to clear the lock entry."); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); -} #define SQL_OPTION_TO_REMOVE "NO_ZERO_DATE" @@ -815,36 +702,34 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, // Try to connect to the db. If it doesn't exist and the create // flag is TRUE, we'll need to connect to the 'mysql' db and execute the // CREATE DATABASE ddl statement there. - if (be->conn != nullptr) - { - dbi_conn_close (be->conn); - } + be->connect(nullptr); + dbi_conn conn; #if HAVE_LIBDBI_R if (dbi_instance) - be->conn = dbi_conn_new_r ("mysql", dbi_instance); + conn = dbi_conn_new_r ("mysql", dbi_instance); else PERR ("Attempt to connect with an uninitialized dbi_instance"); #else - be->conn = dbi_conn_new ("mysql"); + conn = dbi_conn_new ("mysql"); #endif - if (be->conn == nullptr) + if (conn == nullptr) { PERR ("Unable to create mysql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); goto exit; } - dbi_conn_error_handler (be->conn, mysql_error_fn, be); - if (!set_standard_connection_options (qbe, be->conn, host, portnum, dbname, + dbi_conn_error_handler (conn, mysql_error_fn, be); + if (!set_standard_connection_options (qbe, conn, host, portnum, dbname, username, password)) { goto exit; } - be->exists = TRUE; - result = dbi_conn_connect (be->conn); + be->set_exists(true); + result = dbi_conn_connect (conn); if (result == 0) { - adjust_sql_options (be->conn); - dbi_test_result = conn_test_dbi_library (be->conn); + adjust_sql_options (conn); + dbi_test_result = conn_test_dbi_library (conn); switch (dbi_test_result) { case GNC_DBI_PASS: @@ -873,12 +758,12 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, goto exit; } - success = gnc_dbi_lock_database (qbe, ignore_lock); + success = gnc_dbi_lock_database (qbe, conn, ignore_lock); } else { - if (be->exists) + if (be->exists()) { PERR ("Unable to connect to database '%s'\n", dbname); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); @@ -889,22 +774,23 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, if (create) { dbi_result dresult; - result = dbi_conn_set_option (be->conn, "dbname", "mysql"); + result = dbi_conn_set_option (conn, "dbname", "mysql"); if (result < 0) { PERR ("Error setting 'dbname' option\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - result = dbi_conn_connect (be->conn); + result = dbi_conn_connect (conn); if (result < 0) { PERR ("Unable to connect to 'mysql' database\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - adjust_sql_options (be->conn); - dresult = dbi_conn_queryf (be->conn, "CREATE DATABASE %s CHARACTER SET utf8", + adjust_sql_options (conn); + dresult = dbi_conn_queryf (conn, + "CREATE DATABASE %s CHARACTER SET utf8", dbname); if (dresult == nullptr) { @@ -912,39 +798,40 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - dbi_conn_close (be->conn); + dbi_conn_close (conn); + conn = nullptr; // Try again to connect to the db #if HAVE_LIBDBI_R if (dbi_instance) - be->conn = dbi_conn_new_r ("mysql", dbi_instance); + conn = dbi_conn_new_r ("mysql", dbi_instance); else PERR ("Attempt to connect with an uninitialized dbi_instance"); #else - be->conn = dbi_conn_new ("mysql"); + conn = dbi_conn_new ("mysql"); #endif - if (be->conn == nullptr) + if (conn == nullptr) { PERR ("Unable to create mysql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); goto exit; } - dbi_conn_error_handler (be->conn, mysql_error_fn, be); - if (!set_standard_connection_options (qbe, be->conn, host, 0, dbname, username, - password)) + dbi_conn_error_handler (conn, mysql_error_fn, be); + if (!set_standard_connection_options (qbe, conn, host, 0, dbname, + username, password)) { goto exit; } - result = dbi_conn_connect (be->conn); + result = dbi_conn_connect (conn); if (result < 0) { PERR ("Unable to create database '%s'\n", dbname); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - adjust_sql_options (be->conn); - dbi_test_result = conn_test_dbi_library (be->conn); + adjust_sql_options (conn); + dbi_test_result = conn_test_dbi_library (conn); switch (dbi_test_result) { case GNC_DBI_PASS: @@ -964,10 +851,10 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, } if (dbi_test_result != GNC_DBI_PASS) { - dbi_conn_queryf (be->conn, "DROP DATABASE %s", dbname); + dbi_conn_queryf (conn, "DROP DATABASE %s", dbname); goto exit; } - success = gnc_dbi_lock_database (qbe, ignore_lock); + success = gnc_dbi_lock_database (qbe, conn, ignore_lock); } else { @@ -979,15 +866,11 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, if (success) { dbi_result dresult; - - if (be->sql_be.conn != nullptr) - { - delete (be->sql_be.conn); - } - be->sql_be.conn = new GncDbiSqlConnection (new GncDbiProviderImpl, - qbe, be->conn); + be->connect(nullptr); + be->connect( + new GncDbiSqlConnection (new GncDbiProviderImpl, + qbe, conn, lock_table)); } - be->sql_be.timespec_format = MYSQL_TIMESPEC_STR_FORMAT; /* We should now have a proper session set up. * Let's start logging */ @@ -1066,8 +949,6 @@ static void pgsql_error_fn (dbi_conn conn, void* user_data) { GncDbiBackend* be = (GncDbiBackend*)user_data; - GncDbiSqlConnection* dbi_conn = - dynamic_cast(be->sql_be.conn); const gchar* msg; (void)dbi_conn_error (conn, &msg); @@ -1075,32 +956,32 @@ pgsql_error_fn (dbi_conn conn, void* user_data) g_str_has_suffix (msg, "does not exist\n")) { PINFO ("DBI error: %s\n", msg); - be->exists = FALSE; - dbi_conn->set_error (ERR_BACKEND_NO_SUCH_DB, 0, FALSE); + be->set_exists(false); + be->set_error (ERR_BACKEND_NO_SUCH_DB, 0, FALSE); } else if (g_strrstr (msg, "server closed the connection unexpectedly")) // Connection lost { - if (dbi_conn == nullptr) + if (!be->connected()) { PWARN ("DBI Error: Connection lost, connection pointer invalid"); return; } PINFO ("DBI error: %s - Reconnecting...\n", msg); - dbi_conn->set_error (ERR_BACKEND_CONN_LOST, 1, true); - dbi_conn->retry_connection(msg); + be->set_error (ERR_BACKEND_CONN_LOST, 1, true); + be->retry_connection(msg); } - else if (dbi_conn && + else if (be->connected() && (g_str_has_prefix (msg, "connection pointer is NULL") || g_str_has_prefix (msg, "could not connect to server"))) // No connection { - dbi_conn->set_error(ERR_BACKEND_CANT_CONNECT, 1, true); - dbi_conn->retry_connection (msg); + be->set_error(ERR_BACKEND_CANT_CONNECT, 1, true); + be->retry_connection (msg); } else { PERR ("DBI error: %s\n", msg); - dbi_conn->set_error (ERR_BACKEND_MISC, 0, false); + be->set_error (ERR_BACKEND_MISC, 0, false); } } @@ -1144,37 +1025,34 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, // Try to connect to the db. If it doesn't exist and the create // flag is TRUE, we'll need to connect to the 'postgres' db and execute the // CREATE DATABASE ddl statement there. - if (be->conn != nullptr) - { - dbi_conn_close (be->conn); - } - + be->connect(nullptr); + dbi_conn conn; #if HAVE_LIBDBI_R if (dbi_instance) - be->conn = dbi_conn_new_r ("pgsql", dbi_instance); + conn = dbi_conn_new_r ("pgsql", dbi_instance); else PERR ("Attempt to connect with an uninitialized dbi_instance"); #else - be->conn = dbi_conn_new ("pgsql"); + conn = dbi_conn_new ("pgsql"); #endif - if (be->conn == nullptr) + if (conn == nullptr) { PERR ("Unable to create pgsql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); goto exit; } - dbi_conn_error_handler (be->conn, pgsql_error_fn, be); - if (!set_standard_connection_options (qbe, be->conn, host, portnum, dbnamelc, + dbi_conn_error_handler (conn, pgsql_error_fn, be); + if (!set_standard_connection_options (qbe, conn, host, portnum, dbnamelc, username, password)) { goto exit; } - be->exists = TRUE; - result = dbi_conn_connect (be->conn); + be->set_exists(true); + result = dbi_conn_connect (conn); if (result == 0) { - dbi_test_result = conn_test_dbi_library (be->conn); + dbi_test_result = conn_test_dbi_library (conn); switch (dbi_test_result) { case GNC_DBI_PASS: @@ -1203,12 +1081,12 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, goto exit; } - success = gnc_dbi_lock_database (qbe, ignore_lock); + success = gnc_dbi_lock_database (qbe, conn, ignore_lock); } else { - if (be->exists) + if (be->exists()) { PERR ("Unable to connect to database '%s'\n", dbname); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); @@ -1219,21 +1097,21 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, if (create) { dbi_result dresult; - result = dbi_conn_set_option (be->conn, "dbname", "postgres"); + result = dbi_conn_set_option (conn, "dbname", "postgres"); if (result < 0) { PERR ("Error setting 'dbname' option\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - result = dbi_conn_connect (be->conn); + result = dbi_conn_connect (conn); if (result < 0) { PERR ("Unable to connect to 'postgres' database\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - dresult = dbi_conn_queryf (be->conn, + dresult = dbi_conn_queryf (conn, "CREATE DATABASE %s WITH TEMPLATE template0 ENCODING 'UTF8'", dbnamelc); if (dresult == nullptr) { @@ -1241,40 +1119,41 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - dbi_conn_queryf (be->conn, + dbi_conn_queryf (conn, "ALTER DATABASE %s SET standard_conforming_strings TO on", dbnamelc); - dbi_conn_close (be->conn); + dbi_conn_close (conn); // Try again to connect to the db #if HAVE_LIBDBI_R if (dbi_instance) - be->conn = dbi_conn_new_r ("pgsql", dbi_instance); + conn = dbi_conn_new_r ("pgsql", dbi_instance); else PERR ("Attempt to connect with an uninitialized dbi_instance"); #else - be->conn = dbi_conn_new ("pgsql"); + conn = dbi_conn_new ("pgsql"); #endif - if (be->conn == nullptr) + if (conn == nullptr) { PERR ("Unable to create pgsql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); goto exit; } - dbi_conn_error_handler (be->conn, pgsql_error_fn, be); - if (!set_standard_connection_options (qbe, be->conn, host, PGSQL_DEFAULT_PORT, + dbi_conn_error_handler (conn, pgsql_error_fn, be); + if (!set_standard_connection_options (qbe, conn, host, + PGSQL_DEFAULT_PORT, dbnamelc, username, password)) { goto exit; } - result = dbi_conn_connect (be->conn); + result = dbi_conn_connect (conn); if (result < 0) { PERR ("Unable to create database '%s'\n", dbname); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - dbi_test_result = conn_test_dbi_library (be->conn); + dbi_test_result = conn_test_dbi_library (conn); switch (dbi_test_result) { case GNC_DBI_PASS: @@ -1294,11 +1173,11 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, } if (GNC_DBI_PASS != dbi_test_result) { - dbi_conn_select_db (be->conn, "template1"); - dbi_conn_queryf (be->conn, "DROP DATABASE %s", dbnamelc); + dbi_conn_select_db (conn, "template1"); + dbi_conn_queryf (conn, "DROP DATABASE %s", dbnamelc); goto exit; } - success = gnc_dbi_lock_database (qbe, ignore_lock); + success = gnc_dbi_lock_database (qbe, conn, ignore_lock); } else { @@ -1308,14 +1187,11 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, } if (success) { - if (be->sql_be.conn != nullptr) - { - delete (be->sql_be.conn); - } - be->sql_be.conn = new GncDbiSqlConnection (new GncDbiProviderImpl, - qbe, be->conn); + be->connect(nullptr); + be->connect( + new GncDbiSqlConnection (new GncDbiProviderImpl, + qbe, conn, lock_table)); } - be->sql_be.timespec_format = PGSQL_TIMESPEC_STR_FORMAT; /* We should now have a proper session set up. * Let's start logging */ @@ -1370,17 +1246,8 @@ gnc_dbi_session_end (QofBackend* be_start) ENTER (" "); - if (be->conn != nullptr) - { - gnc_dbi_unlock (be_start); - be->conn = nullptr; - } - if (be->sql_be.conn != nullptr) - { - delete (be->sql_be.conn); - be->sql_be.conn = nullptr; - } - gnc_sql_finalize_version_info (&be->sql_be); + be->finalize_version_info (); + be->connect(nullptr); LEAVE (" "); } @@ -1409,7 +1276,7 @@ gnc_dbi_destroy_backend (QofBackend* be) * then the database will be loaded read-only. A resave will update * both values to match this version of Gnucash. */ -static void +void gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) { GncDbiBackend* be = (GncDbiBackend*)qbe; @@ -1421,10 +1288,10 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) if (loadType == LOAD_TYPE_INITIAL_LOAD) { - g_assert (be->sql_be.book == nullptr); // Set up table version information - gnc_sql_init_version_info (&be->sql_be); + be->init_version_info (); + g_assert (be->m_book == nullptr); // Call all object backends to create any required tables auto registry = gnc_sql_get_backend_registry(); @@ -1432,9 +1299,9 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) create_tables(entry, be); } - gnc_sql_load (&be->sql_be, book, loadType); + gnc_sql_load (be, book, loadType); - if (GNUCASH_RESAVE_VERSION > gnc_sql_get_table_version (&be->sql_be, + if (GNUCASH_RESAVE_VERSION > gnc_sql_get_table_version (be, "Gnucash")) { /* The database was loaded with an older database schema or @@ -1442,7 +1309,7 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) * thing needs to be saved anew. */ qof_backend_set_error (qbe, ERR_SQL_DB_TOO_OLD); } - else if (GNUCASH_RESAVE_VERSION < gnc_sql_get_table_version (&be->sql_be, + else if (GNUCASH_RESAVE_VERSION < gnc_sql_get_table_version (be, "Gnucash-Resave")) { /* Worse, the database was created with a newer version. We @@ -1467,8 +1334,8 @@ save_may_clobber_data (QofBackend* qbe) gboolean retval = FALSE; /* Data may be clobbered iff the number of tables != 0 */ - dbname = dbi_conn_get_option (be->conn, "dbname"); - result = dbi_conn_get_table_list (be->conn, dbname, nullptr); + dbname = dbi_conn_get_option (be->conn(), "dbname"); + result = dbi_conn_get_table_list (be->conn(), dbname, nullptr); if (result) { retval = dbi_result_get_numrows (result) > 0; @@ -1583,16 +1450,15 @@ void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) { GncDbiBackend* be = (GncDbiBackend*)qbe; - GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (((GncSqlBackend*) - be)->conn); - const gchar* dbname = nullptr; + auto conn = dynamic_cast(be->m_conn); + g_return_if_fail (conn != nullptr); g_return_if_fail (be != nullptr); g_return_if_fail (book != nullptr); - ENTER ("book=%p, primary=%p", book, be->sql_be.book); - dbname = dbi_conn_get_option (be->conn, "dbname"); - auto table_list = conn->m_provider->get_table_list (conn->m_conn, dbname); + ENTER ("book=%p, primary=%p", book, be->m_book); + auto dbname = dbi_conn_get_option (conn->conn(), "dbname"); + auto table_list = conn->m_provider->get_table_list (conn->conn(), dbname); if (!conn_table_operation (conn, table_list, backup)) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); @@ -1614,7 +1480,7 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) } } - gnc_sql_sync_all (&be->sql_be, book); + gnc_sql_sync_all (be, book); if (qof_backend_check_error (qbe)) { conn_table_operation (conn, table_list, rollback); @@ -1633,7 +1499,7 @@ gnc_dbi_begin_edit (QofBackend* qbe, QofInstance* inst) g_return_if_fail (be != nullptr); g_return_if_fail (inst != nullptr); - gnc_sql_begin_edit (&be->sql_be, inst); + gnc_sql_begin_edit (be, inst); } static void @@ -1644,7 +1510,7 @@ gnc_dbi_rollback_edit (QofBackend* qbe, QofInstance* inst) g_return_if_fail (be != nullptr); g_return_if_fail (inst != nullptr); - gnc_sql_rollback_edit (&be->sql_be, inst); + gnc_sql_rollback_edit (be, inst); } static void @@ -1655,7 +1521,7 @@ gnc_dbi_commit_edit (QofBackend* qbe, QofInstance* inst) g_return_if_fail (be != nullptr); g_return_if_fail (inst != nullptr); - gnc_sql_commit_edit (&be->sql_be, inst); + gnc_sql_commit_edit (be, inst); } /* ================================================================= */ @@ -1684,22 +1550,17 @@ init_sql_backend (GncDbiBackend* dbi_be) /* CoA Export function not implemented for the SQL backend. */ be->export_fn = nullptr; - gnc_sql_init (&dbi_be->sql_be); - - dbi_be->sql_be.conn = nullptr; - dbi_be->sql_be.book = nullptr; + gnc_sql_init (dbi_be); } static QofBackend* new_backend (void (*session_begin) (QofBackend*, QofSession*, const gchar*, - gboolean, - gboolean, - gboolean)) + gboolean, gboolean, gboolean), + const char* format) { - GncDbiBackend* dbi_be; QofBackend* be; - dbi_be = g_new0 (GncDbiBackend, 1); + auto dbi_be = new GncDbiBackend(nullptr, nullptr, format); g_assert (dbi_be != nullptr); be = (QofBackend*)dbi_be; @@ -1714,19 +1575,22 @@ new_backend (void (*session_begin) (QofBackend*, QofSession*, const gchar*, template<> QofBackend* QofDbiBackendProvider::create_backend() { - return new_backend (gnc_dbi_sqlite3_session_begin); + return new_backend (gnc_dbi_sqlite3_session_begin, + SQLITE3_TIMESPEC_STR_FORMAT); } template<> QofBackend* QofDbiBackendProvider::create_backend() { - return new_backend (gnc_dbi_mysql_session_begin); + return new_backend (gnc_dbi_mysql_session_begin, + MYSQL_TIMESPEC_STR_FORMAT); } template<> QofBackend* QofDbiBackendProvider::create_backend() { - return new_backend (gnc_dbi_postgres_session_begin); + return new_backend (gnc_dbi_postgres_session_begin, + PGSQL_TIMESPEC_STR_FORMAT); } diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index bbfabb64e9..c82482e2e0 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -25,8 +25,17 @@ extern "C" { #include +#ifdef G_OS_WIN32 +#include +#define GETPID() GetCurrentProcessId() +#else +#include +#include +#define GETPID() getpid() +#endif } #include +#define GNC_HOST_NAME_MAX 255 /** * Options to conn_table_operation @@ -76,22 +85,41 @@ public: /** * Implementations of GncSqlBackend. */ -struct GncDbiBackend +class GncDbiBackend : public GncSqlBackend { - GncSqlBackend sql_be; - - dbi_conn conn; - - gboolean exists; // Does the database exist? +public: + GncDbiBackend(GncSqlConnection *conn, QofBook* book, + const char* format = nullptr) : + GncSqlBackend(conn, book, format), m_exists{false} {} + bool connected() const noexcept { return m_conn != nullptr; } + /** FIXME: Just a pass-through to m_conn: */ + void set_error(int error, int repeat, bool retry) noexcept + { + m_conn->set_error(error, repeat, retry); + } + void retry_connection(const char* msg) const noexcept + { + m_conn->retry_connection(msg); + } + /* Worst of all: */ + GncSqlConnection* conn() { return m_conn; } + /*-----*/ + bool exists() { return m_exists; } + void set_exists(bool exists) { m_exists = exists; } + friend void gnc_dbi_load(QofBackend*, QofBook*, QofBackendLoadType); + friend void gnc_dbi_safe_sync_all(QofBackend*, QofBook*); +private: + bool m_exists; // Does the database exist? }; class GncDbiSqlConnection : public GncSqlConnection { public: GncDbiSqlConnection (GncDbiProvider* provider, QofBackend* qbe, - dbi_conn conn) : + dbi_conn conn, const char* lock_table) : m_qbe{qbe}, m_conn{conn}, m_provider{provider}, m_conn_ok{true}, - m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, m_retry{false} {} + m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, m_retry{false}, + m_lock_table{lock_table} {} ~GncDbiSqlConnection() override; GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr&) noexcept override; @@ -114,21 +142,21 @@ public: QofBackend* qbe () const noexcept { return m_qbe; } dbi_conn conn() const noexcept { return m_conn; } GncDbiProvider* provider() { return m_provider; } - inline void set_error (int error, int repeat, bool retry) noexcept + inline void set_error(int error, int repeat, bool retry) noexcept override { m_last_error = error; m_error_repeat = repeat; m_retry = retry; } - inline void init_error () noexcept + inline void init_error() noexcept { set_error(ERR_BACKEND_NO_ERR, 0, false); } /** Check if the dbi connection is valid. If not attempt to re-establish it * Returns TRUE is there is a valid connection in the end or FALSE otherwise */ - bool verify() noexcept; - bool retry_connection(const char* msg) noexcept; + bool verify() noexcept override; + bool retry_connection(const char* msg) noexcept override; dbi_result table_manage_backup(const std::string& table_name, TableOpType op); /* FIXME: These three friend functions should really be members, but doing * that is too invasive just yet. */ @@ -162,6 +190,8 @@ private: * original query) */ gboolean m_retry; + const char* m_lock_table; + void unlock_database(); }; diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index aaa33fea10..38628fc901 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -71,10 +71,99 @@ GncDbiSqlStatement::add_where_cond(QofIdTypeConst type_name, } } +void +GncDbiSqlConnection::unlock_database () +{ + GncDbiBackend* qe = reinterpret_cast(m_qbe); + + if (m_conn == nullptr) return; + g_return_if_fail (dbi_conn_error (m_conn, nullptr) == 0); + + auto dbname = dbi_conn_get_option (m_conn, "dbname"); + /* Check if the lock table exists */ + g_return_if_fail (dbname != nullptr); + auto result = dbi_conn_get_table_list (m_conn, dbname, m_lock_table); + if (! (result && dbi_result_get_numrows (result))) + { + if (result) + { + dbi_result_free (result); + result = nullptr; + } + PWARN ("No lock table in database, so not unlocking it."); + return; + } + dbi_result_free (result); + + result = dbi_conn_query (m_conn, "BEGIN"); + if (result) + { + /* Delete the entry if it's our hostname and PID */ + gchar hostname[ GNC_HOST_NAME_MAX + 1 ]; + + dbi_result_free (result); + result = nullptr; + memset (hostname, 0, sizeof (hostname)); + gethostname (hostname, GNC_HOST_NAME_MAX); + result = dbi_conn_queryf (m_conn, + "SELECT * FROM %s WHERE Hostname = '%s' AND PID = '%d'", m_lock_table, hostname, + (int)GETPID ()); + if (result && dbi_result_get_numrows (result)) + { + if (result) + { + dbi_result_free (result); + result = nullptr; + } + result = dbi_conn_queryf (m_conn, "DELETE FROM %s", m_lock_table); + if (!result) + { + PERR ("Failed to delete the lock entry"); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + result = dbi_conn_query (m_conn, "ROLLBACK"); + if (result) + { + dbi_result_free (result); + result = nullptr; + } + return; + } + else + { + dbi_result_free (result); + result = nullptr; + } + result = dbi_conn_query (m_conn, "COMMIT"); + if (result) + { + dbi_result_free (result); + result = nullptr; + } + return; + } + result = dbi_conn_query (m_conn, "ROLLBACK"); + if (result) + { + dbi_result_free (result); + result = nullptr; + } + PWARN ("There was no lock entry in the Lock table"); + return; + } + if (result) + { + dbi_result_free (result); + result = nullptr; + } + PWARN ("Unable to get a lock on LOCK, so failed to clear the lock entry."); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); +} + GncDbiSqlConnection::~GncDbiSqlConnection() { if (m_conn) { + unlock_database(); dbi_conn_close(m_conn); m_conn = nullptr; } @@ -336,7 +425,8 @@ GncDbiSqlConnection::quote_string (const std::string& unquoted_str) } } -/* Check if the dbi connection is valid. If not attempt to re-establish it + +/** Check if the dbi connection is valid. If not attempt to re-establish it * Returns TRUE is there is a valid connection in the end or FALSE otherwise */ bool diff --git a/src/backend/dbi/gnc-dbisqlconnection.hpp b/src/backend/dbi/gnc-dbisqlconnection.hpp new file mode 100644 index 0000000000..64aedb0d60 --- /dev/null +++ b/src/backend/dbi/gnc-dbisqlconnection.hpp @@ -0,0 +1,29 @@ +/******************************************************************** + * gnc-dbisqlconnection.hpp: Encapsulate libdbi dbi_conn * + * * + * Copyright 2016 John Ralls * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ +#ifndef _GNC_DBISQLCONNECTION_HPP_ +#define _GNC_DBISQLCONNECTION_HPP_ +/** + * Encapsulate a libdbi dbi_conn connection. + */ + +#endif //_GNC_DBISQLCONNECTION_HPP_ diff --git a/src/backend/dbi/test/test-backend-dbi-basic.cpp b/src/backend/dbi/test/test-backend-dbi-basic.cpp index 73f60d6adb..7d57e4b3ac 100644 --- a/src/backend/dbi/test/test-backend-dbi-basic.cpp +++ b/src/backend/dbi/test/test-backend-dbi-basic.cpp @@ -351,12 +351,11 @@ teardown (Fixture* fixture, gconstpointer pData) test_clear_error_list (); } - +#if 0 //temporarily disable test pending refactor. static void test_conn_index_functions (QofBackend* qbe) { GncDbiBackend* be = (GncDbiBackend*)qbe; - GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (be->sql_be.conn); auto index_list = conn->provider()->get_index_list (be->conn); g_test_message ("Returned from index list\n"); @@ -369,7 +368,7 @@ test_conn_index_functions (QofBackend* qbe) } } - +#endif /* Given a synthetic session, use the same logic as * QofSession::save_as to save it to a specified sql url, then load it * back and compare. */ @@ -485,7 +484,7 @@ test_dbi_safe_save (Fixture* fixture, gconstpointer pData) compare_books (qof_session_get_book (session_1), qof_session_get_book (session_2)); be = qof_book_get_backend (qof_session_get_book (session_2)); - test_conn_index_functions (be); +// test_conn_index_functions (be); cleanup: fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check, @@ -512,10 +511,9 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData) auto url = (gchar*)pData; QofSession* sess; QofBook* book; - QofBackend* qbe; QofBackendError err; gint ourversion = gnc_prefs_get_long_version (); - + GncSqlBackend* be; // Load the session data if (fixture->filename) url = fixture->filename; @@ -531,11 +529,10 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData) } qof_session_swap_data (fixture->session, sess); qof_session_save (sess, NULL); - qbe = qof_session_get_backend (sess); + be = reinterpret_cast(qof_session_get_backend (sess)); book = qof_session_get_book (sess); qof_book_begin_edit (book); - gnc_sql_set_table_version ((GncSqlBackend*)qbe, - "Gnucash", GNUCASH_RESAVE_VERSION - 1); + be->set_table_version ("Gnucash", GNUCASH_RESAVE_VERSION - 1); qof_book_commit_edit (book); qof_session_end (sess); qof_session_destroy (sess); @@ -544,13 +541,11 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData) qof_session_load (sess, NULL); err = qof_session_pop_error (sess); g_assert_cmpint (err, == , ERR_SQL_DB_TOO_OLD); - qbe = qof_session_get_backend (sess); + be = reinterpret_cast(qof_session_get_backend (sess)); book = qof_session_get_book (sess); qof_book_begin_edit (book); - gnc_sql_set_table_version ((GncSqlBackend*)qbe, - "Gnucash", ourversion); - gnc_sql_set_table_version ((GncSqlBackend*)qbe, - "Gnucash-Resave", ourversion + 1); + be->set_table_version ("Gnucash", ourversion); + be->set_table_version ("Gnucash-Resave", ourversion + 1); qof_book_commit_edit (book); qof_session_end (sess); qof_session_destroy (sess); @@ -561,11 +556,10 @@ test_dbi_version_control (Fixture* fixture, gconstpointer pData) err = qof_session_pop_error (sess); g_assert_cmpint (err, == , ERR_SQL_DB_TOO_NEW); cleanup: - qbe = qof_session_get_backend (sess); + be = reinterpret_cast(qof_session_get_backend (sess)); book = qof_session_get_book (sess); qof_book_begin_edit (book); - gnc_sql_set_table_version ((GncSqlBackend*)qbe, - "Gnucash-Resave", GNUCASH_RESAVE_VERSION); + be->set_table_version ("Gnucash-Resave", GNUCASH_RESAVE_VERSION); qof_book_commit_edit (book); qof_session_end (sess); qof_session_destroy (sess); diff --git a/src/backend/dbi/test/test-dbi-stuff.cpp b/src/backend/dbi/test/test-dbi-stuff.cpp index 38950399d8..8c8006548f 100644 --- a/src/backend/dbi/test/test-dbi-stuff.cpp +++ b/src/backend/dbi/test/test-dbi-stuff.cpp @@ -210,12 +210,11 @@ compare_lots (QofBook* book_1, QofBook* book_2) { do_compare (book_1, book_2, GNC_ID_LOT, compare_single_lot, "Lot lists match"); } - +#if 0 //Disable test temporarily static void test_conn_index_functions (QofBackend* qbe) { GncDbiBackend* be = (GncDbiBackend*)qbe; - GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (be->sql_be.conn); auto index_list = conn->provider()->get_index_list (be->conn); g_test_message ("Returned from index list\n"); @@ -227,7 +226,7 @@ test_conn_index_functions (QofBackend* qbe) g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn(), &errmsg)); } } - +#endif static void compare_pricedbs (QofBook* book_1, QofBook* book_2) { diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index f0114ff10c..0831095db7 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -183,11 +183,11 @@ load_single_account (GncSqlBackend* be, GncSqlRow& row, guid = gnc_sql_load_guid (be, row); if (guid != NULL) { - pAccount = xaccAccountLookup (guid, be->book); + pAccount = xaccAccountLookup (guid, be->book()); } if (pAccount == NULL) { - pAccount = xaccMallocAccount (be->book); + pAccount = xaccMallocAccount (be->book()); } xaccAccountBeginEdit (pAccount); gnc_sql_load_object (be, row, GNC_ID_ACCOUNT, pAccount, col_table); @@ -196,7 +196,7 @@ load_single_account (GncSqlBackend* be, GncSqlRow& row, /* If we don't have a parent and this isn't the root account, it might be because the parent account hasn't been loaded yet. Remember the account and its parent guid for later. */ if (gnc_account_get_parent (pAccount) == NULL - && pAccount != gnc_book_get_root_account (be->book)) + && pAccount != gnc_book_get_root_account (be->book())) { account_parent_guid_struct* s = static_cast ( g_malloc (sizeof (account_parent_guid_struct))); @@ -222,7 +222,7 @@ GncSqlAccountBackend::load_all (GncSqlBackend* be) ENTER (""); - pBook = be->book; + pBook = be->book(); auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); if (stmt == nullptr) @@ -256,7 +256,7 @@ GncSqlAccountBackend::load_all (GncSqlBackend* be) for (elem = l_accounts_needing_parents; elem != NULL;) { account_parent_guid_struct* s = (account_parent_guid_struct*)elem->data; - pParent = xaccAccountLookup (&s->guid, be->book); + pParent = xaccAccountLookup (&s->guid, be->book()); if (pParent != NULL) { GList* next_elem; @@ -347,7 +347,7 @@ GncSqlAccountBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } @@ -397,7 +397,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, { load_from_guid_ref(row, obj_name, pObject, [be](GncGUID* g){ - return xaccAccountLookup(g, be->book); + return xaccAccountLookup(g, be->book()); }); } diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index f51a3a83da..b1ced878df 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -82,10 +82,12 @@ extern "C" #include "gnc-tax-table-sql.h" #include "gnc-vendor-sql.h" +#define VERSION_TABLE_NAME "versions" +#define MAX_TABLE_NAME_LEN 50 +#define TABLE_COL_NAME "table_name" +#define VERSION_COL_NAME "table_version" + static void gnc_sql_init_object_handlers (void); -static void update_progress (GncSqlBackend* be); -static void finish_progress (GncSqlBackend* be); -static gboolean reset_version_info (GncSqlBackend* be); static GncSqlStatementPtr build_insert_statement (GncSqlBackend* be, const gchar* table_name, QofIdTypeConst obj_name, @@ -183,7 +185,7 @@ create_tables(const OBEEntry& entry, GncSqlBackend* be) GncSqlObjectBackendPtr obe = nullptr; std::tie(type, obe) = entry; g_return_if_fail (obe->is_version (GNC_SQL_BACKEND_VERSION)); - update_progress(be); + be->update_progress(); obe->create_tables(be); } @@ -240,12 +242,12 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) ENTER ("be=%p, book=%p", be, book); - be->loading = TRUE; + be->m_loading = TRUE; if (loadType == LOAD_TYPE_INITIAL_LOAD) { - g_assert (be->book == NULL); - be->book = book; + g_assert (be->m_book == NULL); + be->m_book = book; /* Load any initial stuff. Some of this needs to happen in a certain order */ for (auto type : fixed_load_order) @@ -253,7 +255,7 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) auto obe = gnc_sql_get_object_backend(type); if (obe) { - update_progress(be); + be->update_progress(); obe->load_all (be); } } @@ -262,7 +264,7 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) auto obe = gnc_sql_get_object_backend(type); if (obe) { - update_progress(be); + be->update_progress(); obe->load_all (be); } } @@ -284,7 +286,7 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) obe->load_all (be); } - be->loading = FALSE; + be->m_loading = FALSE; g_list_free_full (post_load_commodities, commit_commodity); post_load_commodities = NULL; @@ -292,7 +294,7 @@ gnc_sql_load (GncSqlBackend* be, QofBook* book, QofBackendLoadType loadType) * dirty with this backend */ qof_book_mark_session_saved (book); - finish_progress (be); + be->finish_progress(); LEAVE (""); } @@ -321,7 +323,7 @@ write_account_tree (GncSqlBackend* be, Account* root) } g_list_free (descendants); } - update_progress (be); + be->update_progress(); return is_ok; } @@ -333,12 +335,12 @@ write_accounts (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); - update_progress (be); - is_ok = write_account_tree (be, gnc_book_get_root_account (be->book)); + be->update_progress(); + is_ok = write_account_tree (be, gnc_book_get_root_account (be->book())); if (is_ok) { - update_progress (be); - is_ok = write_account_tree (be, gnc_book_get_template_root (be->book)); + be->update_progress(); + is_ok = write_account_tree (be, gnc_book_get_template_root (be->book())); } return is_ok; @@ -360,7 +362,7 @@ write_tx (Transaction* tx, gpointer data) { s->is_ok = splitbe->commit(s->be, QOF_INSTANCE(split_node->data)); } - update_progress (s->be); + s->be->update_progress (); return (s->is_ok ? 0 : 1); } @@ -373,8 +375,8 @@ write_transactions (GncSqlBackend* be) write_objects_t data{be, true, obe}; (void)xaccAccountTreeForEachTransaction ( - gnc_book_get_root_account (be->book), write_tx, &data); - update_progress (be); + gnc_book_get_root_account (be->book()), write_tx, &data); + be->update_progress(); return data.is_ok; } @@ -385,11 +387,11 @@ write_template_transactions (GncSqlBackend* be) auto obe = gnc_sql_get_object_backend(GNC_ID_TRANS); write_objects_t data{be, true, obe}; - auto ra = gnc_book_get_template_root (be->book); + auto ra = gnc_book_get_template_root (be->book()); if (gnc_account_n_descendants (ra) > 0) { (void)xaccAccountTreeForEachTransaction (ra, write_tx, &data); - update_progress (be); + be->update_progress(); } return data.is_ok; @@ -404,7 +406,7 @@ write_schedXactions (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); - schedXactions = gnc_book_get_schedxactions (be->book)->sx_list; + schedXactions = gnc_book_get_schedxactions (be->book())->sx_list; auto obe = gnc_sql_get_object_backend(GNC_ID_SCHEDXACTION); for (; schedXactions != NULL && is_ok; schedXactions = schedXactions->next) @@ -412,25 +414,270 @@ write_schedXactions (GncSqlBackend* be) tmpSX = static_cast (schedXactions->data); is_ok = obe->commit (be, QOF_INSTANCE (tmpSX)); } - update_progress (be); + be->update_progress(); return is_ok; } -static void -update_progress (GncSqlBackend* be) +static EntryVec version_table { - if (be->be.percentage != NULL) - (be->be.percentage) (NULL, 101.0); + gnc_sql_make_table_entry( + TABLE_COL_NAME, MAX_TABLE_NAME_LEN, COL_PKEY | COL_NNUL), + gnc_sql_make_table_entry(VERSION_COL_NAME, 0, COL_NNUL) +}; + +GncSqlBackend::GncSqlBackend(GncSqlConnection *conn, QofBook* book, + const char* format) : + be {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, ERR_BACKEND_NO_ERR, nullptr, 0, + nullptr}, m_conn{conn}, m_book{book}, m_loading{false}, + m_in_query{false}, m_is_pristine_db{false}, m_versions{nullptr}, + m_timespec_format{format} +{ + if (conn != nullptr) + connect (conn); } -static void -finish_progress (GncSqlBackend* be) +void +GncSqlBackend::connect(GncSqlConnection *conn) noexcept { - if (be->be.percentage != NULL) - (be->be.percentage) (NULL, -1.0); + if (m_conn != nullptr && m_conn != conn) + delete m_conn; + if (m_versions != nullptr) + finalize_version_info(); + m_conn = conn; } +GncSqlStatementPtr +GncSqlBackend::create_statement_from_sql(const std::string& str) const noexcept +{ + auto stmt = m_conn->create_statement_from_sql(str); + if (stmt == nullptr) + { + PERR ("SQL error: %s\n", str.c_str()); + qof_backend_set_error ((QofBackend*)this, ERR_BACKEND_SERVER_ERR); + } + return stmt; +} + +GncSqlResultPtr +GncSqlBackend::execute_select_statement(const GncSqlStatementPtr& stmt) const noexcept +{ + auto result = m_conn->execute_select_statement(stmt); + if (result == nullptr) + { + PERR ("SQL error: %s\n", stmt->to_sql()); + qof_backend_set_error ((QofBackend*)this, ERR_BACKEND_SERVER_ERR); + } + return result; +} + +int +GncSqlBackend::execute_nonselect_statement(const GncSqlStatementPtr& stmt) const noexcept +{ + auto result = m_conn->execute_nonselect_statement(stmt); + if (result == -1) + { + PERR ("SQL error: %s\n", stmt->to_sql()); + qof_backend_set_error ((QofBackend*)this, ERR_BACKEND_SERVER_ERR); + } + return result; +} + +std::string +GncSqlBackend::quote_string(const std::string& str) const noexcept +{ + return m_conn->quote_string(str); +} + +bool +GncSqlBackend::create_table(const std::string& table_name, + const EntryVec& col_table) const noexcept +{ + ColVec info_vec; + gboolean ok = FALSE; + + for (auto const& table_row : col_table) + { + table_row->add_to_table (this, info_vec); + } + return m_conn->create_table (table_name, info_vec); + +} + +bool +GncSqlBackend::create_index(const std::string& index_name, + const std::string& table_name, + const EntryVec& col_table) const noexcept +{ + return m_conn->create_index(index_name, table_name, col_table); +} + +bool +GncSqlBackend::add_columns_to_table(const std::string& table_name, + const EntryVec& col_table) const noexcept +{ + ColVec info_vec; + + for (auto const& table_row : col_table) + { + table_row->add_to_table (this, info_vec); + } + return m_conn->add_columns_to_table(table_name, info_vec); +} + +void +GncSqlBackend::update_progress() const noexcept +{ + if (be.percentage != nullptr) + (be.percentage) (nullptr, 101.0); +} + +void +GncSqlBackend::finish_progress() const noexcept +{ + if (be.percentage != nullptr) + (be.percentage) (nullptr, -1.0); +} + +/** + * Sees if the version table exists, and if it does, loads the info into + * the version hash table. Otherwise, it creates an empty version table. + * + * @param be Backend struct + */ +void +GncSqlBackend::init_version_info() noexcept +{ + if (m_versions != NULL) + { + g_hash_table_destroy (m_versions); + } + m_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + if (m_conn->does_table_exist (VERSION_TABLE_NAME)) + { + std::string sql {"SELECT * FROM "}; + sql += VERSION_TABLE_NAME; + auto stmt = m_conn->create_statement_from_sql(sql); + auto result = m_conn->execute_select_statement (stmt); + for (const auto& row : *result) + { + auto name = row.get_string_at_col (TABLE_COL_NAME); + auto version = row.get_int_at_col (VERSION_COL_NAME); + g_hash_table_insert (m_versions, g_strdup (name.c_str()), + GINT_TO_POINTER (version)); + } + } + else + { + create_table (VERSION_TABLE_NAME, version_table); + set_table_version("Gnucash", gnc_prefs_get_long_version ()); + set_table_version("Gnucash-Resave", GNUCASH_RESAVE_VERSION); + } +} + +/** + * Resets the version table information by removing all version table info. + * It also recreates the version table in the db. + * + * @param be Backend struct + * @return TRUE if successful, FALSE if error + */ +bool +GncSqlBackend::reset_version_info() noexcept +{ + bool ok = true; + if (!m_conn->does_table_exist (VERSION_TABLE_NAME)) + ok = create_table (VERSION_TABLE_NAME, version_table); + if (m_versions == nullptr) + { + m_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + } + else + { + g_hash_table_remove_all (m_versions); + } + + set_table_version ("Gnucash", gnc_prefs_get_long_version ()); + set_table_version ("Gnucash-Resave", GNUCASH_RESAVE_VERSION); + return ok; +} + +/** + * Finalizes the version table info by destroying the hash table. + * + * @param be Backend struct + */ +void +GncSqlBackend::finalize_version_info() noexcept +{ + if (m_versions != nullptr) + { + g_hash_table_destroy (m_versions); + m_versions = nullptr; + } +} + +int +GncSqlBackend::get_table_version(const std::string& table_name) const noexcept +{ + /* If the db is pristine because it's being saved, the table does not exist. */ + if (m_is_pristine_db) + return 0; + + return GPOINTER_TO_INT (g_hash_table_lookup (m_versions, + table_name.c_str())); +} + +/** + * Registers the version for a table. Registering involves updating the + * db version table and also the hash table. + * + * @param be Backend struct + * @param table_name Table name + * @param version Version number + * @return TRUE if successful, FALSE if unsuccessful + */ +bool +GncSqlBackend::set_table_version (const std::string& table_name, int version) noexcept +{ + gchar* sql; + gint cur_version; + gint status; + + g_return_val_if_fail (version > 0, false); + + cur_version = get_table_version (table_name); + if (cur_version != version) + { + if (cur_version == 0) + { + sql = g_strdup_printf ("INSERT INTO %s VALUES('%s',%d)", VERSION_TABLE_NAME, + table_name.c_str(), version); + } + else + { + sql = g_strdup_printf ("UPDATE %s SET %s=%d WHERE %s='%s'", VERSION_TABLE_NAME, + VERSION_COL_NAME, version, + TABLE_COL_NAME, table_name.c_str()); + } + status = gnc_sql_execute_nonselect_sql (this, sql); + if (status == -1) + { + PERR ("SQL error: %s\n", sql); + qof_backend_set_error ((QofBackend*)this, ERR_BACKEND_SERVER_ERR); + } + g_free (sql); + } + + g_hash_table_insert (m_versions, g_strdup (table_name.c_str()), + GINT_TO_POINTER (version)); + + return true; +} + + void gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) { @@ -439,18 +686,18 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) g_return_if_fail (be != NULL); g_return_if_fail (book != NULL); - ENTER ("book=%p, be->book=%p", book, be->book); - update_progress (be); - (void)reset_version_info (be); + be->reset_version_info(); + ENTER ("book=%p, be->book=%p", book, be->book()); + be->update_progress(); /* Create new tables */ - be->is_pristine_db = TRUE; + be->m_is_pristine_db = true; for(auto entry : backend_registry) create_tables(entry, be); /* Save all contents */ - be->book = book; - is_ok = be->conn->begin_transaction (); + be->m_book = book; + is_ok = be->m_conn->begin_transaction (); // FIXME: should write the set of commodities that are used //write_commodities( be, book ); @@ -482,11 +729,11 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) } if (is_ok) { - is_ok = be->conn->commit_transaction (); + is_ok = be->m_conn->commit_transaction (); } if (is_ok) { - be->is_pristine_db = FALSE; + be->m_is_pristine_db = false; /* Mark the session as clean -- though it shouldn't ever get * marked dirty with this backend @@ -497,9 +744,9 @@ gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) { if (!qof_backend_check_error ((QofBackend*)be)) qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_SERVER_ERR); - is_ok = be->conn->rollback_transaction (); + is_ok = be->m_conn->rollback_transaction (); } - finish_progress (be); + be->finish_progress(); LEAVE ("book=%p", book); } @@ -558,15 +805,15 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) g_return_if_fail (be != NULL); g_return_if_fail (inst != NULL); - if (qof_book_is_readonly (be->book)) + if (qof_book_is_readonly (be->book())) { qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_READONLY); - (void)be->conn->rollback_transaction (); + (void)be->m_conn->rollback_transaction (); return; } /* During initial load where objects are being created, don't commit - anything, but do mark the object as clean. */ - if (be->loading) + anything, but do mark the object as clean. */ + if (be->m_loading) { qof_instance_mark_clean (inst); return; @@ -576,7 +823,7 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) if (strcmp (inst->e_type, "PriceDB") == 0) { qof_instance_mark_clean (inst); - qof_book_mark_session_saved (be->book); + qof_book_mark_session_saved (be->book()); return; } @@ -596,7 +843,7 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) return; } - if (!be->conn->begin_transaction ()) + if (!be->m_conn->begin_transaction ()) { PERR ("gnc_sql_commit_edit(): begin_transaction failed\n"); LEAVE ("Rolled back - database transaction begin error"); @@ -614,10 +861,10 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) if (!be_data.is_known) { PERR ("gnc_sql_commit_edit(): Unknown object type '%s'\n", inst->e_type); - (void)be->conn->rollback_transaction (); + (void)be->m_conn->rollback_transaction (); // Don't let unknown items still mark the book as being dirty - qof_book_mark_session_saved (be->book); + qof_book_mark_session_saved (be->book()); qof_instance_mark_clean (inst); LEAVE ("Rolled back - unknown object type"); return; @@ -625,16 +872,16 @@ gnc_sql_commit_edit (GncSqlBackend* be, QofInstance* inst) if (!be_data.is_ok) { // Error - roll it back - (void)be->conn->rollback_transaction (); + (void)be->m_conn->rollback_transaction (); // This *should* leave things marked dirty LEAVE ("Rolled back - database error"); return; } - (void)be->conn->commit_transaction (); + (void)be->m_conn->commit_transaction (); - qof_book_mark_session_saved (be->book); + qof_book_mark_session_saved (be->book()); qof_instance_mark_clean (inst); LEAVE (""); @@ -1011,7 +1258,7 @@ gnc_sql_run_query (QofBackend* pBEnd, gpointer pQuery) // } // Mark the book as clean - qof_instance_mark_clean (QOF_INSTANCE (be->book)); + qof_instance_mark_clean (QOF_INSTANCE (be->book())); // DEBUG( "%s\n", (gchar*)pQueryInfo->pCompiledQuery ); @@ -1431,7 +1678,7 @@ gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, Timespec ts) year = tm->tm_year + 1900; - datebuf = g_strdup_printf (be->timespec_format, + datebuf = g_strdup_printf (be->timespec_format(), year, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); gnc_tm_free (tm); return datebuf; @@ -1794,17 +2041,8 @@ gnc_sql_execute_select_statement (GncSqlBackend* be, { g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (stmt != NULL, NULL); - auto result = be->conn->execute_select_statement (stmt); - if (result == NULL) - { - PERR ("SQL error: %s\n", stmt->to_sql()); - if (!qof_backend_check_error(&be->be)) - qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); - } - - return result; + return be->execute_select_statement (stmt); } GncSqlStatementPtr @@ -1813,15 +2051,7 @@ gnc_sql_create_statement_from_sql (GncSqlBackend* be, const gchar* sql) g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (sql != NULL, NULL); - auto stmt = be->conn->create_statement_from_sql (sql); - if (stmt == nullptr) - { - PERR ("SQL error: %s\n", sql); - if (!qof_backend_check_error(&be->be)) - qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); - } - - return stmt; + return be->create_statement_from_sql (sql); } GncSqlResultPtr @@ -1835,15 +2065,7 @@ gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) { return nullptr; } - auto result = be->conn->execute_select_statement (stmt); - if (result == nullptr) - { - PERR ("SQL error: %s\n", sql); - if (!qof_backend_check_error(&be->be)) - qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); - } - - return result; + return be->execute_select_statement (stmt); } gint @@ -1857,8 +2079,7 @@ gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql) { return -1; } - auto result = be->conn->execute_nonselect_statement (stmt); - return result; + return be->execute_nonselect_statement (stmt); } guint @@ -1942,7 +2163,7 @@ gnc_sql_do_db_operation (GncSqlBackend* be, const EntryVec& table) { GncSqlStatementPtr stmt; - gboolean ok = FALSE; + bool ok = false; g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); @@ -1965,20 +2186,8 @@ gnc_sql_do_db_operation (GncSqlBackend* be, { g_assert (FALSE); } - if (stmt != nullptr) - { - auto result = be->conn->execute_nonselect_statement (stmt); - if (result == -1) - { - PERR ("SQL error: %s\n", stmt->to_sql()); - if (!qof_backend_check_error(&be->be)) - qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); - } - else - { - ok = TRUE; - } - } + if (be->execute_nonselect_statement (stmt) != -1) + ok = true; return ok; } @@ -2012,11 +2221,11 @@ build_insert_statement (GncSqlBackend* be, { if (col_value != *values.begin()) sql << ","; - sql << be->conn->quote_string(col_value.second); + sql << be->quote_string(col_value.second); } sql << ")"; - stmt = be->conn->create_statement_from_sql(sql.str()); + stmt = be->create_statement_from_sql(sql.str()); return stmt; } @@ -2045,10 +2254,10 @@ build_update_statement (GncSqlBackend* be, if (col_value != *values.begin()) sql << ","; sql << col_value.first << "=" << - be->conn->quote_string(col_value.second); + be->quote_string(col_value.second); } - stmt = be->conn->create_statement_from_sql(sql.str()); + stmt = be->create_statement_from_sql(sql.str()); /* We want our where condition to be just the first column and * value, i.e. the guid of the object. */ @@ -2071,7 +2280,7 @@ build_delete_statement (GncSqlBackend* be, g_return_val_if_fail (pObject != NULL, NULL); sql << "DELETE FROM " << table_name; - auto stmt = be->conn->create_statement_from_sql (sql.str()); + auto stmt = be->create_statement_from_sql (sql.str()); /* WHERE */ PairVec values; @@ -2096,7 +2305,7 @@ GncSqlObjectBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } @@ -2126,51 +2335,28 @@ GncSqlObjectBackend::commit (GncSqlBackend* be, QofInstance* inst) /* ================================================================= */ -static gboolean -do_create_table (const GncSqlBackend* be, const gchar* table_name, - const EntryVec& col_table) -{ - ColVec info_vec; - gboolean ok = FALSE; - - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (table_name != NULL, FALSE); - - for (auto const& table_row : col_table) - { - table_row->add_to_table (be, info_vec); - } - ok = be->conn->create_table (table_name, info_vec); - return ok; -} - gboolean -gnc_sql_create_table (GncSqlBackend* be, const char* table_name, - gint table_version, const EntryVec& col_table) +gnc_sql_create_table (GncSqlBackend* be, const gchar* table_name, + int table_version, const EntryVec& col_table) { - gboolean ok; - - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (table_name != NULL, FALSE); - DEBUG ("Creating %s table\n", table_name); - ok = do_create_table (be, table_name, col_table); - if (ok) - { - ok = gnc_sql_set_table_version (be, table_name, table_version); - } - return ok; + if (be->create_table (table_name, col_table)) + return be->set_table_version (table_name, table_version); + + return false; } void GncSqlObjectBackend::create_tables (GncSqlBackend* be) { g_return_if_fail (be != nullptr); - int version = gnc_sql_get_table_version (be, m_table_name.c_str()); - if (version == 0) //No tables, otherwise version will be >= 1. - gnc_sql_create_table (be, m_table_name.c_str(), - m_version, m_col_table); + int version = be->get_table_version (m_table_name); + if (version == 0) //No tables, otherwise version will be >= 1. + { + be->create_table(m_table_name, m_col_table); + be->set_table_version(m_table_name, m_version); + } else if (version != m_version) PERR("Version mismatch in table %s, expecting %d but backend is %d." "Table creation aborted.", m_table_name.c_str(), m_version, version); @@ -2183,7 +2369,7 @@ gnc_sql_create_temp_table (const GncSqlBackend* be, const gchar* table_name, g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - return do_create_table (be, table_name, col_table); + return be->create_table (table_name, col_table); } gboolean @@ -2197,7 +2383,7 @@ gnc_sql_create_index (const GncSqlBackend* be, const gchar* index_name, g_return_val_if_fail (index_name != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - ok = be->conn->create_index (index_name, table_name, col_table); + ok = be->create_index (index_name, table_name, col_table); return ok; } @@ -2206,14 +2392,7 @@ gnc_sql_get_table_version (const GncSqlBackend* be, const gchar* table_name) { g_return_val_if_fail (be != NULL, 0); g_return_val_if_fail (table_name != NULL, 0); - - /* If the db is pristine because it's being saved, the table does not exist. */ - if (be->is_pristine_db) - { - return 0; - } - - return GPOINTER_TO_INT (g_hash_table_lookup (be->versions, table_name)); + return be->get_table_version(table_name); } /* Create a temporary table, copy the data from the old table, delete the @@ -2252,169 +2431,14 @@ gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name, gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const gchar* table_name, const EntryVec& new_col_table) { - ColVec info_vec; - gboolean ok = FALSE; - g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (table_name != NULL, FALSE); - for (auto const& table_row : new_col_table) - { - table_row->add_to_table (be, info_vec); - } - ok = be->conn->add_columns_to_table(table_name, info_vec); - return ok; + return be->add_columns_to_table(table_name, new_col_table); } /* ================================================================= */ -#define VERSION_TABLE_NAME "versions" -#define MAX_TABLE_NAME_LEN 50 -#define TABLE_COL_NAME "table_name" -#define VERSION_COL_NAME "table_version" -static EntryVec version_table -{ - gnc_sql_make_table_entry( - TABLE_COL_NAME, MAX_TABLE_NAME_LEN, COL_PKEY | COL_NNUL), - gnc_sql_make_table_entry(VERSION_COL_NAME, 0, COL_NNUL) -}; - -/** - * Sees if the version table exists, and if it does, loads the info into - * the version hash table. Otherwise, it creates an empty version table. - * - * @param be Backend struct - */ -void -gnc_sql_init_version_info (GncSqlBackend* be) -{ - g_return_if_fail (be != NULL); - - if (be->versions != NULL) - { - g_hash_table_destroy (be->versions); - } - be->versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - - if (be->conn->does_table_exist (VERSION_TABLE_NAME)) - { - auto sql = g_strdup_printf ("SELECT * FROM %s", VERSION_TABLE_NAME); - auto result = gnc_sql_execute_select_sql (be, sql); - g_free (sql); - for (const auto& row : *result) - { - auto name = row.get_string_at_col (TABLE_COL_NAME); - auto version = row.get_int_at_col (VERSION_COL_NAME); - g_hash_table_insert (be->versions, g_strdup (name.c_str()), - GINT_TO_POINTER (version)); - } - } - else - { - do_create_table (be, VERSION_TABLE_NAME, version_table); - gnc_sql_set_table_version (be, "Gnucash", - gnc_prefs_get_long_version ()); - gnc_sql_set_table_version (be, "Gnucash-Resave", - GNUCASH_RESAVE_VERSION); - } -} - -/** - * Resets the version table information by removing all version table info. - * It also recreates the version table in the db. - * - * @param be Backend struct - * @return TRUE if successful, FALSE if error - */ -static gboolean -reset_version_info (GncSqlBackend* be) -{ - gboolean ok; - - g_return_val_if_fail (be != NULL, FALSE); - - ok = do_create_table (be, VERSION_TABLE_NAME, version_table); - if (be->versions == NULL) - { - be->versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - } - else - { - g_hash_table_remove_all (be->versions); - } - - gnc_sql_set_table_version (be, "Gnucash", gnc_prefs_get_long_version ()); - gnc_sql_set_table_version (be, "Gnucash-Resave", GNUCASH_RESAVE_VERSION); - return ok; -} - -/** - * Finalizes the version table info by destroying the hash table. - * - * @param be Backend struct - */ -void -gnc_sql_finalize_version_info (GncSqlBackend* be) -{ - g_return_if_fail (be != NULL); - - if (be->versions != NULL) - { - g_hash_table_destroy (be->versions); - be->versions = NULL; - } -} - -/** - * Registers the version for a table. Registering involves updating the - * db version table and also the hash table. - * - * @param be Backend struct - * @param table_name Table name - * @param version Version number - * @return TRUE if successful, FALSE if unsuccessful - */ -gboolean -gnc_sql_set_table_version (GncSqlBackend* be, const gchar* table_name, - gint version) -{ - gchar* sql; - gint cur_version; - gint status; - - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (table_name != NULL, FALSE); - g_return_val_if_fail (version > 0, FALSE); - - cur_version = gnc_sql_get_table_version (be, table_name); - if (cur_version != version) - { - if (cur_version == 0) - { - sql = g_strdup_printf ("INSERT INTO %s VALUES('%s',%d)", VERSION_TABLE_NAME, - table_name, version); - } - else - { - sql = g_strdup_printf ("UPDATE %s SET %s=%d WHERE %s='%s'", VERSION_TABLE_NAME, - VERSION_COL_NAME, version, - TABLE_COL_NAME, table_name); - } - status = gnc_sql_execute_nonselect_sql (be, sql); - if (status == -1) - { - PERR ("SQL error: %s\n", sql); - if (!qof_backend_check_error(&be->be)) - qof_backend_set_error (&be->be, ERR_BACKEND_SERVER_ERR); - } - g_free (sql); - } - - g_hash_table_insert (be->versions, g_strdup (table_name), - GINT_TO_POINTER (version)); - - return TRUE; -} /* This is necessary for 64-bit builds because g++ complains * that reinterpret_casting a void* (64 bits) to an int (32 bits) diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 734cbb7e02..15f32e8490 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -59,22 +59,66 @@ using ColVec = std::vector; using StrVec = std::vector; using PairVec = std::vector>; class GncSqlConnection; +class GncSqlStatement; +using GncSqlStatementPtr = std::unique_ptr; +class GncSqlResult; +//using GncSqlResultPtr = std::unique_ptr; +using GncSqlResultPtr = GncSqlResult*; /** * @struct GncSqlBackend * * Main SQL backend structure. */ -struct GncSqlBackend +class GncSqlBackend { - QofBackend be; /**< QOF backend */ - GncSqlConnection* conn; /**< SQL connection */ - QofBook* book; /**< The primary, main open book */ - gboolean loading; /**< We are performing an initial load */ - gboolean in_query; /**< We are processing a query */ - gboolean is_pristine_db; /**< Are we saving to a new pristine db? */ - GHashTable* versions; /**< Version number for each table */ - const gchar* timespec_format; /**< Format string for SQL for timespec values */ +public: + GncSqlBackend(GncSqlConnection *conn, QofBook* book, + const char* format = nullptr); + virtual ~GncSqlBackend() = default; + /** Connect the backend to a GncSqlConnection. + * Sets up version info. Calling with nullptr clears the connection and + * destroys the version info. + */ + void connect(GncSqlConnection *conn) noexcept; + void init_version_info() noexcept; + bool reset_version_info() noexcept; + void finalize_version_info() noexcept; + /* FIXME: These are just pass-throughs of m_conn functions. */ + GncSqlStatementPtr create_statement_from_sql(const std::string& str) const noexcept; + GncSqlResultPtr execute_select_statement(const GncSqlStatementPtr& stmt) const noexcept; + int execute_nonselect_statement(const GncSqlStatementPtr& stmt) const noexcept; + std::string quote_string(const std::string&) const noexcept; + bool create_table(const std::string& table_name, const EntryVec& col_table) const noexcept; + bool create_index(const std::string& index_name, + const std::string& table_name, + const EntryVec& col_table) const noexcept; + bool add_columns_to_table(const std::string& table_name, + const EntryVec& col_table) const noexcept; + int get_table_version(const std::string& table_name) const noexcept; + bool set_table_version (const std::string& table_name, int version) noexcept; + QofBook* book() const noexcept { return m_book; } + + bool pristine() const noexcept { return m_is_pristine_db; } + void update_progress() const noexcept; + void finish_progress() const noexcept; + void set_loading(bool val) noexcept { m_loading = val; } + const char* timespec_format() const noexcept { return m_timespec_format; } + + friend void gnc_sql_load(GncSqlBackend*, QofBook*, QofBackendLoadType); + friend void gnc_sql_sync_all(GncSqlBackend*, QofBook*); + friend void gnc_sql_commit_edit(GncSqlBackend*, QofInstance*); + +protected: + QofBackend be; /**< QOF backend. Not a pointer, nor really a member */ + GncSqlConnection* m_conn; /**< SQL connection */ + QofBook* m_book; /**< The primary, main open book */ + bool m_loading; /**< We are performing an initial load */ + bool m_in_query; /**< We are processing a query */ + bool m_is_pristine_db; /**< Are we saving to a new pristine db? */ + GHashTable* m_versions; /**< Version number for each table */ + const char* m_timespec_format; /**< Format string for SQL for timespec values */ +private: }; /** @@ -137,9 +181,6 @@ void gnc_sql_commit_edit (GncSqlBackend* qbe, QofInstance* inst); /** */ -class GncSqlResult; -//using GncSqlResultPtr = std::unique_ptr; -using GncSqlResultPtr = GncSqlResult*; /** * SQL statement provider. @@ -152,8 +193,6 @@ public: virtual void add_where_cond (QofIdTypeConst, const PairVec&) = 0; }; -using GncSqlStatementPtr = std::unique_ptr; - /** * Encapsulate the connection to the database. */ @@ -192,6 +231,10 @@ public: * If not 0 will normally be meaningless outside of implementation code. */ virtual int dberror() const noexcept = 0; + virtual void set_error(int error, int repeat, bool retry) noexcept = 0; + virtual bool verify() noexcept = 0; + virtual bool retry_connection(const char* msg) noexcept = 0; + }; /** diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index 28cb6b27ee..e4054d79c2 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -197,10 +197,10 @@ load_single_billterm (GncSqlBackend* be, GncSqlRow& row, g_return_val_if_fail (be != NULL, NULL); guid = gnc_sql_load_guid (be, row); - pBillTerm = gncBillTermLookup (be->book, guid); + pBillTerm = gncBillTermLookup (be->book(), guid); if (pBillTerm == NULL) { - pBillTerm = gncBillTermCreate (be->book); + pBillTerm = gncBillTermCreate (be->book()); } gnc_sql_load_object (be, row, GNC_ID_BILLTERM, pBillTerm, col_table); @@ -298,7 +298,7 @@ GncSqlBillTermBackend::write (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); write_objects_t data {be, true, this}; - qof_object_foreach (GNC_ID_BILLTERM, be->book, do_save_billterm, &data); + qof_object_foreach (GNC_ID_BILLTERM, be->book(), do_save_billterm, &data); return data.is_ok; } @@ -319,7 +319,7 @@ GncSqlBillTermBackend::create_tables (GncSqlBackend* be) { /* Upgrade 64 bit int handling */ gnc_sql_upgrade_table (be, TABLE_NAME, col_table); - gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION); + be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Billterms table upgraded from version 1 to version %d\n", TABLE_VERSION); @@ -336,7 +336,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, { load_from_guid_ref(row, obj_name, pObject, [be](GncGUID* g){ - return gncBillTermLookup(be->book, g); + return gncBillTermLookup(be->book(), g); }); } diff --git a/src/backend/sql/gnc-book-sql.cpp b/src/backend/sql/gnc-book-sql.cpp index 081a74439c..5e4b4b5d8f 100644 --- a/src/backend/sql/gnc-book-sql.cpp +++ b/src/backend/sql/gnc-book-sql.cpp @@ -152,7 +152,7 @@ load_single_book (GncSqlBackend* be, GncSqlRow& row) gnc_sql_load_guid (be, row); - pBook = be->book; + pBook = be->book(); if (pBook == NULL) { pBook = qof_book_new (); @@ -182,9 +182,9 @@ GncSqlBookBackend::load_all (GncSqlBackend* be) */ if (row == result->end()) { - be->loading = FALSE; - commit(be, QOF_INSTANCE (be->book)); - be->loading = TRUE; + be->set_loading(false); + commit (be, QOF_INSTANCE (be->book())); + be->set_loading(true); } else { diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index 8c76172394..96aee9f71e 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -275,7 +275,7 @@ save_budget_amounts (GncSqlBackend* be, GncBudget* budget) info.budget = budget; num_periods = gnc_budget_get_num_periods (budget); descendants = gnc_account_get_descendants (gnc_book_get_root_account ( - be->book)); + be->book())); for (node = descendants; node != NULL && is_ok; node = g_list_next (node)) { guint i; @@ -308,11 +308,11 @@ load_single_budget (GncSqlBackend* be, GncSqlRow& row) guid = gnc_sql_load_guid (be, row); if (guid != NULL) { - pBudget = gnc_budget_lookup (guid, be->book); + pBudget = gnc_budget_lookup (guid, be->book()); } if (pBudget == NULL) { - pBudget = gnc_budget_new (be->book); + pBudget = gnc_budget_new (be->book()); } gnc_budget_begin_edit (pBudget); @@ -398,7 +398,7 @@ GncSqlBudgetBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } @@ -464,7 +464,7 @@ GncSqlBudgetBackend::write (GncSqlBackend* be) data.be = be; data.is_ok = TRUE; data.obe = this; - qof_collection_foreach (qof_book_get_collection (be->book, GNC_ID_BUDGET), + qof_collection_foreach (qof_book_get_collection (be->book(), GNC_ID_BUDGET), (QofInstanceForeachCB)do_save, &data); return data.is_ok; @@ -479,7 +479,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, { load_from_guid_ref(row, obj_name, pObject, [be](GncGUID* g){ - return gnc_budget_lookup (g, be->book); + return gnc_budget_lookup (g, be->book()); }); } diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index efac9acc46..7b1ca5bc77 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -129,7 +129,7 @@ set_quote_source_name (gpointer pObject, gpointer pValue) static gnc_commodity* load_single_commodity (GncSqlBackend* be, GncSqlRow& row) { - QofBook* pBook = be->book; + QofBook* pBook = be->book(); gnc_commodity* pCommodity; pCommodity = gnc_commodity_new (pBook, NULL, NULL, NULL, NULL, 100); @@ -145,7 +145,7 @@ GncSqlCommodityBackend::load_all (GncSqlBackend* be) { gnc_commodity_table* pTable; - pTable = gnc_commodity_table_get_table (be->book); + pTable = gnc_commodity_table_get_table (be->book()); auto stmt = gnc_sql_create_select_statement (be, COMMODITIES_TABLE); if (stmt == nullptr) return; auto result = gnc_sql_execute_select_statement (be, stmt); @@ -186,7 +186,7 @@ do_commit_commodity (GncSqlBackend* be, QofInstance* inst, { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant || force_insert) + else if (be->pristine() || is_infant || force_insert) { op = OP_DB_INSERT; } @@ -268,7 +268,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, { load_from_guid_ref(row, obj_name, pObject, [be](GncGUID* g){ - return gnc_commodity_find_commodity_by_guid(g, be->book); + return gnc_commodity_find_commodity_by_guid(g, be->book()); }); } diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index 43bce7f309..de77b245e4 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -110,10 +110,10 @@ load_single_customer (GncSqlBackend* be, GncSqlRow& row) g_return_val_if_fail (be != NULL, NULL); guid = gnc_sql_load_guid (be, row); - pCustomer = gncCustomerLookup (be->book, guid); + pCustomer = gncCustomerLookup (be->book(), guid); if (pCustomer == NULL) { - pCustomer = gncCustomerCreate (be->book); + pCustomer = gncCustomerCreate (be->book()); } gnc_sql_load_object (be, row, GNC_ID_CUSTOMER, pCustomer, col_table); qof_instance_mark_clean (QOF_INSTANCE (pCustomer)); @@ -164,7 +164,7 @@ GncSqlCustomerBackend::create_tables (GncSqlBackend* be) { /* Upgrade 64 bit int handling */ gnc_sql_upgrade_table (be, TABLE_NAME, col_table); - gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION); + be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Customers table upgraded from version 1 to version %d\n", TABLE_VERSION); @@ -214,7 +214,7 @@ GncSqlCustomerBackend::write (GncSqlBackend* be) data.be = be; data.is_ok = TRUE; data.obe = this; - qof_object_foreach (GNC_ID_CUSTOMER, be->book, write_single_customer, + qof_object_foreach (GNC_ID_CUSTOMER, be->book(), write_single_customer, (gpointer)&data); return data.is_ok; } diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index 166596a193..f295a5d386 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -96,10 +96,10 @@ load_single_employee (GncSqlBackend* be, GncSqlRow& row) g_return_val_if_fail (be != NULL, NULL); guid = gnc_sql_load_guid (be, row); - pEmployee = gncEmployeeLookup (be->book, guid); + pEmployee = gncEmployeeLookup (be->book(), guid); if (pEmployee == NULL) { - pEmployee = gncEmployeeCreate (be->book); + pEmployee = gncEmployeeCreate (be->book()); } gnc_sql_load_object (be, row, GNC_ID_EMPLOYEE, pEmployee, col_table); qof_instance_mark_clean (QOF_INSTANCE (pEmployee)); @@ -151,7 +151,7 @@ GncSqlEmployeeBackend::create_tables (GncSqlBackend* be) { /* Upgrade 64 bit int handling */ gnc_sql_upgrade_table (be, TABLE_NAME, col_table); - gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION); + be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Employees table upgraded from version 1 to version %d\n", TABLE_VERSION); @@ -179,7 +179,7 @@ GncSqlEmployeeBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } @@ -259,7 +259,7 @@ GncSqlEmployeeBackend::write (GncSqlBackend* be) data.be = be; data.is_ok = TRUE; data.obe = this; - qof_object_foreach (GNC_ID_EMPLOYEE, be->book, write_single_employee, &data); + qof_object_foreach (GNC_ID_EMPLOYEE, be->book(), write_single_employee, &data); return data.is_ok; } diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index c9ca9c10ea..3f0623db80 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -178,10 +178,10 @@ load_single_entry (GncSqlBackend* be, GncSqlRow& row) g_return_val_if_fail (be != NULL, NULL); guid = gnc_sql_load_guid (be, row); - pEntry = gncEntryLookup (be->book, guid); + pEntry = gncEntryLookup (be->book(), guid); if (pEntry == NULL) { - pEntry = gncEntryCreate (be->book); + pEntry = gncEntryCreate (be->book()); } gnc_sql_load_object (be, row, GNC_ID_ENTRY, pEntry, col_table); qof_instance_mark_clean (QOF_INSTANCE (pEntry)); @@ -234,7 +234,7 @@ GncSqlEntryBackend::create_tables (GncSqlBackend* be) 2->3: "entered" -> "date_entered", and it can be NULL */ gnc_sql_upgrade_table (be, TABLE_NAME, col_table); - gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION); + be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Entries table upgraded from version %d to version %d\n", version, TABLE_VERSION); @@ -267,7 +267,7 @@ GncSqlEntryBackend::write (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); write_objects_t data{be, true, this}; - qof_object_foreach (GNC_ID_ENTRY, be->book, write_single_entry, &data); + qof_object_foreach (GNC_ID_ENTRY, be->book(), write_single_entry, &data); return data.is_ok; } diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index e3e5b036de..d6d8f5dff7 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -117,10 +117,10 @@ load_single_invoice (GncSqlBackend* be, GncSqlRow& row) g_return_val_if_fail (be != NULL, NULL); guid = gnc_sql_load_guid (be, row); - pInvoice = gncInvoiceLookup (be->book, guid); + pInvoice = gncInvoiceLookup (be->book(), guid); if (pInvoice == NULL) { - pInvoice = gncInvoiceCreate (be->book); + pInvoice = gncInvoiceCreate (be->book()); } gnc_sql_load_object (be, row, GNC_ID_INVOICE, pInvoice, col_table); qof_instance_mark_clean (QOF_INSTANCE (pInvoice)); @@ -173,7 +173,7 @@ GncSqlInvoiceBackend::create_tables (GncSqlBackend* be) 2->3: invoice open date can be NULL */ gnc_sql_upgrade_table (be, TABLE_NAME, col_table); - gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION); + be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Invoices table upgraded from version %d to version %d\n", version, TABLE_VERSION); @@ -201,7 +201,7 @@ GncSqlInvoiceBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } @@ -277,7 +277,7 @@ GncSqlInvoiceBackend::write (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); write_objects_t data{be, true, this}; - qof_object_foreach (GNC_ID_INVOICE, be->book, write_single_invoice, &data); + qof_object_foreach (GNC_ID_INVOICE, be->book(), write_single_invoice, &data); return data.is_ok; } @@ -291,7 +291,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, { load_from_guid_ref(row, obj_name, pObject, [be](GncGUID* g){ - return gncInvoiceLookup (be->book, g); + return gncInvoiceLookup (be->book(), g); }); } diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index da052c442d..cb03233dd0 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -89,10 +89,10 @@ load_single_job (GncSqlBackend* be, GncSqlRow& row) g_return_val_if_fail (be != NULL, NULL); guid = gnc_sql_load_guid (be, row); - pJob = gncJobLookup (be->book, guid); + pJob = gncJobLookup (be->book(), guid); if (pJob == NULL) { - pJob = gncJobCreate (be->book); + pJob = gncJobCreate (be->book()); } gnc_sql_load_object (be, row, GNC_ID_JOB, pJob, col_table); qof_instance_mark_clean (QOF_INSTANCE (pJob)); @@ -164,7 +164,7 @@ GncSqlJobBackend::write (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); write_objects_t data{be, true, this}; - qof_object_foreach (GNC_ID_JOB, be->book, write_single_job, &data); + qof_object_foreach (GNC_ID_JOB, be->book(), write_single_job, &data); return data.is_ok; } diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index 4e3bebe979..ce4fcda627 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -113,7 +113,7 @@ load_single_lot (GncSqlBackend* be, GncSqlRow& row) g_return_val_if_fail (be != NULL, NULL); - lot = gnc_lot_new (be->book); + lot = gnc_lot_new (be->book()); gnc_lot_begin_edit (lot); gnc_sql_load_object (be, row, GNC_ID_LOT, lot, col_table); @@ -166,7 +166,7 @@ GncSqlLotsBackend::create_tables (GncSqlBackend* be) old table, then rename the new one. */ gnc_sql_upgrade_table (be, TABLE_NAME, col_table); - (void)gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION); + be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Lots table upgraded from version 1 to version %d\n", TABLE_VERSION); } @@ -189,7 +189,7 @@ GncSqlLotsBackend::write (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); write_objects_t data{be, true, this}; - qof_collection_foreach (qof_book_get_collection (be->book, GNC_ID_LOT), + qof_collection_foreach (qof_book_get_collection (be->book(), GNC_ID_LOT), (QofInstanceForeachCB)do_save_lot, &data); return data.is_ok; } @@ -203,7 +203,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, { load_from_guid_ref(row, obj_name, pObject, [be](GncGUID* g){ - return gnc_lot_lookup(g, be->book); + return gnc_lot_lookup(g, be->book()); }); } diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index f330f3e1ec..8541bbe90a 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -89,10 +89,10 @@ load_single_order (GncSqlBackend* be, GncSqlRow& row) g_return_val_if_fail (be != NULL, NULL); guid = gnc_sql_load_guid (be, row); - pOrder = gncOrderLookup (be->book, guid); + pOrder = gncOrderLookup (be->book(), guid); if (pOrder == NULL) { - pOrder = gncOrderCreate (be->book); + pOrder = gncOrderCreate (be->book()); } gnc_sql_load_object (be, row, GNC_ID_ORDER, pOrder, col_table); qof_instance_mark_clean (QOF_INSTANCE (pOrder)); @@ -164,7 +164,7 @@ GncSqlOrderBackend::write (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); write_objects_t data{be, true, this}; - qof_object_foreach (GNC_ID_ORDER, be->book, write_single_order, &data); + qof_object_foreach (GNC_ID_ORDER, be->book(), write_single_order, &data); return data.is_ok; } @@ -178,7 +178,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, { load_from_guid_ref(row, obj_name, pObject, [be](GncGUID* g){ - return gncOrderLookup(be->book, g); + return gncOrderLookup(be->book(), g); }); } diff --git a/src/backend/sql/gnc-owner-sql.cpp b/src/backend/sql/gnc-owner-sql.cpp index 0e354f9282..ca6b452cff 100644 --- a/src/backend/sql/gnc-owner-sql.cpp +++ b/src/backend/sql/gnc-owner-sql.cpp @@ -61,7 +61,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, g_return_if_fail (be != NULL); g_return_if_fail (pObject != NULL); - auto book = be->book; + auto book = be->book(); auto buf = std::string{m_col_name} + "_type"; try { diff --git a/src/backend/sql/gnc-price-sql.cpp b/src/backend/sql/gnc-price-sql.cpp index 1fa67b8c11..7974eaf228 100644 --- a/src/backend/sql/gnc-price-sql.cpp +++ b/src/backend/sql/gnc-price-sql.cpp @@ -89,7 +89,7 @@ load_single_price (GncSqlBackend* be, GncSqlRow& row) g_return_val_if_fail (be != NULL, NULL); - pPrice = gnc_price_create (be->book); + pPrice = gnc_price_create (be->book()); gnc_price_begin_edit (pPrice); gnc_sql_load_object (be, row, GNC_ID_PRICE, pPrice, col_table); @@ -106,7 +106,7 @@ GncSqlPriceBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); - pBook = be->book; + pBook = be->book(); pPriceDB = gnc_pricedb_get_db (pBook); auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); if (stmt != nullptr) @@ -154,7 +154,7 @@ GncSqlPriceBackend::create_tables (GncSqlBackend* be) { /* Upgrade 64 bit int handling */ gnc_sql_upgrade_table (be, TABLE_NAME, col_table); - (void)gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION); + be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Prices table upgraded from version 1 to version %d\n", TABLE_VERSION); } @@ -179,7 +179,7 @@ GncSqlPriceBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } @@ -226,7 +226,7 @@ GncSqlPriceBackend::write (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); write_objects_t data{be, true, this}; - auto priceDB = gnc_pricedb_get_db (be->book); + auto priceDB = gnc_pricedb_get_db (be->book()); return gnc_pricedb_foreach_price (priceDB, write_price, &data, TRUE); } diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index 10d1a817a7..7ca09cafdd 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -321,7 +321,7 @@ gnc_sql_set_recurrences_from_db (GncSqlBackend* be, const GncGUID* guid) (void)guid_to_string_buff (guid, guid_buf); buf = g_strdup_printf ("SELECT * FROM %s WHERE obj_guid='%s'", TABLE_NAME, guid_buf); - auto stmt = be->conn->create_statement_from_sql (buf); + auto stmt = be->create_statement_from_sql (buf); g_free (buf); auto result = gnc_sql_execute_select_statement (be, stmt); return result; @@ -424,7 +424,7 @@ GncSqlRecurrenceBackend::create_tables (GncSqlBackend* be) { upgrade_recurrence_table_1_2 (be); } - (void)gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION); + be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Recurrence table upgraded from version %d to version %d\n", version, TABLE_VERSION); } diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index 2ed4002ae7..3eb6e3c590 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -104,7 +104,7 @@ load_single_sx (GncSqlBackend* be, GncSqlRow& row) guid = gnc_sql_load_guid (be, row); g_assert (guid != NULL); - pSx = xaccSchedXactionMalloc (be->book); + pSx = xaccSchedXactionMalloc (be->book()); gnc_sx_begin_edit (pSx); gnc_sql_load_object (be, row, GNC_SX_ID, pSx, col_table); @@ -128,7 +128,7 @@ GncSqlSchedXactionBackend::load_all (GncSqlBackend* be) auto result = gnc_sql_execute_select_statement (be, stmt); SchedXactions* sxes; GList* list = NULL; - sxes = gnc_book_get_schedxactions (be->book); + sxes = gnc_book_get_schedxactions (be->book()); for (auto row : *result) { @@ -171,7 +171,7 @@ GncSqlSchedXactionBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index b87dfd6297..c91f77c646 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -714,7 +714,7 @@ gnc_sql_slots_save (GncSqlBackend* be, const GncGUID* guid, gboolean is_infant, g_return_val_if_fail (pFrame != NULL, FALSE); // If this is not saving into a new db, clear out the old saved slots first - if (!be->is_pristine_db && !is_infant) + if (!be->pristine() && !is_infant) { (void)gnc_sql_slots_delete (be, guid); } @@ -947,7 +947,7 @@ load_slot_for_book_object (GncSqlBackend* be, GncSqlRow& row, guid = load_obj_guid (be, row); g_return_if_fail (guid != NULL); - inst = lookup_fn (guid, be->book); + inst = lookup_fn (guid, be->book()); g_return_if_fail (inst != NULL); slot_info.be = be; @@ -1045,7 +1045,7 @@ GncSqlSlotsBackend::create_tables (GncSqlBackend* be) PERR ("Unable to add gdate column\n"); } } - (void)gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION); + be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Slots table upgraded from version %d to version %d\n", version, TABLE_VERSION); } diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index 415f76612a..94d1f48cdf 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -237,7 +237,7 @@ load_taxtable_entries (GncSqlBackend* be, GncTaxTable* tt) g_value_set_string (&value, guid_buf); buf = g_strdup_printf ("SELECT * FROM %s WHERE taxtable='%s'", TTENTRIES_TABLE_NAME, guid_buf); - auto stmt = be->conn->create_statement_from_sql (buf); + auto stmt = be->create_statement_from_sql (buf); g_free (buf); auto result = gnc_sql_execute_select_statement (be, stmt); for (auto row : *result) @@ -254,10 +254,10 @@ load_single_taxtable (GncSqlBackend* be, GncSqlRow& row, g_return_if_fail (be != NULL); guid = gnc_sql_load_guid (be, row); - tt = gncTaxTableLookup (be->book, guid); + tt = gncTaxTableLookup (be->book(), guid); if (tt == NULL) { - tt = gncTaxTableCreate (be->book); + tt = gncTaxTableCreate (be->book()); } gnc_sql_load_object (be, row, GNC_ID_TAXTABLE, tt, tt_col_table); gnc_sql_slots_load (be, QOF_INSTANCE (tt)); @@ -342,7 +342,7 @@ GncSqlTaxTableBackend::create_tables (GncSqlBackend* be) { /* Upgrade 64 bit int handling */ gnc_sql_upgrade_table (be, TT_TABLE_NAME, tt_col_table); - gnc_sql_set_table_version (be, TT_TABLE_NAME, TT_TABLE_VERSION); + be->set_table_version (TT_TABLE_NAME, TT_TABLE_VERSION); PINFO ("Taxtables table upgraded from version 1 to version %d\n", TT_TABLE_VERSION); } @@ -357,7 +357,7 @@ GncSqlTaxTableBackend::create_tables (GncSqlBackend* be) { /* Upgrade 64 bit int handling */ gnc_sql_upgrade_table (be, TTENTRIES_TABLE_NAME, ttentries_col_table); - gnc_sql_set_table_version (be, TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION); + be->set_table_version (TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION); PINFO ("Taxtable entries table upgraded from version 1 to version %d\n", TTENTRIES_TABLE_VERSION); } @@ -423,7 +423,7 @@ GncSqlTaxTableBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } @@ -477,7 +477,7 @@ GncSqlTaxTableBackend::write (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); write_objects_t data{be, true, this}; - qof_object_foreach (GNC_ID_TAXTABLE, be->book, save_next_taxtable, &data); + qof_object_foreach (GNC_ID_TAXTABLE, be->book(), save_next_taxtable, &data); return data.is_ok; } @@ -491,7 +491,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, { load_from_guid_ref(row, obj_name, pObject, [be](GncGUID* g){ - return gncTaxTableLookup(be->book, g); + return gncTaxTableLookup(be->book(), g); }); } diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index f595eba66c..e1300ad2db 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -231,12 +231,12 @@ load_single_split (GncSqlBackend* be, GncSqlRow& row) else { split_guid = *guid; - pSplit = xaccSplitLookup (&split_guid, be->book); + pSplit = xaccSplitLookup (&split_guid, be->book()); } if (pSplit == NULL) { - pSplit = xaccMallocSplit (be->book); + pSplit = xaccMallocSplit (be->book()); } /* If the split is dirty, don't overwrite it */ @@ -246,12 +246,12 @@ load_single_split (GncSqlBackend* be, GncSqlRow& row) } /*# -ifempty */ - if (pSplit != xaccSplitLookup (&split_guid, be->book)) + if (pSplit != xaccSplitLookup (&split_guid, be->book())) { gchar guidstr[GUID_ENCODING_LENGTH + 1]; guid_to_string_buff (qof_instance_get_guid (pSplit), guidstr); PERR ("A malformed split with id %s was found in the dataset.", guidstr); - qof_backend_set_error (&be->be, ERR_BACKEND_DATA_CORRUPT); + qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_DATA_CORRUPT); pSplit = NULL; } return pSplit; @@ -308,22 +308,22 @@ load_single_tx (GncSqlBackend* be, GncSqlRow& row) tx_guid = *guid; // Don't overwrite the transaction if it's already been loaded (and possibly modified). - pTx = xaccTransLookup (&tx_guid, be->book); + pTx = xaccTransLookup (&tx_guid, be->book()); if (pTx != NULL) { return NULL; } - pTx = xaccMallocTransaction (be->book); + pTx = xaccMallocTransaction (be->book()); xaccTransBeginEdit (pTx); gnc_sql_load_object (be, row, GNC_ID_TRANS, pTx, tx_col_table); - if (pTx != xaccTransLookup (&tx_guid, be->book)) + if (pTx != xaccTransLookup (&tx_guid, be->book())) { gchar guidstr[GUID_ENCODING_LENGTH + 1]; guid_to_string_buff (qof_instance_get_guid (pTx), guidstr); PERR ("A malformed transaction with id %s was found in the dataset.", guidstr); - qof_backend_set_error (&be->be, ERR_BACKEND_DATA_CORRUPT); + qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_DATA_CORRUPT); pTx = NULL; } @@ -370,7 +370,7 @@ query_transactions (GncSqlBackend* be, const GncSqlStatementPtr& stmt) #if LOAD_TRANSACTIONS_AS_NEEDED GSList* bal_list = NULL; GSList* nextbal; - Account* root = gnc_book_get_root_account (be->book); + Account* root = gnc_book_get_root_account (be->book()); qof_event_suspend (); xaccAccountBeginEdit (root); @@ -506,7 +506,7 @@ GncSqlTransBackend::create_tables (GncSqlBackend* be) 2->3: allow dates to be NULL */ gnc_sql_upgrade_table (be, m_table_name.c_str(), tx_col_table); - (void)gnc_sql_set_table_version (be, m_table_name.c_str(), m_version); + be->set_table_version (m_table_name.c_str(), m_version); PINFO ("Transactions table upgraded from version %d to version %d\n", version, m_version); } @@ -544,7 +544,7 @@ GncSqlSplitBackend::create_tables (GncSqlBackend* be) m_table_name.c_str(), account_guid_col_table)) PERR ("Unable to create index\n"); - (void)gnc_sql_set_table_version (be, m_table_name.c_str(), m_version); + be->set_table_version (m_table_name.c_str(), m_version); PINFO ("Splits table upgraded from version %d to version %d\n", version, m_version); } @@ -625,7 +625,7 @@ GncSqlSplitBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } @@ -668,7 +668,7 @@ GncSqlTransBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } @@ -685,7 +685,7 @@ GncSqlTransBackend::commit (GncSqlBackend* be, QofInstance* inst) if (! is_ok) { err = "Commodity save failed: Probably an invalid or missing currency"; - qof_backend_set_error (&be->be, ERR_BACKEND_DATA_CORRUPT); + qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_DATA_CORRUPT); } } @@ -1238,7 +1238,7 @@ set_acct_bal_account_from_guid (gpointer pObject, gpointer pValue) g_return_if_fail (pObject != NULL); g_return_if_fail (pValue != NULL); - bal->acct = xaccAccountLookup (guid, bal->be->book); + bal->acct = xaccAccountLookup (guid, bal->be->book()); } static void @@ -1389,7 +1389,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, auto val = row.get_string_at_col (m_col_name); GncGUID guid; (void)string_to_guid (val.c_str(), &guid); - auto tx = xaccTransLookup (&guid, be->book); + auto tx = xaccTransLookup (&guid, be->book()); // If the transaction is not found, try loading it if (tx == nullptr) @@ -1399,7 +1399,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, auto stmt = gnc_sql_create_statement_from_sql ((GncSqlBackend*)be, buf.c_str()); query_transactions ((GncSqlBackend*)be, stmt); - tx = xaccTransLookup (&guid, be->book); + tx = xaccTransLookup (&guid, be->book()); } if (tx != nullptr) diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index 3c40be7862..6ee5035bb0 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -99,10 +99,10 @@ load_single_vendor (GncSqlBackend* be, GncSqlRow& row) g_return_val_if_fail (be != NULL, NULL); guid = gnc_sql_load_guid (be, row); - pVendor = gncVendorLookup (be->book, guid); + pVendor = gncVendorLookup (be->book(), guid); if (pVendor == NULL) { - pVendor = gncVendorCreate (be->book); + pVendor = gncVendorCreate (be->book()); } gnc_sql_load_object (be, row, GNC_ID_VENDOR, pVendor, col_table); qof_instance_mark_clean (QOF_INSTANCE (pVendor)); @@ -154,7 +154,7 @@ GncSqlVendorBackend::commit (GncSqlBackend* be, QofInstance* inst) { op = OP_DB_DELETE; } - else if (be->is_pristine_db || is_infant) + else if (be->pristine() || is_infant) { op = OP_DB_INSERT; } @@ -229,7 +229,7 @@ GncSqlVendorBackend::write (GncSqlBackend* be) g_return_val_if_fail (be != NULL, FALSE); write_objects_t data{be, true, this}; - qof_object_foreach (GNC_ID_VENDOR, be->book, write_single_vendor, &data); + qof_object_foreach (GNC_ID_VENDOR, be->book(), write_single_vendor, &data); return data.is_ok; } diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index 46bec746d5..d83eb5021e 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -105,6 +105,9 @@ public: virtual std::string quote_string (const std::string& str) const noexcept override { return std::string{str}; } int dberror() const noexcept override { return 0; } + void set_error(int error, int repeat, bool retry) noexcept override { return; } + bool verify() noexcept override { return true; } + bool retry_connection(const char* msg) noexcept override { return true; } private: GncMockSqlResult m_result; }; @@ -256,7 +259,6 @@ test_dirty_cb (QofBook* book, gboolean dirty, gpointer data) static void test_gnc_sql_commit_edit (void) { - GncSqlBackend be; QofInstance* inst; guint dirty_called = 0; GncMockSqlConnection conn; @@ -282,52 +284,51 @@ test_gnc_sql_commit_edit (void) g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_list_handler, NULL); qof_object_initialize (); - be.book = qof_book_new (); - be.conn = &conn; + auto book = qof_book_new(); + GncSqlBackend be (&conn, book); inst = static_cast (g_object_new (QOF_TYPE_INSTANCE, NULL)); - qof_instance_init_data (inst, QOF_ID_NULL, be.book); - be.loading = FALSE; - qof_book_set_dirty_cb (be.book, test_dirty_cb, &dirty_called); + qof_instance_init_data (inst, QOF_ID_NULL, book); + qof_book_set_dirty_cb (book, test_dirty_cb, &dirty_called); qof_instance_set_dirty_flag (inst, TRUE); - qof_book_mark_session_dirty (be.book); + qof_book_mark_session_dirty (book); g_assert (qof_instance_get_dirty_flag (inst)); - g_assert (qof_book_session_not_saved (be.book)); + g_assert (qof_book_session_not_saved (book)); g_assert_cmpint (dirty_called, == , 1); gnc_sql_commit_edit (&be, inst); g_assert (!qof_instance_get_dirty_flag (inst)); - g_assert (!qof_book_session_not_saved (be.book)); + g_assert (!qof_book_session_not_saved (book)); g_assert_cmpint (dirty_called, == , 0); g_assert_cmpint (check1.hits, == , 2); g_assert_cmpint (check2.hits, == , 0); - qof_book_mark_session_dirty (be.book); + qof_book_mark_session_dirty (book); - g_assert (!qof_instance_get_dirty_flag (QOF_INSTANCE (be.book))); - g_assert (qof_book_session_not_saved (be.book)); + g_assert (!qof_instance_get_dirty_flag (QOF_INSTANCE (book))); + g_assert (qof_book_session_not_saved (book)); g_assert_cmpint (dirty_called, == , 1); - gnc_sql_commit_edit (&be, QOF_INSTANCE (be.book)); - g_assert (!qof_instance_get_dirty_flag (QOF_INSTANCE (be.book))); - g_assert (qof_book_session_not_saved (be.book)); + gnc_sql_commit_edit (&be, QOF_INSTANCE (book)); + g_assert (!qof_instance_get_dirty_flag (QOF_INSTANCE (book))); + g_assert (qof_book_session_not_saved (book)); g_assert_cmpint (dirty_called, == , 1); g_assert_cmpint (check1.hits, == , 2); g_assert_cmpint (check2.hits, == , 0); - qof_instance_set_dirty_flag (QOF_INSTANCE (be.book), TRUE); + qof_instance_set_dirty_flag (QOF_INSTANCE (book), TRUE); - g_assert (qof_instance_get_dirty_flag (QOF_INSTANCE (be.book))); - g_assert (qof_book_session_not_saved (be.book)); + g_assert (qof_instance_get_dirty_flag (QOF_INSTANCE (book))); + g_assert (qof_book_session_not_saved (book)); g_assert_cmpint (dirty_called, == , 1); - gnc_sql_commit_edit (&be, QOF_INSTANCE (be.book)); - g_assert (!qof_instance_get_dirty_flag (QOF_INSTANCE (be.book))); - g_assert (!qof_book_session_not_saved (be.book)); + gnc_sql_commit_edit (&be, QOF_INSTANCE (book)); + g_assert (!qof_instance_get_dirty_flag (QOF_INSTANCE (book))); + g_assert (!qof_book_session_not_saved (book)); g_assert_cmpint (dirty_called, == , 0); g_assert_cmpint (check1.hits, == , 2); g_assert_cmpint (check2.hits, == , 2); g_log_remove_handler (logdomain, hdlr1); g_object_unref (inst); - g_object_unref (be.book); + g_object_unref (book); } /* handle_and_term static void @@ -633,14 +634,7 @@ gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, Timespec ts)// C: 1 static void test_gnc_sql_convert_timespec_to_string () { - GncSqlBackend be = {{ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, ERR_BACKEND_NO_ERR, nullptr, - 0, nullptr - }, - nullptr, nullptr, FALSE, FALSE, FALSE, nullptr, - "%4d-%02d-%02d %02d:%02d:%02d" - }; + GncSqlBackend be {nullptr, nullptr, "%4d-%02d-%02d %02d:%02d:%02d"}; const char* date[numtests] = {"1995-03-11 19:17:26", "2001-04-20 11:44:07", "1964-02-29 09:15:23", From d1fd223f9fd947e168a5ac5ab2842bc09ef7b23e Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 23 Jul 2016 12:52:17 -0700 Subject: [PATCH 33/63] Make conn_table_operation and add_columns_ddl members of GncDbiSqlConnection. So they don't need to be friends. --- src/backend/dbi/gnc-backend-dbi.cpp | 124 +---------------------- src/backend/dbi/gnc-backend-dbi.hpp | 12 +-- src/backend/dbi/gnc-dbisqlconnection.cpp | 107 ++++++++++++++++++- 3 files changed, 115 insertions(+), 128 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index c45288dbff..a8739f4f25 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -1344,98 +1344,6 @@ save_may_clobber_data (QofBackend* qbe) return retval; } -/** - * Perform a specified SQL operation on every table in a - * database. Possible operations are: - * * drop: to DROP all tables from the database - * * empty: to DELETE all records from each table in the database. - * * backup: Rename every table from "name" to "name_back" - * * drop_backup: DROP the backup tables. - * * rollback: DROP the new table "name" and rename "name_back" to - * "name", restoring the database to its previous state. - * - * The intent of the last two is to be able to move an existing table - * aside, query its contents with a transformation (in 2.4.x this is - * already done as the contents are loaded completely when a Qof - * session is started), save them to a new table according to a new - * database format, and finally drop the backup table; if there's an - * error during the process, rollback allows returning the table to - * its original state. - * - * @param sql_conn: The sql connection (via dbi) to which the - * transactions will be sent - * @param tables: GList of tables to operate on. - * @param op: The operation to perform. - * @return Success (TRUE) or failure. - */ - -gboolean -conn_table_operation (GncSqlConnection* sql_conn, - std::vector table_name_list, - TableOpType op) -{ - gboolean result = TRUE; - GncDbiSqlConnection* conn = (GncDbiSqlConnection*) (sql_conn); - const gchar* dbname = dbi_conn_get_option (conn->m_conn, "dbname"); - - g_return_val_if_fail (!table_name_list.empty(), FALSE); - - for (auto table : table_name_list) - { - dbi_result result; - auto table_name = table.c_str(); - /* Ignore the lock table */ - if (g_strcmp0 (table_name, lock_table) == 0) - { - continue; - } - do - { - conn->init_error (); - switch (op) - { - case rollback: - { - auto full_table_name_list = - conn->m_provider->get_table_list (conn->m_conn, dbname); - if (std::find (full_table_name_list.begin(), - full_table_name_list.end(), - table_name) != full_table_name_list.end()) - { - result = dbi_conn_queryf (conn->m_conn, "DROP TABLE %s", - table_name); - if (result) - break; - } - } - /* Fall through */ - case backup: - case drop_backup: - result = conn->table_manage_backup (table_name, op); - break; - case empty: - result = dbi_conn_queryf (conn->m_conn, "DELETE FROM TABLE %s", - table_name); - break; - case drop: - default: - result = dbi_conn_queryf (conn->m_conn, "DROP TABLE %s", - table_name); - break; - } - } - while (conn->m_retry); - if (result != nullptr) - { - if (dbi_result_free (result) < 0) - { - PERR ("Error in dbi_result_free() result\n"); - result = FALSE; - } - } - } - return result; -} /** * Safely resave a database by renaming all of its tables, recreating @@ -1459,10 +1367,10 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) ENTER ("book=%p, primary=%p", book, be->m_book); auto dbname = dbi_conn_get_option (conn->conn(), "dbname"); auto table_list = conn->m_provider->get_table_list (conn->conn(), dbname); - if (!conn_table_operation (conn, table_list, backup)) + if (!conn->table_operation (table_list, backup)) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - conn_table_operation (conn, table_list, rollback); + conn->table_operation (table_list, rollback); LEAVE ("Failed to rename tables"); return; } @@ -1474,7 +1382,7 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) if (DBI_ERROR_NONE != dbi_conn_error (conn->m_conn, &errmsg)) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - conn_table_operation (conn, table_list, rollback); + conn->table_operation (table_list, rollback); LEAVE ("Failed to drop indexes %s", errmsg); return; } @@ -1483,11 +1391,11 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) gnc_sql_sync_all (be, book); if (qof_backend_check_error (qbe)) { - conn_table_operation (conn, table_list, rollback); + conn->table_operation (table_list, rollback); LEAVE ("Failed to create new database tables"); return; } - conn_table_operation (conn, table_list, drop_backup); + conn->table_operation (table_list, drop_backup); LEAVE ("book=%p", book); } /* ================================================================= */ @@ -1915,28 +1823,6 @@ GncDbiSqlResult::size() const noexcept /* --------------------------------------------------------- */ -std::string -add_columns_ddl(const GncSqlConnection* conn, - const std::string& table_name, - const ColVec& info_vec) -{ - std::string ddl; - const GncDbiSqlConnection* dbi_conn = dynamic_cast(conn); - - g_return_val_if_fail (conn != nullptr, nullptr); - ddl += "ALTER TABLE " + table_name; - for (auto const& info : info_vec) - { - if (info != *info_vec.begin()) - { - ddl += ", "; - } - ddl += "ADD COLUMN "; - dbi_conn->m_provider->append_col_def (ddl, info); - } - return ddl; -} - template<> void GncDbiProviderImpl::append_col_def(std::string& ddl, const GncSqlColumnInfo& info) diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index c82482e2e0..c3ef108d0f 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -160,13 +160,11 @@ public: dbi_result table_manage_backup(const std::string& table_name, TableOpType op); /* FIXME: These three friend functions should really be members, but doing * that is too invasive just yet. */ - friend gboolean conn_table_operation (GncSqlConnection* sql_conn, - std::vector table_name_list, - TableOpType op); + bool table_operation (const std::vector& table_name_list, + TableOpType op) noexcept; + std::string add_columns_ddl(const std::string& table_name, + const ColVec& info_vec) const noexcept; friend void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book); - friend std::string add_columns_ddl(const GncSqlConnection* conn, - const std::string& table_name, - const ColVec& info_vec); private: QofBackend* m_qbe; @@ -195,8 +193,6 @@ private: }; -gboolean conn_table_operation (GncSqlConnection* sql_conn, - GSList* table_name_list, TableOpType op); void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book); std::string add_columns_ddl(const GncSqlConnection* conn, const std::string& table_name, diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index 38628fc901..f715ab4a35 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -390,7 +390,7 @@ GncDbiSqlConnection::add_columns_to_table(const std::string& table_name, const ColVec& info_vec) const noexcept { - auto ddl = add_columns_ddl(this, table_name, info_vec); + auto ddl = add_columns_ddl(table_name, info_vec); if (ddl.empty()) return false; @@ -503,3 +503,108 @@ GncDbiSqlConnection::table_manage_backup (const std::string& table_name, } return result; } +/** + * Perform a specified SQL operation on every table in a + * database. Possible operations are: + * * drop: to DROP all tables from the database + * * empty: to DELETE all records from each table in the database. + * * backup: Rename every table from "name" to "name_back" + * * drop_backup: DROP the backup tables. + * * rollback: DROP the new table "name" and rename "name_back" to + * "name", restoring the database to its previous state. + * + * The intent of the last two is to be able to move an existing table + * aside, query its contents with a transformation (in 2.4.x this is + * already done as the contents are loaded completely when a Qof + * session is started), save them to a new table according to a new + * database format, and finally drop the backup table; if there's an + * error during the process, rollback allows returning the table to + * its original state. + * + * @param sql_conn: The sql connection (via dbi) to which the + * transactions will be sent + * @param tables: GList of tables to operate on. + * @param op: The operation to perform. + * @return Success (TRUE) or failure. + */ + +bool +GncDbiSqlConnection::table_operation(const std::vector& table_names, + TableOpType op) noexcept +{ + const char* dbname = dbi_conn_get_option (m_conn, "dbname"); + std::string lock_table{m_lock_table}; + g_return_val_if_fail (!table_names.empty(), FALSE); + bool retval{true}; + for (auto table : table_names) + { + dbi_result result; + /* Ignore the lock table */ + if (table == lock_table) + { + continue; + } + do + { + init_error(); + switch (op) + { + case rollback: + { + auto all_tables = m_provider->get_table_list(m_conn, dbname); + if (std::find(all_tables.begin(), + all_tables.end(), table) != all_tables.end()) + { + result = dbi_conn_queryf (m_conn, "DROP TABLE %s", + table.c_str()); + if (result) + break; + } + } + /* Fall through */ + case backup: + case drop_backup: + result = table_manage_backup (table, op); + break; + case empty: + result = dbi_conn_queryf (m_conn, "DELETE FROM TABLE %s", + table.c_str()); + break; + case drop: + default: + result = dbi_conn_queryf (m_conn, "DROP TABLE %s", table.c_str()); + break; + } + } + while (m_retry); + + if (result != nullptr) + { + if (dbi_result_free (result) < 0) + { + PERR ("Error in dbi_result_free() result\n"); + retval = false; + } + } + } + return retval; +} + +std::string +GncDbiSqlConnection::add_columns_ddl(const std::string& table_name, + const ColVec& info_vec) const noexcept +{ + std::string ddl; + + ddl += "ALTER TABLE " + table_name; + for (auto const& info : info_vec) + { + if (info != *info_vec.begin()) + { + ddl += ", "; + } + ddl += "ADD COLUMN "; + m_provider->append_col_def (ddl, info); + } + return ddl; +} From 885470b3e7c437e5f3b437d8be084c5f6b5017a9 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 23 Jul 2016 13:38:40 -0700 Subject: [PATCH 34/63] Replace std::vector with StrVec. --- src/backend/dbi/gnc-backend-dbi.cpp | 26 ++++++++++++------------ src/backend/dbi/gnc-backend-dbi.hpp | 2 +- src/backend/dbi/gnc-dbisqlconnection.cpp | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index a8739f4f25..86755d8320 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -132,10 +132,10 @@ public: std::string create_table_ddl(const GncSqlConnection* conn, const std::string& table_name, const ColVec& info_vec); - std::vector get_table_list(dbi_conn conn, + StrVec get_table_list(dbi_conn conn, const std::string& dbname); void append_col_def(std::string& ddl, const GncSqlColumnInfo& info); - std::vector get_index_list (dbi_conn conn); + StrVec get_index_list (dbi_conn conn); void drop_index(dbi_conn conn, const std::string& index); }; @@ -326,10 +326,10 @@ exit: LEAVE ("%s", msg); } -template<> std::vector +template<> StrVec GncDbiProviderImpl::get_index_list (dbi_conn conn) { - std::vector retval; + StrVec retval; const char* errmsg; dbi_result result = dbi_conn_query (conn, "SELECT name FROM sqlite_master WHERE type = 'index' AND name NOT LIKE 'sqlite_autoindex%'"); @@ -891,10 +891,10 @@ exit: LEAVE (" "); } -template<> std::vector +template<> StrVec GncDbiProviderImpl::get_index_list (dbi_conn conn) { - std::vector retval; + StrVec retval; const char* errmsg; auto dbname = dbi_conn_get_option (conn, "dbname"); auto table_list = dbi_conn_get_table_list (conn, dbname, nullptr); @@ -1213,10 +1213,10 @@ exit: LEAVE (" "); } -template<> std::vector +template<> StrVec GncDbiProviderImpl::get_index_list (dbi_conn conn) { - std::vector retval; + StrVec retval; const char* errmsg; PINFO ("Retrieving postgres index list\n"); auto result = dbi_conn_query (conn, @@ -2010,10 +2010,10 @@ GncDbiProviderImpl::append_col_def (std::string& ddl, } } -static std::vector +static StrVec conn_get_table_list (dbi_conn conn, const std::string& dbname) { - std::vector retval; + StrVec retval; auto tables = dbi_conn_get_table_list (conn, dbname.c_str(), nullptr); while (dbi_result_next_row (tables) != 0) { @@ -2024,7 +2024,7 @@ conn_get_table_list (dbi_conn conn, const std::string& dbname) return retval; } -template<> std::vector +template<> StrVec GncDbiProviderImpl::get_table_list (dbi_conn conn, const std::string& dbname) { @@ -2036,14 +2036,14 @@ GncDbiProviderImpl::get_table_list (dbi_conn conn, return list; } -template<> std::vector +template<> StrVec GncDbiProviderImpl::get_table_list (dbi_conn conn, const std::string& dbname) { return conn_get_table_list (conn, dbname); } -template<> std::vector +template<> StrVec GncDbiProviderImpl::get_table_list (dbi_conn conn, const std::string& dbname) { diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index c3ef108d0f..acc7dad681 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -160,7 +160,7 @@ public: dbi_result table_manage_backup(const std::string& table_name, TableOpType op); /* FIXME: These three friend functions should really be members, but doing * that is too invasive just yet. */ - bool table_operation (const std::vector& table_name_list, + bool table_operation (const StrVec& table_name_list, TableOpType op) noexcept; std::string add_columns_ddl(const std::string& table_name, const ColVec& info_vec) const noexcept; diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index f715ab4a35..86b1678392 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -529,8 +529,8 @@ GncDbiSqlConnection::table_manage_backup (const std::string& table_name, */ bool -GncDbiSqlConnection::table_operation(const std::vector& table_names, - TableOpType op) noexcept +GncDbiSqlConnection::table_operation(const StrVec& table_names, + TableOpType op) noexcept { const char* dbname = dbi_conn_get_option (m_conn, "dbname"); std::string lock_table{m_lock_table}; From cb464da599ec3dabead4427a3ff47b975b925317 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 23 Jul 2016 14:33:34 -0700 Subject: [PATCH 35/63] Replace GHashTable in GncSqlConnection with a std::vector. --- src/backend/sql/gnc-backend-sql.cpp | 79 ++++++++++++----------------- src/backend/sql/gnc-backend-sql.h | 8 +-- 2 files changed, 38 insertions(+), 49 deletions(-) diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index b1ced878df..39670d8318 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -431,8 +431,7 @@ GncSqlBackend::GncSqlBackend(GncSqlConnection *conn, QofBook* book, be {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, ERR_BACKEND_NO_ERR, nullptr, 0, nullptr}, m_conn{conn}, m_book{book}, m_loading{false}, - m_in_query{false}, m_is_pristine_db{false}, m_versions{nullptr}, - m_timespec_format{format} + m_in_query{false}, m_is_pristine_db{false}, m_timespec_format{format} { if (conn != nullptr) connect (conn); @@ -443,8 +442,7 @@ GncSqlBackend::connect(GncSqlConnection *conn) noexcept { if (m_conn != nullptr && m_conn != conn) delete m_conn; - if (m_versions != nullptr) - finalize_version_info(); + finalize_version_info(); m_conn = conn; } @@ -549,11 +547,6 @@ GncSqlBackend::finish_progress() const noexcept void GncSqlBackend::init_version_info() noexcept { - if (m_versions != NULL) - { - g_hash_table_destroy (m_versions); - } - m_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); if (m_conn->does_table_exist (VERSION_TABLE_NAME)) { @@ -564,9 +557,8 @@ GncSqlBackend::init_version_info() noexcept for (const auto& row : *result) { auto name = row.get_string_at_col (TABLE_COL_NAME); - auto version = row.get_int_at_col (VERSION_COL_NAME); - g_hash_table_insert (m_versions, g_strdup (name.c_str()), - GINT_TO_POINTER (version)); + unsigned int version = row.get_int_at_col (VERSION_COL_NAME); + m_versions.push_back(std::make_pair(name, version)); } } else @@ -590,15 +582,7 @@ GncSqlBackend::reset_version_info() noexcept bool ok = true; if (!m_conn->does_table_exist (VERSION_TABLE_NAME)) ok = create_table (VERSION_TABLE_NAME, version_table); - if (m_versions == nullptr) - { - m_versions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - } - else - { - g_hash_table_remove_all (m_versions); - } - + m_versions.clear(); set_table_version ("Gnucash", gnc_prefs_get_long_version ()); set_table_version ("Gnucash-Resave", GNUCASH_RESAVE_VERSION); return ok; @@ -612,22 +596,22 @@ GncSqlBackend::reset_version_info() noexcept void GncSqlBackend::finalize_version_info() noexcept { - if (m_versions != nullptr) - { - g_hash_table_destroy (m_versions); - m_versions = nullptr; - } + m_versions.clear(); } -int +unsigned int GncSqlBackend::get_table_version(const std::string& table_name) const noexcept { /* If the db is pristine because it's being saved, the table does not exist. */ if (m_is_pristine_db) return 0; - return GPOINTER_TO_INT (g_hash_table_lookup (m_versions, - table_name.c_str())); + auto version = std::find_if(m_versions.begin(), m_versions.end(), + [table_name](const VersionPair& version) { + return version.first == table_name; }); + if (version != m_versions.end()) + return version->second; + return 0; } /** @@ -640,40 +624,43 @@ GncSqlBackend::get_table_version(const std::string& table_name) const noexcept * @return TRUE if successful, FALSE if unsuccessful */ bool -GncSqlBackend::set_table_version (const std::string& table_name, int version) noexcept +GncSqlBackend::set_table_version (const std::string& table_name, + unsigned int version) noexcept { - gchar* sql; - gint cur_version; - gint status; - g_return_val_if_fail (version > 0, false); - cur_version = get_table_version (table_name); + unsigned int cur_version{0}; + std::stringstream sql; + auto ver_entry = std::find_if(m_versions.begin(), m_versions.end(), + [table_name](const VersionPair& ver) { + return ver.first == table_name; }); + if (ver_entry != m_versions.end()) + cur_version = ver_entry->second; if (cur_version != version) { if (cur_version == 0) { - sql = g_strdup_printf ("INSERT INTO %s VALUES('%s',%d)", VERSION_TABLE_NAME, - table_name.c_str(), version); + sql << "INSERT INTO " << VERSION_TABLE_NAME << " VALUES('" << + table_name << "'," << version <<")"; + m_versions.push_back(std::make_pair(table_name, version)); } else { - sql = g_strdup_printf ("UPDATE %s SET %s=%d WHERE %s='%s'", VERSION_TABLE_NAME, - VERSION_COL_NAME, version, - TABLE_COL_NAME, table_name.c_str()); + sql << "UPDATE " << VERSION_TABLE_NAME << " SET " << + VERSION_COL_NAME << "=" << version << " WHERE " << + TABLE_COL_NAME << "='" << table_name << "'"; + ver_entry->second = version; } - status = gnc_sql_execute_nonselect_sql (this, sql); + auto stmt = create_statement_from_sql(sql.str()); + auto status = execute_nonselect_statement (stmt); if (status == -1) { - PERR ("SQL error: %s\n", sql); + PERR ("SQL error: %s\n", sql.str().c_str()); qof_backend_set_error ((QofBackend*)this, ERR_BACKEND_SERVER_ERR); + return false; } - g_free (sql); } - g_hash_table_insert (m_versions, g_strdup (table_name.c_str()), - GINT_TO_POINTER (version)); - return true; } diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 15f32e8490..35c3220589 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -58,6 +58,8 @@ using EntryVec = std::vector; using ColVec = std::vector; using StrVec = std::vector; using PairVec = std::vector>; +using VersionPair = std::pair; +using VersionVec = std::vector; class GncSqlConnection; class GncSqlStatement; using GncSqlStatementPtr = std::unique_ptr; @@ -95,8 +97,8 @@ public: const EntryVec& col_table) const noexcept; bool add_columns_to_table(const std::string& table_name, const EntryVec& col_table) const noexcept; - int get_table_version(const std::string& table_name) const noexcept; - bool set_table_version (const std::string& table_name, int version) noexcept; + unsigned int get_table_version(const std::string& table_name) const noexcept; + bool set_table_version (const std::string& table_name, unsigned int version) noexcept; QofBook* book() const noexcept { return m_book; } bool pristine() const noexcept { return m_is_pristine_db; } @@ -116,7 +118,7 @@ protected: bool m_loading; /**< We are performing an initial load */ bool m_in_query; /**< We are processing a query */ bool m_is_pristine_db; /**< Are we saving to a new pristine db? */ - GHashTable* m_versions; /**< Version number for each table */ + VersionVec m_versions; /**< Version number for each table */ const char* m_timespec_format; /**< Format string for SQL for timespec values */ private: }; From 4b62deee42db1734922bb255d3d86e1883f9271e Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 24 Jul 2016 10:39:14 -0700 Subject: [PATCH 36/63] Rework gnc_sql_append_guid_list_to_sql to eliminate GString and GList. Which in turn forced rework of its users since the GString and GList were passed-in parameters. --- src/backend/sql/gnc-backend-sql.cpp | 28 ++++------- src/backend/sql/gnc-backend-sql.h | 10 ++-- src/backend/sql/gnc-bill-term-sql.cpp | 13 ++---- src/backend/sql/gnc-budget-sql.cpp | 30 +++++------- src/backend/sql/gnc-customer-sql.cpp | 16 ++----- src/backend/sql/gnc-employee-sql.cpp | 16 ++----- src/backend/sql/gnc-entry-sql.cpp | 15 ++---- src/backend/sql/gnc-invoice-sql.cpp | 15 ++---- src/backend/sql/gnc-job-sql.cpp | 15 ++---- src/backend/sql/gnc-order-sql.cpp | 15 ++---- src/backend/sql/gnc-schedxaction-sql.cpp | 13 ++---- src/backend/sql/gnc-slots-sql.cpp | 45 +++++++----------- src/backend/sql/gnc-slots-sql.h | 7 +-- src/backend/sql/gnc-transaction-sql.cpp | 59 +++++++++--------------- src/backend/sql/gnc-vendor-sql.cpp | 13 ++---- 15 files changed, 117 insertions(+), 193 deletions(-) diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 39670d8318..7d61bebce3 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -625,7 +625,7 @@ GncSqlBackend::get_table_version(const std::string& table_name) const noexcept */ bool GncSqlBackend::set_table_version (const std::string& table_name, - unsigned int version) noexcept + uint_t version) noexcept { g_return_val_if_fail (version > 0, false); @@ -2069,33 +2069,23 @@ gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql) return be->execute_nonselect_statement (stmt); } -guint -gnc_sql_append_guid_list_to_sql (GString* sql, GList* list, guint maxCount) +uint_t +gnc_sql_append_guids_to_sql (std::stringstream& sql, const InstanceVec& instances) { - gchar guid_buf[GUID_ENCODING_LENGTH + 1]; - gboolean first_guid = TRUE; - guint count; + char guid_buf[GUID_ENCODING_LENGTH + 1]; - g_return_val_if_fail (sql != NULL, 0); - - if (list == NULL) return 0; - - for (count = 0; list != NULL && count < maxCount; list = list->next, count++) + for (auto inst : instances) { - QofInstance* inst = QOF_INSTANCE (list->data); (void)guid_to_string_buff (qof_instance_get_guid (inst), guid_buf); - if (!first_guid) + if (inst != *(instances.begin())) { - (void)g_string_append (sql, ","); + sql << ","; } - (void)g_string_append (sql, "'"); - (void)g_string_append (sql, guid_buf); - (void)g_string_append (sql, "'"); - first_guid = FALSE; + sql << "'" << guid_buf << "'"; } - return count; + return instances.size(); } /* ================================================================= */ static PairVec diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 35c3220589..10227c45f7 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -50,13 +50,17 @@ extern "C" #include #include #include +#include + +using uint_t = unsigned int; struct GncSqlColumnInfo; class GncSqlColumnTableEntry; using GncSqlColumnTableEntryPtr = std::shared_ptr; using EntryVec = std::vector; using ColVec = std::vector; using StrVec = std::vector; +using InstanceVec = std::vector; using PairVec = std::vector>; using VersionPair = std::pair; using VersionVec = std::vector; @@ -98,7 +102,7 @@ public: bool add_columns_to_table(const std::string& table_name, const EntryVec& col_table) const noexcept; unsigned int get_table_version(const std::string& table_name) const noexcept; - bool set_table_version (const std::string& table_name, unsigned int version) noexcept; + bool set_table_version (const std::string& table_name, uint_t version) noexcept; QofBook* book() const noexcept { return m_book; } bool pristine() const noexcept { return m_is_pristine_db; } @@ -946,8 +950,8 @@ GncSqlStatementPtr gnc_sql_create_select_statement (GncSqlBackend* be, * @param maxCount Max # of GUIDs to append * @return Number of GUIDs appended */ -guint gnc_sql_append_guid_list_to_sql (GString* str, GList* list, - guint maxCount); +uint_t gnc_sql_append_guids_to_sql (std::stringstream& sql, + const InstanceVec& instances); /** * Initializes DB table version information. diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index e4054d79c2..9b41b76337 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -240,22 +240,19 @@ GncSqlBillTermBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - GList* list = NULL; + InstanceVec instances; GList* l_billterms_needing_parents = NULL; for (auto row : *result) { auto pBillTerm = load_single_billterm (be, row, &l_billterms_needing_parents); - if (pBillTerm != NULL) - list = g_list_append (list, pBillTerm); + if (pBillTerm != nullptr) + instances.push_back(QOF_INSTANCE(pBillTerm)); } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec (be, instances); /* 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/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index 96aee9f71e..ddf05bdfa4 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -332,29 +332,23 @@ load_single_budget (GncSqlBackend* be, GncSqlRow& row) void GncSqlBudgetBackend::load_all (GncSqlBackend* be) { - GList* list = NULL; - + InstanceVec instances; g_return_if_fail (be != NULL); auto stmt = gnc_sql_create_select_statement (be, BUDGET_TABLE); - if (stmt != nullptr) - { - auto result = gnc_sql_execute_select_statement (be, stmt); - for (auto row : *result) - { - auto b = load_single_budget (be, row); - if (b != NULL) - { - list = g_list_prepend (list, b); - } - } + if (stmt == nullptr) + return; - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + auto result = gnc_sql_execute_select_statement (be, stmt); + for (auto row : *result) + { + auto b = load_single_budget (be, row); + if (b != nullptr) + instances.push_back(QOF_INSTANCE(b)); } + + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec (be, instances); } /* ================================================================= */ diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index de77b245e4..91e3c490a6 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -126,25 +126,19 @@ GncSqlCustomerBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - GList* list = NULL; + InstanceVec instances; for (auto row : *result) { GncCustomer* pCustomer = load_single_customer (be, row); - if (pCustomer != NULL) - { - list = g_list_append (list, pCustomer); - } + if (pCustomer != nullptr) + instances.push_back(QOF_INSTANCE(pCustomer)); } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec (be, instances); } /* ================================================================= */ diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index f295a5d386..a39e2ce6e9 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -115,23 +115,17 @@ GncSqlEmployeeBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - GList* list = NULL; + InstanceVec instances; for (auto row : *result) { GncEmployee* pEmployee = load_single_employee (be, row); - if (pEmployee != NULL) - { - list = g_list_append (list, pEmployee); - } - } - - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); + if (pEmployee != nullptr) + instances.push_back(QOF_INSTANCE(pEmployee)); } + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec (be, instances); } /* ================================================================= */ diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index 3f0623db80..f6d31ed9a4 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -196,22 +196,17 @@ GncSqlEntryBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - GList* list = NULL; + InstanceVec instances; for (auto row : *result) { GncEntry* pEntry = load_single_entry (be, row); - if (pEntry != NULL) - { - list = g_list_append (list, pEntry); - } + if (pEntry != nullptr) + instances.push_back(QOF_INSTANCE(pEntry)); } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec(be, instances); } /* ================================================================= */ diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index d6d8f5dff7..f1c14b2d03 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -135,22 +135,17 @@ GncSqlInvoiceBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - GList* list = NULL; + InstanceVec instances; for (auto row : *result) { GncInvoice* pInvoice = load_single_invoice (be, row); - if (pInvoice != NULL) - { - list = g_list_append (list, pInvoice); - } + if (pInvoice != nullptr) + instances.push_back(QOF_INSTANCE(pInvoice)); } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec (be, instances); } /* ================================================================= */ diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index cb03233dd0..019c30648f 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -107,22 +107,17 @@ GncSqlJobBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - GList* list = NULL; + InstanceVec instances; for (auto row : *result) { GncJob* pJob = load_single_job (be, row); - if (pJob != NULL) - { - list = g_list_append (list, pJob); - } + if (pJob != nullptr) + instances.push_back(QOF_INSTANCE(pJob)); } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec (be, instances); } /* ================================================================= */ diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index 8541bbe90a..7115f25702 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -107,22 +107,17 @@ GncSqlOrderBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - GList* list = NULL; + InstanceVec instances; for (auto row : *result) { GncOrder* pOrder = load_single_order (be, row); - if (pOrder != NULL) - { - list = g_list_append (list, pOrder); - } + if (pOrder != nullptr) + instances.push_back(QOF_INSTANCE(pOrder)); } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec (be, instances); } /* ================================================================= */ diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index 3eb6e3c590..82c6cac418 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -127,7 +127,7 @@ GncSqlSchedXactionBackend::load_all (GncSqlBackend* be) if (stmt == NULL) return; auto result = gnc_sql_execute_select_statement (be, stmt); SchedXactions* sxes; - GList* list = NULL; + InstanceVec instances; sxes = gnc_book_get_schedxactions (be->book()); for (auto row : *result) @@ -135,18 +135,15 @@ GncSqlSchedXactionBackend::load_all (GncSqlBackend* be) SchedXaction* sx; sx = load_single_sx (be, row); - if (sx != NULL) + if (sx != nullptr) { gnc_sxes_add_sx (sxes, sx); - list = g_list_prepend (list, sx); + instances.push_back(QOF_INSTANCE(sx)); } } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec (be, instances); } diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index c91f77c646..6c606286d3 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -886,50 +886,39 @@ load_slot_for_list_item (GncSqlBackend* be, GncSqlRow& row, } void -gnc_sql_slots_load_for_list (GncSqlBackend* be, GList* list) +gnc_sql_slots_load_for_instancevec (GncSqlBackend* be, InstanceVec& instances) { QofCollection* coll; - GString* sql; - gboolean single_item; + std::stringstream sql; g_return_if_fail (be != NULL); // Ignore empty list - if (list == NULL) return; + if (instances.empty()) return; - coll = qof_instance_get_collection (QOF_INSTANCE (list->data)); + coll = qof_instance_get_collection (instances[0]); // Create the query for all slots for all items on the list - sql = g_string_sized_new (40 + (GUID_ENCODING_LENGTH + 3) * g_list_length ( - list)); - g_string_append_printf (sql, "SELECT * FROM %s WHERE %s ", TABLE_NAME, - obj_guid_col_table[0]->name()); - if (g_list_length (list) != 1) - { - (void)g_string_append (sql, "IN ("); - single_item = FALSE; - } + + sql << "SELECT * FROM " << TABLE_NAME << " WHERE " << + obj_guid_col_table[0]->name(); + if (instances.size() != 1) + sql << " IN ("; else - { - (void)g_string_append (sql, "= "); - single_item = TRUE; - } - (void)gnc_sql_append_guid_list_to_sql (sql, list, G_MAXUINT); - if (!single_item) - { - (void)g_string_append (sql, ")"); - } + sql << " = "; + + gnc_sql_append_guids_to_sql (sql, instances); + if (instances.size() > 1) + sql << ")"; // Execute the query and load the slots - auto stmt = gnc_sql_create_statement_from_sql (be, sql->str); + auto stmt = be->create_statement_from_sql(sql.str()); if (stmt == nullptr) { - PERR ("stmt == NULL, SQL = '%s'\n", sql->str); - (void)g_string_free (sql, TRUE); + PERR ("stmt == NULL, SQL = '%s'\n", sql.str().c_str()); return; } - (void)g_string_free (sql, TRUE); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement (stmt); for (auto row : *result) load_slot_for_list_item (be, row, coll); } diff --git a/src/backend/sql/gnc-slots-sql.h b/src/backend/sql/gnc-slots-sql.h index 6690777599..e931edad30 100644 --- a/src/backend/sql/gnc-slots-sql.h +++ b/src/backend/sql/gnc-slots-sql.h @@ -64,14 +64,15 @@ gboolean gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid); void gnc_sql_slots_load (GncSqlBackend* be, QofInstance* inst); /** - * gnc_sql_slots_load_for_list - Loads slots for a list of objects from the db. - * Loading slots for a list of objects can be faster than loading for one object + * 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 be SQL backend * @param list List of objects */ -void gnc_sql_slots_load_for_list (GncSqlBackend* be, GList* list); +void gnc_sql_slots_load_for_instancevec (GncSqlBackend* be, + InstanceVec& instances); typedef QofInstance* (*BookLookupFn) (const GncGUID* guid, const QofBook* book); diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index e1300ad2db..a5f6334768 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -258,40 +258,31 @@ load_single_split (GncSqlBackend* be, GncSqlRow& row) } static void -load_splits_for_tx_list (GncSqlBackend* be, GList* list) +load_splits_for_tx_list (GncSqlBackend* be, InstanceVec& transactions) { - GString* sql; - g_return_if_fail (be != NULL); - if (list == NULL) return; + std::stringstream sql; - sql = g_string_sized_new (40 + (GUID_ENCODING_LENGTH + 3) * g_list_length ( - list)); - g_string_append_printf (sql, "SELECT * FROM %s WHERE %s IN (", SPLIT_TABLE, - tx_guid_col_table[0]->name()); - (void)gnc_sql_append_guid_list_to_sql (sql, list, G_MAXUINT); - (void)g_string_append (sql, ")"); + sql << "SELECT * FROM " << SPLIT_TABLE << " WHERE " << + tx_guid_col_table[0]->name() << " IN ("; + gnc_sql_append_guids_to_sql (sql, transactions); + sql << ")"; // Execute the query and load the splits - auto result = gnc_sql_execute_select_sql (be, sql->str); - GList* split_list = NULL; + auto stmt = be->create_statement_from_sql(sql.str()); + auto result = be->execute_select_statement (stmt); + InstanceVec instances; + for (auto row : *result) { - Split* s; - s = load_single_split (be, row); - if (s != NULL) - { - split_list = g_list_prepend (split_list, s); - } + Split* s = load_single_split (be, row); + if (s != nullptr) + instances.push_back(QOF_INSTANCE(s)); } - if (split_list != NULL) - { - gnc_sql_slots_load_for_list (be, split_list); - g_list_free (split_list); - } - (void)g_string_free (sql, TRUE); + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec (be, instances); } static Transaction* @@ -364,7 +355,6 @@ query_transactions (GncSqlBackend* be, const GncSqlStatementPtr& stmt) if (result->begin() == result->end()) return; - GList* tx_list = NULL; GList* node; Transaction* tx; #if LOAD_TRANSACTIONS_AS_NEEDED @@ -383,30 +373,27 @@ query_transactions (GncSqlBackend* be, const GncSqlStatementPtr& stmt) #endif // Load the transactions + InstanceVec instances; for (auto row : *result) { tx = load_single_tx (be, row); - if (tx != NULL) + if (tx != nullptr) { xaccTransScrubPostedDate (tx); - tx_list = g_list_prepend (tx_list, tx); + instances.push_back(QOF_INSTANCE(tx)); } } // Load all splits and slots for the transactions - if (tx_list != NULL) + if (!instances.empty()) { - gnc_sql_slots_load_for_list (be, tx_list); - load_splits_for_tx_list (be, tx_list); + gnc_sql_slots_load_for_instancevec (be, instances); + load_splits_for_tx_list (be, instances); } // Commit all of the transactions - for (node = tx_list; node != NULL; node = node->next) - { - Transaction* pTx = GNC_TRANSACTION (node->data); - xaccTransCommitEdit (pTx); - } - g_list_free (tx_list); + 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 diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index 6ee5035bb0..37d30701bb 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -117,20 +117,17 @@ GncSqlVendorBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); auto result = gnc_sql_execute_select_statement (be, stmt); - GList* list = NULL; + InstanceVec instances; for (auto row : *result) { GncVendor* pVendor = load_single_vendor (be, row); - if (pVendor != NULL) - list = g_list_append (list, pVendor); + if (pVendor != nullptr) + instances.push_back(QOF_INSTANCE(pVendor)); } - if (list != NULL) - { - gnc_sql_slots_load_for_list (be, list); - g_list_free (list); - } + if (!instances.empty()) + gnc_sql_slots_load_for_instancevec (be, instances); } /* ================================================================= */ From a303ae688afae1a972ad91a4aa4ea7cfdf6f79e6 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 24 Jul 2016 10:40:09 -0700 Subject: [PATCH 37/63] Remove some GList and GSList uses from tests. --- src/backend/dbi/gnc-dbisqlconnection.cpp | 2 +- .../dbi/test/test-backend-dbi-basic.cpp | 50 ++++++-------- .../sql/test/utest-gnc-backend-sql.cpp | 69 ------------------- 3 files changed, 23 insertions(+), 98 deletions(-) diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index 86b1678392..fabc26fbfe 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -523,7 +523,7 @@ GncDbiSqlConnection::table_manage_backup (const std::string& table_name, * * @param sql_conn: The sql connection (via dbi) to which the * transactions will be sent - * @param tables: GList of tables to operate on. + * @param table_namess: StrVec of tables to operate on. * @param op: The operation to perform. * @return Success (TRUE) or failure. */ diff --git a/src/backend/dbi/test/test-backend-dbi-basic.cpp b/src/backend/dbi/test/test-backend-dbi-basic.cpp index 7d57e4b3ac..816881f552 100644 --- a/src/backend/dbi/test/test-backend-dbi-basic.cpp +++ b/src/backend/dbi/test/test-backend-dbi-basic.cpp @@ -235,16 +235,6 @@ setup_business (Fixture* fixture, gconstpointer pData) fixture->filename = NULL; } -static void -drop_table (gconstpointer tdata, gconstpointer cdata) -{ - gchar* table = (gchar*)tdata; - dbi_conn conn = (dbi_conn)cdata; - gchar* query = g_strdup_printf ("DROP TABLE %s", table); - dbi_result rslt = dbi_conn_query (conn, query); - g_free (query); -} - static void destroy_database (gchar* url) { @@ -261,7 +251,7 @@ destroy_database (gchar* url) auto errfmt = "Unable to delete tables in %s: %s"; gint fail = 0; dbi_result tables; - GSList* list = NULL; + StrVec tblnames; gnc_uri_get_components (url, &protocol, &host, &portnum, &username, &password, &dbname); @@ -313,12 +303,16 @@ destroy_database (gchar* url) tables = dbi_conn_get_table_list (conn, dbname, NULL); while (dbi_result_next_row (tables) != 0) { - const gchar* table = dbi_result_get_string_idx (tables, 1); - list = g_slist_prepend (list, g_strdup (table)); + const std::string table{dbi_result_get_string_idx (tables, 1)}; + tblnames.push_back(table); } dbi_result_free (tables); - g_slist_foreach (list, (GFunc)drop_table, (gpointer)conn); - g_slist_free_full (list, (GDestroyNotify)g_free); + std::for_each(tblnames.begin(), tblnames.end(), + [conn](std::string table) { + std::string query{"DROP TABLE "}; + query += table; + dbi_result rslt = dbi_conn_query (conn, query.c_str()); + }); } static void @@ -654,8 +648,8 @@ create_dbi_test_suite (const char* dbm_name, const char* url) void test_suite_gnc_backend_dbi (void) { - dbi_driver driver = NULL; - GList* drivers = NULL; + dbi_driver driver = nullptr; + StrVec drivers; #if HAVE_LIBDBI_R if (dbi_instance == NULL) dbi_initialize_r (NULL, &dbi_instance); @@ -665,19 +659,19 @@ test_suite_gnc_backend_dbi (void) while ((driver = dbi_driver_list (driver))) #endif { - drivers = g_list_prepend (drivers, - (gchar*)dbi_driver_get_name (driver)); + drivers.push_back(dbi_driver_get_name (driver)); } - if (g_list_find_custom (drivers, "sqlite3", (GCompareFunc)g_strcmp0)) - create_dbi_test_suite ("sqlite3", "sqlite3"); - if (strlen (TEST_MYSQL_URL) > 0 && - g_list_find_custom (drivers, "mysql", (GCompareFunc)g_strcmp0)) - create_dbi_test_suite ("mysql", TEST_MYSQL_URL); - if (strlen (TEST_PGSQL_URL) > 0 && - g_list_find_custom (drivers, "pgsql", (GCompareFunc)g_strcmp0)) + for (auto name : drivers) { - g_setenv ("PGOPTIONS", "-c client_min_messages=WARNING", FALSE); - create_dbi_test_suite ("postgres", TEST_PGSQL_URL); + if (name == "sqlite3") + create_dbi_test_suite ("sqlite3", "sqlite3"); + if (strlen (TEST_MYSQL_URL) > 0 && name == "mysql") + create_dbi_test_suite ("mysql", TEST_MYSQL_URL); + if (strlen (TEST_PGSQL_URL) > 0 && name == "pgsql") + { + g_setenv ("PGOPTIONS", "-c client_min_messages=WARNING", FALSE); + create_dbi_test_suite ("postgres", TEST_PGSQL_URL); + } } GNC_TEST_ADD_FUNC( suitename, "adjust sql options string localtime", diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index d83eb5021e..c31070ad77 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -444,23 +444,6 @@ gnc_sql_get_getter (QofIdTypeConst obj_name, const GncSqlColumnTableEntry& table test_gnc_sql_get_getter (Fixture *fixture, gconstpointer pData) { }*/ -// Make Static -/* gnc_sql_add_colname_to_list -void -gnc_sql_add_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pList)// 9 -*/ -/* static void -test_gnc_sql_add_colname_to_list (Fixture *fixture, gconstpointer pData) -{ -}*/ -/* gnc_sql_add_subtable_colnames_to_list -void -gnc_sql_add_subtable_colnames_to_list (const GncSqlColumnTableEntry& table_row, const EntryVec& subtable, -GList** pList)// C: 1 */ -/* static void -test_gnc_sql_add_subtable_colnames_to_list (Fixture *fixture, gconstpointer pData) -{ -}*/ /* load_string static void load_string (const GncSqlBackend* be, GncSqlRow& row, @@ -470,24 +453,6 @@ const GncSqlColumnTableEntry& table_row)// 2 test_load_string (Fixture *fixture, gconstpointer pData) { }*/ -/* add_string_col_info_to_list -static void -add_string_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEntry& table_row, -GList** pList)// 2 -*/ -/* static void -test_add_string_col_info_to_list (Fixture *fixture, gconstpointer pData) -{ -}*/ -/* add_gvalue_string_to_slist -static void -add_gvalue_string_to_slist (const GncSqlBackend* be, QofIdTypeConst obj_name, -const gpointer pObject, const GncSqlColumnTableEntry& table_row, GSList** pList)// 2 -*/ -/* static void -test_add_gvalue_string_to_slist (Fixture *fixture, gconstpointer pData) -{ -}*/ /* load_int static void load_int (const GncSqlBackend* be, GncSqlRow& row,// 4 @@ -718,14 +683,6 @@ add_numeric_col_info_to_list (const GncSqlBackend* be, const GncSqlColumnTableEn test_add_numeric_col_info_to_list (Fixture *fixture, gconstpointer pData) { }*/ -/* add_numeric_colname_to_list -static void -add_numeric_colname_to_list (const GncSqlColumnTableEntry& table_row, GList** pList)// 2 -*/ -/* static void -test_add_numeric_colname_to_list (Fixture *fixture, gconstpointer pData) -{ -}*/ /* add_value_numeric_to_vec static void add_value_numeric_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name,// 2 @@ -818,13 +775,6 @@ execute_statement_get_count (GncSqlBackend* be, GncSqlStatement* stmt)// 2 test_execute_statement_get_count (Fixture *fixture, gconstpointer pData) { }*/ -/* gnc_sql_append_guid_list_to_sql -guint -gnc_sql_append_guid_list_to_sql (GString* sql, GList* list, guint maxCount)// C: 2 in 2 */ -/* static void -test_gnc_sql_append_guid_list_to_sql (Fixture *fixture, gconstpointer pData) -{ -}*/ /* gnc_sql_object_is_it_in_db gboolean gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name,// C: 1 */ @@ -839,14 +789,6 @@ gnc_sql_do_db_operation (GncSqlBackend* be,// C: 22 in 12 */ test_gnc_sql_do_db_operation (Fixture *fixture, gconstpointer pData) { }*/ -/* create_gslist_from_values -static GSList* -create_gslist_from_values (GncSqlBackend* be,// 3 -*/ -/* static void -test_create_gslist_from_values (Fixture *fixture, gconstpointer pData) -{ -}*/ /* gnc_sql_get_sql_value gchar* gnc_sql_get_sql_value (const GncSqlConnection* conn, const GValue* value)// C: 1 */ @@ -854,14 +796,6 @@ gnc_sql_get_sql_value (const GncSqlConnection* conn, const GValue* value)// C: 1 test_gnc_sql_get_sql_value (Fixture *fixture, gconstpointer pData) { }*/ -/* free_gvalue_list -static void -free_gvalue_list (GSList* list)// 4 -*/ -/* static void -test_free_gvalue_list (Fixture *fixture, gconstpointer pData) -{ -}*/ // Make Static /* build_insert_statement build_insert_statement (GncSqlBackend* be,// 3 @@ -1004,7 +938,6 @@ test_suite_gnc_backend_sql (void) // GNC_TEST_ADD (suitename, "get autoinc id", Fixture, nullptr, test_get_autoinc_id, teardown); // GNC_TEST_ADD (suitename, "set autoinc id", Fixture, nullptr, test_set_autoinc_id, teardown); // GNC_TEST_ADD (suitename, "gnc sql get getter", Fixture, nullptr, test_gnc_sql_get_getter, teardown); -// GNC_TEST_ADD (suitename, "gnc sql add colname to list", Fixture, nullptr, test_gnc_sql_add_colname_to_list, teardown); // GNC_TEST_ADD (suitename, "gnc sql add subtable colnames to list", Fixture, nullptr, test_gnc_sql_add_subtable_colnames_to_list, teardown); // GNC_TEST_ADD (suitename, "load string", Fixture, nullptr, test_load_string, teardown); // GNC_TEST_ADD (suitename, "add string col info to list", Fixture, nullptr, test_add_string_col_info_to_list, teardown); @@ -1054,9 +987,7 @@ test_suite_gnc_backend_sql (void) // GNC_TEST_ADD (suitename, "gnc sql append guid list to sql", Fixture, nullptr, test_gnc_sql_append_guid_list_to_sql, teardown); // GNC_TEST_ADD (suitename, "gnc sql object is it in db", Fixture, nullptr, test_gnc_sql_object_is_it_in_db, teardown); // GNC_TEST_ADD (suitename, "gnc sql do db operation", Fixture, nullptr, test_gnc_sql_do_db_operation, teardown); -// GNC_TEST_ADD (suitename, "create gslist from values", Fixture, nullptr, test_create_gslist_from_values, teardown); // GNC_TEST_ADD (suitename, "gnc sql get sql value", Fixture, nullptr, test_gnc_sql_get_sql_value, teardown); -// GNC_TEST_ADD (suitename, "free gvalue list", Fixture, nullptr, test_free_gvalue_list, teardown); // GNC_TEST_ADD (suitename, "build insert statement", Fixture, nullptr, test_build_insert_statement, teardown); // GNC_TEST_ADD (suitename, "build update statement", Fixture, nullptr, test_build_update_statement, teardown); // GNC_TEST_ADD (suitename, "build delete statement", Fixture, nullptr, test_build_delete_statement, teardown); From 54acef27c2b265f14364c1a47808899c644f6f66 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 24 Jul 2016 12:12:27 -0700 Subject: [PATCH 38/63] Remove a bunch of free functions already implemented as GncSqlBackend members. --- src/backend/dbi/gnc-backend-dbi.cpp | 6 +- src/backend/dbi/gnc-backend-dbi.hpp | 3 - src/backend/sql/gnc-account-sql.cpp | 2 +- src/backend/sql/gnc-backend-sql.cpp | 84 ++--------- src/backend/sql/gnc-backend-sql.h | 138 +++++++----------- src/backend/sql/gnc-bill-term-sql.cpp | 6 +- src/backend/sql/gnc-book-sql.cpp | 2 +- src/backend/sql/gnc-budget-sql.cpp | 14 +- src/backend/sql/gnc-commodity-sql.cpp | 2 +- src/backend/sql/gnc-customer-sql.cpp | 6 +- src/backend/sql/gnc-employee-sql.cpp | 6 +- src/backend/sql/gnc-entry-sql.cpp | 6 +- src/backend/sql/gnc-invoice-sql.cpp | 6 +- src/backend/sql/gnc-job-sql.cpp | 2 +- src/backend/sql/gnc-lots-sql.cpp | 6 +- src/backend/sql/gnc-order-sql.cpp | 2 +- src/backend/sql/gnc-price-sql.cpp | 6 +- src/backend/sql/gnc-recurrence-sql.cpp | 10 +- src/backend/sql/gnc-schedxaction-sql.cpp | 2 +- src/backend/sql/gnc-slots-sql.cpp | 33 ++--- src/backend/sql/gnc-tax-table-sql.cpp | 12 +- src/backend/sql/gnc-transaction-sql.cpp | 35 +++-- src/backend/sql/gnc-vendor-sql.cpp | 2 +- .../sql/test/utest-gnc-backend-sql.cpp | 25 ---- 24 files changed, 145 insertions(+), 271 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 86755d8320..b194b635bf 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -1301,16 +1301,14 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) gnc_sql_load (be, book, loadType); - if (GNUCASH_RESAVE_VERSION > gnc_sql_get_table_version (be, - "Gnucash")) + if (GNUCASH_RESAVE_VERSION > be->get_table_version("Gnucash")) { /* The database was loaded with an older database schema or * data semantics. In order to ensure consistency, the whole * thing needs to be saved anew. */ qof_backend_set_error (qbe, ERR_SQL_DB_TOO_OLD); } - else if (GNUCASH_RESAVE_VERSION < gnc_sql_get_table_version (be, - "Gnucash-Resave")) + else if (GNUCASH_RESAVE_VERSION < be->get_table_version("Gnucash-Resave")) { /* Worse, the database was created with a newer version. We * can't safely write to this database, so the user will have diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index acc7dad681..75e4c5e876 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -194,9 +194,6 @@ private: }; void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book); -std::string add_columns_ddl(const GncSqlConnection* conn, - const std::string& table_name, - const ColVec& info_vec); /* external access required for tests */ std::string adjust_sql_options_string(const std::string&); diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index 0831095db7..1ec57f5c8a 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -230,7 +230,7 @@ GncSqlAccountBackend::load_all (GncSqlBackend* be) LEAVE ("stmt == NULL"); return; } - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); for (auto row : *result) load_single_account (be, row, &l_accounts_needing_parents); diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 7d61bebce3..ade1a20299 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -503,6 +503,15 @@ GncSqlBackend::create_table(const std::string& table_name, } +bool +GncSqlBackend::create_table(const std::string& table_name, int table_version, + const EntryVec& col_table) noexcept +{ + if (create_table (table_name, col_table)) + return set_table_version (table_name, table_version); + return false; +} + bool GncSqlBackend::create_index(const std::string& index_name, const std::string& table_name, @@ -2003,7 +2012,7 @@ gnc_sql_create_select_statement (GncSqlBackend* be, const gchar* table_name) g_return_val_if_fail (table_name != NULL, NULL); auto sql = g_strdup_printf ("SELECT * FROM %s", table_name); - auto stmt = gnc_sql_create_statement_from_sql (be, sql); + auto stmt = be->create_statement_from_sql(sql); g_free (sql); return stmt; } @@ -2017,29 +2026,11 @@ create_single_col_select_statement (GncSqlBackend* be, g_return_val_if_fail (table_name != NULL, NULL); auto sql = std::string{"SELECT "} + table_row->name() + " FROM " + table_name; - return gnc_sql_create_statement_from_sql (be, sql.c_str()); + return be->create_statement_from_sql(sql.c_str()); } /* ================================================================= */ -GncSqlResultPtr -gnc_sql_execute_select_statement (GncSqlBackend* be, - const GncSqlStatementPtr& stmt) -{ - - g_return_val_if_fail (be != NULL, NULL); - - return be->execute_select_statement (stmt); -} - -GncSqlStatementPtr -gnc_sql_create_statement_from_sql (GncSqlBackend* be, const gchar* sql) -{ - g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (sql != NULL, NULL); - - return be->create_statement_from_sql (sql); -} GncSqlResultPtr gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) @@ -2047,7 +2038,7 @@ gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) g_return_val_if_fail (be != NULL, NULL); g_return_val_if_fail (sql != NULL, NULL); - auto stmt = gnc_sql_create_statement_from_sql (be, sql); + auto stmt = be->create_statement_from_sql(sql); if (stmt == nullptr) { return nullptr; @@ -2061,7 +2052,7 @@ gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql) g_return_val_if_fail (be != NULL, 0); g_return_val_if_fail (sql != NULL, 0); - auto stmt = gnc_sql_create_statement_from_sql (be, sql); + auto stmt = be->create_statement_from_sql(sql); if (stmt == NULL) { return -1; @@ -2122,11 +2113,10 @@ gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gchar* table_name, /* WHERE */ PairVec values{get_object_values(be, obj_name, pObject, table)}; stmt->add_where_cond(obj_name, values); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement (stmt); if (result != NULL) { auto retval = result->size() > 0; - delete result; return retval; } return false; @@ -2311,19 +2301,6 @@ GncSqlObjectBackend::commit (GncSqlBackend* be, QofInstance* inst) } /* ================================================================= */ - -gboolean -gnc_sql_create_table (GncSqlBackend* be, const gchar* table_name, - int table_version, const EntryVec& col_table) -{ - DEBUG ("Creating %s table\n", table_name); - - if (be->create_table (table_name, col_table)) - return be->set_table_version (table_name, table_version); - - return false; -} - void GncSqlObjectBackend::create_tables (GncSqlBackend* be) { @@ -2349,29 +2326,6 @@ gnc_sql_create_temp_table (const GncSqlBackend* be, const gchar* table_name, return be->create_table (table_name, col_table); } -gboolean -gnc_sql_create_index (const GncSqlBackend* be, const gchar* index_name, - const gchar* table_name, - const EntryVec& col_table) -{ - gboolean ok; - - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (index_name != NULL, FALSE); - g_return_val_if_fail (table_name != NULL, FALSE); - - ok = be->create_index (index_name, table_name, col_table); - return ok; -} - -gint -gnc_sql_get_table_version (const GncSqlBackend* be, const gchar* table_name) -{ - g_return_val_if_fail (be != NULL, 0); - g_return_val_if_fail (table_name != NULL, 0); - return be->get_table_version(table_name); -} - /* Create a temporary table, copy the data from the old table, delete the old table, then rename the new one. */ void @@ -2404,16 +2358,6 @@ gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name, g_free (temp_table_name); } -/* Adds one or more columns to an existing table. */ -gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const gchar* table_name, - const EntryVec& new_col_table) -{ - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (table_name != NULL, FALSE); - - return be->add_columns_to_table(table_name, new_col_table); -} - /* ================================================================= */ diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 10227c45f7..4fe36a206b 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -87,21 +87,70 @@ public: * destroys the version info. */ void connect(GncSqlConnection *conn) noexcept; + /** + * Initializes DB table version information. + * + * @param be SQL backend struct + */ void init_version_info() noexcept; bool reset_version_info() noexcept; + /** + * Finalizes DB table version information. + * + * @param be SQL backend struct + */ void finalize_version_info() noexcept; /* FIXME: These are just pass-throughs of m_conn functions. */ GncSqlStatementPtr create_statement_from_sql(const std::string& str) const noexcept; + /** Executes an SQL SELECT statement and returns the result rows. If an + * error occurs, an entry is added to the log, an error status is returned + * to qof and nullptr is returned. + * + * @param statement Statement + * @return Results, or nullptr if an error has occured + */ GncSqlResultPtr execute_select_statement(const GncSqlStatementPtr& stmt) const noexcept; int execute_nonselect_statement(const GncSqlStatementPtr& stmt) const noexcept; std::string quote_string(const std::string&) const noexcept; + /** + * Creates a table in the database + * + * @param table_name Table name + * @param col_table DB table description + * @return TRUE if successful, FALSE if unsuccessful + */ bool create_table(const std::string& table_name, const EntryVec& col_table) const noexcept; + /** + * Creates a table in the database and sets its version + * + * @param table_name Table name + * @param table_version Table version + * @param col_table DB table description + * @return TRUE if successful, FALSE if unsuccessful + */ + bool create_table(const std::string& table_name, int table_version, + const EntryVec& col_table) noexcept; + /** + * Creates an index in the database + * + * @param index_name Index name + * @param table_name Table name + * @param col_table Columns that the index should index + * @return TRUE if successful, FALSE if unsuccessful + */ bool create_index(const std::string& index_name, const std::string& table_name, const EntryVec& col_table) const noexcept; + /** + * Adds one or more columns to an existing table. + * + * @param table_name SQL table name + * @param new_col_table Column table for new columns + * @return TRUE if successful, FALSE if unsuccessful + */ bool add_columns_to_table(const std::string& table_name, const EntryVec& col_table) const noexcept; - unsigned int get_table_version(const std::string& table_name) const noexcept; + uint_t get_table_version(const std::string& table_name) const noexcept; bool set_table_version (const std::string& table_name, uint_t version) noexcept; QofBook* book() const noexcept { return m_book; } @@ -796,18 +845,6 @@ gboolean gnc_sql_do_db_operation (GncSqlBackend* be, gpointer pObject, const EntryVec& table); -/** - * Executes an SQL SELECT statement and returns the result rows. If an error - * occurs, an entry is added to the log, an error status is returned to qof and - * NULL is returned. - * - * @param be SQL backend struct - * @param statement Statement - * @return Results, or NULL if an error has occured - */ -GncSqlResultPtr gnc_sql_execute_select_statement (GncSqlBackend* be, - const GncSqlStatementPtr& statement); - /** * Executes an SQL SELECT statement from an SQL char string and returns the * result rows. If an error occurs, an entry is added to the log, an error @@ -828,16 +865,6 @@ GncSqlResultPtr gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) */ gint gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql); -/** - * Creates a statement from an SQL char string. - * - * @param be SQL backend struct - * @param sql SQL char string - * @return Statement - */ -GncSqlStatementPtr gnc_sql_create_statement_from_sql (GncSqlBackend* be, - const gchar* sql); - /** * Loads a Gnucash object from the database. * @@ -867,34 +894,6 @@ gboolean gnc_sql_object_is_it_in_db (GncSqlBackend* be, const gpointer pObject, const EntryVec& table ); -/** - * Returns the version number for a DB table. - * - * @param be SQL backend struct - * @param table_name Table name - * @return Version number, or 0 if the table does not exist - */ -gint gnc_sql_get_table_version (const GncSqlBackend* be, - const gchar* table_name); - -gboolean gnc_sql_set_table_version (GncSqlBackend* be, - const gchar* table_name, - gint version); - -/** - * Creates a table in the database - * - * @param be SQL backend struct - * @param table_name Table name - * @param table_version Table version - * @param col_table DB table description - * @return TRUE if successful, FALSE if unsuccessful - */ -gboolean gnc_sql_create_table (GncSqlBackend* be, - const gchar* table_name, - gint table_version, - const EntryVec& col_table); - /** * Creates a temporary table in the database. A temporary table does not * have a version number added to the versions table. @@ -908,18 +907,6 @@ gboolean gnc_sql_create_temp_table (const GncSqlBackend* be, const gchar* table_name, const EntryVec& col_table); -/** - * Creates an index in the database - * - * @param be SQL backend struct - * @param index_name Index name - * @param table_name Table name - * @param col_table Columns that the index should index - * @return TRUE if successful, FALSE if unsuccessful - */ -gboolean gnc_sql_create_index (const GncSqlBackend* be, const char* index_name, - const char* table_name, const EntryVec& col_table); - /** * Loads the object guid from a database row. The table must have a column * named "guid" with type CT_GUID. @@ -953,20 +940,6 @@ GncSqlStatementPtr gnc_sql_create_select_statement (GncSqlBackend* be, uint_t gnc_sql_append_guids_to_sql (std::stringstream& sql, const InstanceVec& instances); -/** - * Initializes DB table version information. - * - * @param be SQL backend struct - */ -void gnc_sql_init_version_info (GncSqlBackend* be); - -/** - * Finalizes DB table version information. - * - * @param be SQL backend struct - */ -void gnc_sql_finalize_version_info (GncSqlBackend* be); - /** * Converts a Timespec value to a string value for the database. * @@ -991,17 +964,6 @@ gchar* gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, void gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name, const EntryVec& col_table); -/** - * Adds one or more columns to an existing table. - * - * @param be SQL backend - * @param table_name SQL table name - * @param new_col_table Column table for new columns - * @return TRUE if successful, FALSE if unsuccessful - */ -gboolean gnc_sql_add_columns_to_table (GncSqlBackend* be, const char* table_name, - const EntryVec& new_col_table); - void _retrieve_guid_ (gpointer pObject, gpointer pValue); gpointer gnc_sql_compile_query (QofBackend* pBEnd, QofQuery* pQuery); diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index 9b41b76337..e01d9a8896 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -239,7 +239,7 @@ GncSqlBillTermBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); InstanceVec instances; GList* l_billterms_needing_parents = NULL; @@ -307,10 +307,10 @@ GncSqlBillTermBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TABLE_NAME); + version = be->get_table_version( TABLE_NAME); if (version == 0) { - gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); + be->create_table(TABLE_NAME, TABLE_VERSION, col_table); } else if (version == 1) { diff --git a/src/backend/sql/gnc-book-sql.cpp b/src/backend/sql/gnc-book-sql.cpp index 5e4b4b5d8f..2e339c87fd 100644 --- a/src/backend/sql/gnc-book-sql.cpp +++ b/src/backend/sql/gnc-book-sql.cpp @@ -174,7 +174,7 @@ GncSqlBookBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, BOOK_TABLE); if (stmt != nullptr) { - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); auto row = result->begin(); /* If there are no rows, try committing the book; unset diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index ddf05bdfa4..47a26341e5 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -214,11 +214,11 @@ load_budget_amounts (GncSqlBackend* be, GncBudget* budget) guid_buf); auto sql = g_strdup_printf ("SELECT * FROM %s WHERE budget_guid='%s'", AMOUNTS_TABLE, guid_buf); - auto stmt = gnc_sql_create_statement_from_sql (be, sql); + auto stmt = be->create_statement_from_sql(sql); g_free (sql); if (stmt != nullptr) { - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); budget_amount_info_t info = { budget, NULL, 0 }; for (auto row : *result) @@ -339,7 +339,7 @@ GncSqlBudgetBackend::load_all (GncSqlBackend* be) if (stmt == nullptr) return; - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); for (auto row : *result) { auto b = load_single_budget (be, row); @@ -359,16 +359,16 @@ GncSqlBudgetBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, BUDGET_TABLE); + version = be->get_table_version( BUDGET_TABLE); if (version == 0) { - (void)gnc_sql_create_table (be, BUDGET_TABLE, TABLE_VERSION, col_table); + (void)be->create_table(BUDGET_TABLE, TABLE_VERSION, col_table); } - version = gnc_sql_get_table_version (be, AMOUNTS_TABLE); + version = be->get_table_version( AMOUNTS_TABLE); if (version == 0) { - (void)gnc_sql_create_table (be, AMOUNTS_TABLE, AMOUNTS_TABLE_VERSION, + (void)be->create_table(AMOUNTS_TABLE, AMOUNTS_TABLE_VERSION, budget_amounts_col_table); } } diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index 7b1ca5bc77..864b6bf667 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -148,7 +148,7 @@ GncSqlCommodityBackend::load_all (GncSqlBackend* be) pTable = gnc_commodity_table_get_table (be->book()); auto stmt = gnc_sql_create_select_statement (be, COMMODITIES_TABLE); if (stmt == nullptr) return; - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); for (auto row : *result) { diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index 91e3c490a6..5dfbed6bec 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -127,7 +127,7 @@ GncSqlCustomerBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); InstanceVec instances; for (auto row : *result) @@ -149,10 +149,10 @@ GncSqlCustomerBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TABLE_NAME); + version = be->get_table_version( TABLE_NAME); if (version == 0) { - gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); + be->create_table(TABLE_NAME, TABLE_VERSION, col_table); } else if (version == 1) { diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index a39e2ce6e9..3922123a61 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -113,7 +113,7 @@ GncSqlEmployeeBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); InstanceVec instances; @@ -136,10 +136,10 @@ GncSqlEmployeeBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TABLE_NAME); + version = be->get_table_version( TABLE_NAME); if (version == 0) { - gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); + be->create_table(TABLE_NAME, TABLE_VERSION, col_table); } else if (version == 1) { diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index f6d31ed9a4..8d778cb0ff 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -195,7 +195,7 @@ GncSqlEntryBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); InstanceVec instances; for (auto row : *result) @@ -217,10 +217,10 @@ GncSqlEntryBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TABLE_NAME); + version = be->get_table_version( TABLE_NAME); if (version == 0) { - gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); + be->create_table(TABLE_NAME, TABLE_VERSION, col_table); } else if (version < TABLE_VERSION) { diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index f1c14b2d03..c31a15d1f9 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -134,7 +134,7 @@ GncSqlInvoiceBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); InstanceVec instances; for (auto row : *result) @@ -156,10 +156,10 @@ GncSqlInvoiceBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TABLE_NAME); + version = be->get_table_version( TABLE_NAME); if (version == 0) { - gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); + be->create_table(TABLE_NAME, TABLE_VERSION, col_table); } else if (version < TABLE_VERSION) { diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index 019c30648f..e8c0a86f4f 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -106,7 +106,7 @@ GncSqlJobBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); InstanceVec instances; for (auto row : *result) diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index ce4fcda627..893dcf7b68 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -130,7 +130,7 @@ GncSqlLotsBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); if (stmt != nullptr) { - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); if (result->begin () == nullptr) return; for (auto row : *result) @@ -151,11 +151,11 @@ GncSqlLotsBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TABLE_NAME); + version = be->get_table_version( TABLE_NAME); if (version == 0) { /* The table doesn't exist, so create it */ - (void)gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); + (void)be->create_table(TABLE_NAME, TABLE_VERSION, col_table); } else if (version == 1) { diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index 7115f25702..2159575a7b 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -106,7 +106,7 @@ GncSqlOrderBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); InstanceVec instances; for (auto row : *result) diff --git a/src/backend/sql/gnc-price-sql.cpp b/src/backend/sql/gnc-price-sql.cpp index 7974eaf228..0ab58c4d88 100644 --- a/src/backend/sql/gnc-price-sql.cpp +++ b/src/backend/sql/gnc-price-sql.cpp @@ -111,7 +111,7 @@ GncSqlPriceBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); if (stmt != nullptr) { - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); if (result->begin() == result->end()) return; @@ -145,10 +145,10 @@ GncSqlPriceBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TABLE_NAME); + version = be->get_table_version( TABLE_NAME); if (version == 0) { - (void)gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); + (void)be->create_table(TABLE_NAME, TABLE_VERSION, col_table); } else if (version == 1) { diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index 7ca09cafdd..cb79b6998e 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -323,7 +323,7 @@ gnc_sql_set_recurrences_from_db (GncSqlBackend* be, const GncGUID* guid) guid_buf); auto stmt = be->create_statement_from_sql (buf); g_free (buf); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); return result; } @@ -377,8 +377,8 @@ static void upgrade_recurrence_table_1_2 (GncSqlBackend* be) { /* Step 1: add field, but allow it to be null */ - gboolean ok = gnc_sql_add_columns_to_table (be, TABLE_NAME, - weekend_adjust_col_table); + gboolean ok = be->add_columns_to_table(TABLE_NAME, + weekend_adjust_col_table); if (!ok) { PERR ("Unable to add recurrence_weekend_adjust column\n"); @@ -410,10 +410,10 @@ GncSqlRecurrenceBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TABLE_NAME); + version = be->get_table_version( TABLE_NAME); if (version == 0) { - (void)gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); + (void)be->create_table(TABLE_NAME, TABLE_VERSION, col_table); } else if (version < TABLE_VERSION) { diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index 82c6cac418..53e7694605 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -125,7 +125,7 @@ GncSqlSchedXactionBackend::load_all (GncSqlBackend* be) auto stmt = gnc_sql_create_select_statement (be, SCHEDXACTION_TABLE); if (stmt == NULL) return; - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); SchedXactions* sxes; InstanceVec instances; sxes = gnc_book_get_schedxactions (be->book()); diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index 6c606286d3..195777b086 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -741,11 +741,11 @@ gnc_sql_slots_delete (GncSqlBackend* be, const GncGUID* guid) buf = g_strdup_printf ("SELECT * FROM %s WHERE obj_guid='%s' and slot_type in ('%d', '%d') and not guid_val is null", TABLE_NAME, guid_buf, KvpValue::Type::FRAME, KvpValue::Type::GLIST); - auto stmt = gnc_sql_create_statement_from_sql (be, buf); + auto stmt = be->create_statement_from_sql(buf); g_free (buf); if (stmt != nullptr) { - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); for (auto row : *result) { try @@ -824,7 +824,6 @@ gnc_sql_slots_load (GncSqlBackend* be, QofInstance* inst) static void slots_load_info (slot_info_t* pInfo) { - gchar* buf; gchar guid_buf[GUID_ENCODING_LENGTH + 1]; g_return_if_fail (pInfo != NULL); @@ -834,13 +833,13 @@ slots_load_info (slot_info_t* pInfo) (void)guid_to_string_buff (pInfo->guid, guid_buf); - buf = g_strdup_printf ("SELECT * FROM %s WHERE obj_guid='%s'", - TABLE_NAME, guid_buf); - auto stmt = gnc_sql_create_statement_from_sql (pInfo->be, buf); - g_free (buf); + std::stringstream buf; + buf << "SELECT * FROM " << TABLE_NAME << + " WHERE obj_guid='" << guid_buf << "'"; + auto stmt = pInfo->be->create_statement_from_sql (buf.str()); if (stmt != nullptr) { - auto result = gnc_sql_execute_select_statement (pInfo->be, stmt); + auto result = pInfo->be->execute_select_statement (stmt); for (auto row : *result) load_slot (pInfo, row); } @@ -976,7 +975,7 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be, subquery); // Execute the query and load the slots - auto stmt = gnc_sql_create_statement_from_sql (be, sql); + auto stmt = be->create_statement_from_sql(sql); if (stmt == nullptr) { PERR ("stmt == NULL, SQL = '%s'\n", sql); @@ -984,7 +983,7 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be, return; } g_free (sql); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); for (auto row : *result) load_slot_for_book_object (be, row, lookup_fn); } @@ -998,13 +997,13 @@ GncSqlSlotsBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TABLE_NAME); + version = be->get_table_version( TABLE_NAME); if (version == 0) { - (void)gnc_sql_create_table (be, TABLE_NAME, TABLE_VERSION, col_table); + (void)be->create_table(TABLE_NAME, TABLE_VERSION, col_table); - ok = gnc_sql_create_index (be, "slots_guid_index", TABLE_NAME, - obj_guid_col_table); + ok = be->create_index ("slots_guid_index", TABLE_NAME, + obj_guid_col_table); if (!ok) { PERR ("Unable to create index\n"); @@ -1019,8 +1018,8 @@ GncSqlSlotsBackend::create_tables (GncSqlBackend* be) if (version == 1) { gnc_sql_upgrade_table (be, TABLE_NAME, col_table); - ok = gnc_sql_create_index (be, "slots_guid_index", TABLE_NAME, - obj_guid_col_table); + ok = be->create_index ("slots_guid_index", TABLE_NAME, + obj_guid_col_table); if (!ok) { PERR ("Unable to create index\n"); @@ -1028,7 +1027,7 @@ GncSqlSlotsBackend::create_tables (GncSqlBackend* be) } else if (version == 2) { - ok = gnc_sql_add_columns_to_table (be, TABLE_NAME, gdate_col_table); + ok = be->add_columns_to_table(TABLE_NAME, gdate_col_table); if (!ok) { PERR ("Unable to add gdate column\n"); diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index 94d1f48cdf..eca590e014 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -239,7 +239,7 @@ load_taxtable_entries (GncSqlBackend* be, GncTaxTable* tt) TTENTRIES_TABLE_NAME, guid_buf); auto stmt = be->create_statement_from_sql (buf); g_free (buf); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); for (auto row : *result) load_single_ttentry (be, row, tt); } @@ -295,7 +295,7 @@ GncSqlTaxTableBackend::load_all (GncSqlBackend* be) /* First time, create the query */ auto stmt = gnc_sql_create_select_statement (be, TT_TABLE_NAME); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); GList* tt_needing_parents = NULL; for (auto row : *result) @@ -333,10 +333,10 @@ GncSqlTaxTableBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, TT_TABLE_NAME); + version = be->get_table_version( TT_TABLE_NAME); if (version == 0) { - gnc_sql_create_table (be, TT_TABLE_NAME, TT_TABLE_VERSION, tt_col_table); + be->create_table(TT_TABLE_NAME, TT_TABLE_VERSION, tt_col_table); } else if (version == 1) { @@ -347,10 +347,10 @@ GncSqlTaxTableBackend::create_tables (GncSqlBackend* be) TT_TABLE_VERSION); } - version = gnc_sql_get_table_version (be, TTENTRIES_TABLE_NAME); + version = be->get_table_version( TTENTRIES_TABLE_NAME); if (version == 0) { - gnc_sql_create_table (be, TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION, + be->create_table(TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION, ttentries_col_table); } else if (version == 1) diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index a5f6334768..74ddd1b576 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -351,7 +351,7 @@ query_transactions (GncSqlBackend* be, const GncSqlStatementPtr& stmt) g_return_if_fail (be != NULL); g_return_if_fail (stmt != NULL); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); if (result->begin() == result->end()) return; @@ -474,12 +474,12 @@ GncSqlTransBackend::create_tables (GncSqlBackend* be) g_return_if_fail (be != NULL); - version = gnc_sql_get_table_version (be, m_table_name.c_str()); + version = be->get_table_version( m_table_name.c_str()); if (version == 0) { - (void)gnc_sql_create_table (be, TRANSACTION_TABLE, TX_TABLE_VERSION, + (void)be->create_table(TRANSACTION_TABLE, TX_TABLE_VERSION, tx_col_table); - ok = gnc_sql_create_index (be, "tx_post_date_index", TRANSACTION_TABLE, + ok = be->create_index ("tx_post_date_index", TRANSACTION_TABLE, post_date_col_table); if (!ok) { @@ -503,15 +503,15 @@ GncSqlSplitBackend::create_tables (GncSqlBackend* be) { g_return_if_fail (be != nullptr); - auto version = gnc_sql_get_table_version (be, m_table_name.c_str()); + auto version = be->get_table_version( m_table_name.c_str()); if (version == 0) { - (void)gnc_sql_create_table (be, m_table_name.c_str(), + (void)be->create_table(m_table_name.c_str(), m_version, m_col_table); - if (!gnc_sql_create_index (be, "splits_tx_guid_index", + if (!be->create_index("splits_tx_guid_index", m_table_name.c_str(), tx_guid_col_table)) PERR ("Unable to create index\n"); - if (!gnc_sql_create_index (be, "splits_account_guid_index", + if (!be->create_index("splits_account_guid_index", m_table_name.c_str(), account_guid_col_table)) PERR ("Unable to create index\n"); @@ -523,11 +523,11 @@ GncSqlSplitBackend::create_tables (GncSqlBackend* be) 1->2: 64 bit int handling 3->4: Split reconcile date can be NULL */ gnc_sql_upgrade_table (be, m_table_name.c_str(), split_col_table); - if (!gnc_sql_create_index (be, "splits_tx_guid_index", + if (!be->create_index("splits_tx_guid_index", m_table_name.c_str(), tx_guid_col_table)) PERR ("Unable to create index\n"); - if (!gnc_sql_create_index (be, "splits_account_guid_index", + if (!be->create_index("splits_account_guid_index", m_table_name.c_str(), account_guid_col_table)) PERR ("Unable to create index\n"); @@ -761,7 +761,7 @@ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* be, 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 = gnc_sql_create_statement_from_sql (be, query_sql); + auto stmt = be->create_statement_from_sql(query_sql); g_free (query_sql); if (stmt != nullptr) { @@ -781,7 +781,7 @@ GncSqlTransBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); auto query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE); - auto stmt = gnc_sql_create_statement_from_sql (be, query_sql); + auto stmt = be->create_statement_from_sql(query_sql); g_free (query_sql); if (stmt != nullptr) { @@ -1166,7 +1166,7 @@ done_compiling_query: { query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE); } - query_info->stmt = gnc_sql_create_statement_from_sql (be, query_sql); + query_info->stmt = be->create_statement_from_sql(query_sql); g_string_free (sql, TRUE); g_free (query_sql); @@ -1175,7 +1175,7 @@ done_compiling_query: else { query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE); - query_info->stmt = gnc_sql_create_statement_from_sql (be, query_sql); + query_info->stmt = be->create_statement_from_sql(query_sql); g_free (query_sql); } @@ -1287,10 +1287,10 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be) 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 = gnc_sql_create_statement_from_sql (be, buf); + auto stmt = be->create_statement_from_sql(buf); g_assert (stmt != nullptr); g_free (buf); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); acct_balances_t* bal = NULL; for (auto row : *result) @@ -1383,8 +1383,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, { auto buf = std::string{"SELECT * FROM "} + TRANSACTION_TABLE + " WHERE guid='" + val + "'"; - auto stmt = gnc_sql_create_statement_from_sql ((GncSqlBackend*)be, - buf.c_str()); + auto stmt = be->create_statement_from_sql (buf); query_transactions ((GncSqlBackend*)be, stmt); tx = xaccTransLookup (&guid, be->book()); } diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index 37d30701bb..5aaa56bb75 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -116,7 +116,7 @@ GncSqlVendorBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - auto result = gnc_sql_execute_select_statement (be, stmt); + auto result = be->execute_select_statement(stmt); InstanceVec instances; for (auto row : *result) diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index c31070ad77..27d3817ef3 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -828,13 +828,6 @@ do_create_table (const GncSqlBackend* be, const gchar* table_name,// 5 test_do_create_table (Fixture *fixture, gconstpointer pData) { }*/ -/* gnc_sql_create_table -gboolean -gnc_sql_create_table (GncSqlBackend* be, const gchar* table_name,// C: 22 in 19 */ -/* static void -test_gnc_sql_create_table (Fixture *fixture, gconstpointer pData) -{ -}*/ // Make Static /* gnc_sql_create_temp_table gboolean @@ -851,13 +844,6 @@ gnc_sql_create_index (const GncSqlBackend* be, const gchar* index_name,// C: 7 i test_gnc_sql_create_index (Fixture *fixture, gconstpointer pData) { }*/ -/* gnc_sql_get_table_version -gint -gnc_sql_get_table_version (const GncSqlBackend* be, const gchar* table_name)// C: 24 in 20 */ -/* static void -test_gnc_sql_get_table_version (Fixture *fixture, gconstpointer pData) -{ -}*/ /* gnc_sql_upgrade_table void gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name,// C: 12 in 10 */ @@ -893,14 +879,6 @@ gnc_sql_finalize_version_info (GncSqlBackend* be)// C: 1 */ test_gnc_sql_finalize_version_info (Fixture *fixture, gconstpointer pData) { }*/ -/* gnc_sql_set_table_version -gboolean -gnc_sql_set_table_version (GncSqlBackend* be, const gchar* table_name, gint version)// C: 12 in 10 */ -/* static void -test_gnc_sql_set_table_version (Fixture *fixture, gconstpointer pData) -{ -}*/ - void test_suite_gnc_backend_sql (void) @@ -992,15 +970,12 @@ test_suite_gnc_backend_sql (void) // GNC_TEST_ADD (suitename, "build update statement", Fixture, nullptr, test_build_update_statement, teardown); // GNC_TEST_ADD (suitename, "build delete statement", Fixture, nullptr, test_build_delete_statement, teardown); // GNC_TEST_ADD (suitename, "do create table", Fixture, nullptr, test_do_create_table, teardown); -// GNC_TEST_ADD (suitename, "gnc sql create table", Fixture, nullptr, test_gnc_sql_create_table, teardown); // GNC_TEST_ADD (suitename, "gnc sql create temp table", Fixture, nullptr, test_gnc_sql_create_temp_table, teardown); // GNC_TEST_ADD (suitename, "gnc sql create index", Fixture, nullptr, test_gnc_sql_create_index, teardown); -// GNC_TEST_ADD (suitename, "gnc sql get table version", Fixture, nullptr, test_gnc_sql_get_table_version, teardown); // GNC_TEST_ADD (suitename, "gnc sql upgrade table", Fixture, nullptr, test_gnc_sql_upgrade_table, teardown); // GNC_TEST_ADD (suitename, "gnc sql add columns to table", Fixture, nullptr, test_gnc_sql_add_columns_to_table, teardown); // GNC_TEST_ADD (suitename, "gnc sql init version info", Fixture, nullptr, test_gnc_sql_init_version_info, teardown); // GNC_TEST_ADD (suitename, "reset version info", Fixture, nullptr, test_reset_version_info, teardown); // GNC_TEST_ADD (suitename, "gnc sql finalize version info", Fixture, nullptr, test_gnc_sql_finalize_version_info, teardown); -// GNC_TEST_ADD (suitename, "gnc sql set table version", Fixture, nullptr, test_gnc_sql_set_table_version, teardown); } From c2082bea99bdb5bf144daad675f155b34abeea79 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sun, 24 Jul 2016 15:16:15 -0700 Subject: [PATCH 39/63] Convert upgrade_table to member, remove some convenience functions. To wit, gnc_sql_execute_select_sql, gnc_sql_execute_nonselect_sql, gnc_sql_create_temp_table, and gnc_sql_create_select_statement. --- src/backend/sql/gnc-account-sql.cpp | 16 +- src/backend/sql/gnc-backend-sql.cpp | 156 ++++++------------ src/backend/sql/gnc-backend-sql.h | 144 ++++++---------- src/backend/sql/gnc-bill-term-sql.cpp | 6 +- src/backend/sql/gnc-book-sql.cpp | 4 +- src/backend/sql/gnc-budget-sql.cpp | 19 +-- src/backend/sql/gnc-commodity-sql.cpp | 5 +- src/backend/sql/gnc-customer-sql.cpp | 6 +- src/backend/sql/gnc-employee-sql.cpp | 6 +- src/backend/sql/gnc-entry-sql.cpp | 6 +- src/backend/sql/gnc-invoice-sql.cpp | 6 +- src/backend/sql/gnc-job-sql.cpp | 4 +- src/backend/sql/gnc-lots-sql.cpp | 6 +- src/backend/sql/gnc-order-sql.cpp | 4 +- src/backend/sql/gnc-price-sql.cpp | 6 +- src/backend/sql/gnc-recurrence-sql.cpp | 14 +- src/backend/sql/gnc-schedxaction-sql.cpp | 4 +- src/backend/sql/gnc-slots-sql.cpp | 2 +- src/backend/sql/gnc-tax-table-sql.cpp | 8 +- src/backend/sql/gnc-transaction-sql.cpp | 7 +- src/backend/sql/gnc-vendor-sql.cpp | 4 +- .../sql/test/utest-gnc-backend-sql.cpp | 27 ++- 22 files changed, 188 insertions(+), 272 deletions(-) diff --git a/src/backend/sql/gnc-account-sql.cpp b/src/backend/sql/gnc-account-sql.cpp index 1ec57f5c8a..5590ba342a 100644 --- a/src/backend/sql/gnc-account-sql.cpp +++ b/src/backend/sql/gnc-account-sql.cpp @@ -224,19 +224,17 @@ GncSqlAccountBackend::load_all (GncSqlBackend* be) pBook = be->book(); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); - if (stmt == nullptr) - { - LEAVE ("stmt == NULL"); - return; - } + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); for (auto row : *result) load_single_account (be, row, &l_accounts_needing_parents); - auto sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", TABLE_NAME); - gnc_sql_slots_load_for_sql_subquery (be, sql, (BookLookupFn)xaccAccountLookup); - g_free (sql); + sql.str(""); + sql << "SELECT DISTINCT guid FROM " << TABLE_NAME; + gnc_sql_slots_load_for_sql_subquery (be, sql.str().c_str(), + (BookLookupFn)xaccAccountLookup); /* While there are items on the list of accounts needing parents, try to see if the parent has now been loaded. Theory says that if diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index ade1a20299..1ba18bfb28 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -673,6 +673,50 @@ GncSqlBackend::set_table_version (const std::string& table_name, return true; } +void +GncSqlBackend::upgrade_table (const std::string& table_name, + const EntryVec& col_table) noexcept +{ + DEBUG ("Upgrading %s table\n", table_name.c_str()); + + auto temp_table_name = table_name + "_new"; + create_table (temp_table_name, col_table); + std::stringstream sql; + sql << "INSERT INTO " << temp_table_name << " SELECT * FROM " << table_name; + auto stmt = create_statement_from_sql(sql.str()); + execute_nonselect_statement(stmt); + + sql.str(""); + sql << "DROP TABLE " << table_name; + stmt = create_statement_from_sql(sql.str()); + execute_nonselect_statement(stmt); + + sql.str(""); + sql << "ALTER TABLE " << temp_table_name << " RENAME TO " << table_name; + stmt = create_statement_from_sql(sql.str()); + execute_nonselect_statement(stmt); +} + +/* This is required because we're passing be->timespace_format to + * g_strdup_printf. + */ +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +std::string +GncSqlBackend::time64_to_string (time64 t) const noexcept +{ + auto tm = gnc_gmtime (&t); + + auto year = tm->tm_year + 1900; + + auto datebuf = g_strdup_printf (m_timespec_format, + year, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + gnc_tm_free (tm); + std::string date{datebuf}; + g_free(datebuf); + return date; +} +#pragma GCC diagnostic warning "-Wformat-nonliteral" void gnc_sql_sync_all (GncSqlBackend* be, QofBook* book) @@ -1657,30 +1701,6 @@ typedef void (*TimespecSetterFunc) (const gpointer, Timespec*); #define TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" #define TIMESPEC_COL_SIZE (4+2+2+2+2+2) -/* This is required because we're passing be->timespace_format to - * g_strdup_printf. - */ -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -gchar* -gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, Timespec ts) -{ - time64 time; - struct tm* tm; - gint year; - gchar* datebuf; - - time = timespecToTime64 (ts); - tm = gnc_gmtime (&time); - - year = tm->tm_year + 1900; - - datebuf = g_strdup_printf (be->timespec_format(), - year, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - gnc_tm_free (tm); - return datebuf; -} -#pragma GCC diagnostic warning "-Wformat-nonliteral" - template<> void GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, GncSqlRow& row, @@ -1764,9 +1784,8 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, if (ts.tv_sec != 0 || ts.tv_nsec != 0) { - char* datebuf = gnc_sql_convert_timespec_to_string (be, ts); - vec.emplace_back (std::make_pair (std::string{m_col_name}, - std::string{datebuf})); + auto datebuf = be->time64_to_string (ts.tv_sec); + vec.emplace_back (std::make_pair (std::string{m_col_name}, datebuf)); return; } } @@ -2005,18 +2024,6 @@ gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow& row, } /* ================================================================= */ -GncSqlStatementPtr -gnc_sql_create_select_statement (GncSqlBackend* be, const gchar* table_name) -{ - g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (table_name != NULL, NULL); - - auto sql = g_strdup_printf ("SELECT * FROM %s", table_name); - auto stmt = be->create_statement_from_sql(sql); - g_free (sql); - return stmt; -} - static GncSqlStatementPtr create_single_col_select_statement (GncSqlBackend* be, const gchar* table_name, @@ -2031,35 +2038,6 @@ create_single_col_select_statement (GncSqlBackend* be, /* ================================================================= */ - -GncSqlResultPtr -gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql) -{ - g_return_val_if_fail (be != NULL, NULL); - g_return_val_if_fail (sql != NULL, NULL); - - auto stmt = be->create_statement_from_sql(sql); - if (stmt == nullptr) - { - return nullptr; - } - return be->execute_select_statement (stmt); -} - -gint -gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql) -{ - g_return_val_if_fail (be != NULL, 0); - g_return_val_if_fail (sql != NULL, 0); - - auto stmt = be->create_statement_from_sql(sql); - if (stmt == NULL) - { - return -1; - } - return be->execute_nonselect_statement (stmt); -} - uint_t gnc_sql_append_guids_to_sql (std::stringstream& sql, const InstanceVec& instances) { @@ -2316,48 +2294,6 @@ GncSqlObjectBackend::create_tables (GncSqlBackend* be) "Table creation aborted.", m_table_name.c_str(), m_version, version); } -gboolean -gnc_sql_create_temp_table (const GncSqlBackend* be, const gchar* table_name, - const EntryVec& col_table) -{ - g_return_val_if_fail (be != NULL, FALSE); - g_return_val_if_fail (table_name != NULL, FALSE); - - return be->create_table (table_name, col_table); -} - -/* Create a temporary table, copy the data from the old table, delete the - old table, then rename the new one. */ -void -gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name, - const EntryVec& col_table) -{ - gchar* sql; - gchar* temp_table_name; - - g_return_if_fail (be != NULL); - g_return_if_fail (table_name != NULL); - - DEBUG ("Upgrading %s table\n", table_name); - - temp_table_name = g_strdup_printf ("%s_new", table_name); - (void)gnc_sql_create_temp_table (be, temp_table_name, col_table); - sql = g_strdup_printf ("INSERT INTO %s SELECT * FROM %s", - temp_table_name, table_name); - (void)gnc_sql_execute_nonselect_sql (be, sql); - g_free (sql); - - sql = g_strdup_printf ("DROP TABLE %s", table_name); - (void)gnc_sql_execute_nonselect_sql (be, sql); - g_free (sql); - - sql = g_strdup_printf ("ALTER TABLE %s RENAME TO %s", temp_table_name, - table_name); - (void)gnc_sql_execute_nonselect_sql (be, sql); - g_free (sql); - g_free (temp_table_name); -} - /* ================================================================= */ diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 4fe36a206b..cdf72fc9a8 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -21,7 +21,7 @@ /** * @defgroup SQLBE SQL Backend Core - @{ + @{ */ /** @addtogroup Columns Columns @@ -112,13 +112,13 @@ public: GncSqlResultPtr execute_select_statement(const GncSqlStatementPtr& stmt) const noexcept; int execute_nonselect_statement(const GncSqlStatementPtr& stmt) const noexcept; std::string quote_string(const std::string&) const noexcept; - /** - * Creates a table in the database - * - * @param table_name Table name - * @param col_table DB table description - * @return TRUE if successful, FALSE if unsuccessful - */ + /** + * Creates a table in the database + * + * @param table_name Table name + * @param col_table DB table description + * @return TRUE if successful, FALSE if unsuccessful + */ bool create_table(const std::string& table_name, const EntryVec& col_table) const noexcept; /** * Creates a table in the database and sets its version @@ -150,8 +150,35 @@ public: */ bool add_columns_to_table(const std::string& table_name, const EntryVec& col_table) const noexcept; + /** + * Upgrades a table to a new structure. + * + * The upgrade is done by creating a new table with the new structure, + * SELECTing the old data into the new table, deleting the old table, then + * renaming the new table. Therefore, this will only work if the new table + * structure is similar enough to the old table that the SELECT will work. + * + * @param table_name SQL table name + * @param col_table Column table + */ + void upgrade_table (const std::string& table_name, + const EntryVec& col_table) noexcept; + /** + * Returns the version number for a DB table. + * + * @param table_name Table name + * @return Version number, or 0 if the table does not exist + */ uint_t get_table_version(const std::string& table_name) const noexcept; bool set_table_version (const std::string& table_name, uint_t version) noexcept; + /** + * Converts a time64 value to a string value for the database. + * + * @param t time64 to be converted. + * @return String representation of the Timespec + */ + std::string time64_to_string (time64 t) const noexcept; + QofBook* book() const noexcept { return m_book; } bool pristine() const noexcept { return m_is_pristine_db; } @@ -390,8 +417,8 @@ class GncSqlObjectBackend public: GncSqlObjectBackend (int version, const std::string& type, const std::string& table, const EntryVec& vec) : - m_table_name{table}, m_version{version}, m_type_name{type}, - m_col_table{vec} {} + m_table_name{table}, m_version{version}, m_type_name{type}, + m_col_table{vec} {} /** * Load all objects of m_type in the database into memory. * @param be The GncSqlBackend containing the database connection. @@ -592,21 +619,21 @@ public: QofIdTypeConst obj_name, gpointer pObject, T get_ref) const noexcept - { - g_return_if_fail (pObject != NULL); - - try { - GncGUID guid; - auto val = row.get_string_at_col (m_col_name); - (void)string_to_guid (val.c_str(), &guid); - auto target = get_ref(&guid); - if (target != nullptr) - set_parameter (pObject, target, get_setter(obj_name), - m_gobj_param_name); + g_return_if_fail (pObject != NULL); + + try + { + GncGUID guid; + auto val = row.get_string_at_col (m_col_name); + (void)string_to_guid (val.c_str(), &guid); + auto target = get_ref(&guid); + if (target != nullptr) + set_parameter (pObject, target, get_setter(obj_name), + m_gobj_param_name); + } + catch (std::invalid_argument) {} } - catch (std::invalid_argument) {} - } protected: template T @@ -676,7 +703,7 @@ public: gpointer pObject) const noexcept override; void add_to_table(const GncSqlBackend* be, ColVec& vec) const noexcept override; void add_to_query(const GncSqlBackend* be, QofIdTypeConst obj_name, - gpointer pObject, PairVec& vec) const noexcept override; + gpointer pObject, PairVec& vec) const noexcept override; }; template @@ -845,25 +872,6 @@ gboolean gnc_sql_do_db_operation (GncSqlBackend* be, gpointer pObject, const EntryVec& table); -/** - * Executes an SQL SELECT statement from an SQL char string and returns the - * result rows. If an error occurs, an entry is added to the log, an error - * status is returned to qof and NULL is returned. - * - * @param be SQL backend struct - * @param sql SQL SELECT string - * @return Results, or NULL if an error has occured - */ -GncSqlResultPtr gnc_sql_execute_select_sql (GncSqlBackend* be, const gchar* sql); - -/** - * Executes an SQL non-SELECT statement from an SQL char string. - * - * @param be SQL backend struct - * @param sql SQL non-SELECT string - * @returns Number of rows affected, or -1 if an error has occured - */ -gint gnc_sql_execute_nonselect_sql (GncSqlBackend* be, const gchar* sql); /** * Loads a Gnucash object from the database. @@ -893,20 +901,6 @@ gboolean gnc_sql_object_is_it_in_db (GncSqlBackend* be, QofIdTypeConst obj_name, const gpointer pObject, const EntryVec& table ); - -/** - * Creates a temporary table in the database. A temporary table does not - * have a version number added to the versions table. - * - * @param be SQL backend struct - * @param table_name Table name - * @param col_table DB table description - * @return TRUE if successful, FALSE if unsuccessful - */ -gboolean gnc_sql_create_temp_table (const GncSqlBackend* be, - const gchar* table_name, - const EntryVec& col_table); - /** * Loads the object guid from a database row. The table must have a column * named "guid" with type CT_GUID. @@ -919,16 +913,6 @@ gboolean gnc_sql_create_temp_table (const GncSqlBackend* be, const GncGUID* gnc_sql_load_guid (const GncSqlBackend* be, GncSqlRow& row); -/** - * Creates a basic SELECT statement for a table. - * - * @param be SQL backend struct - * @param table_name Table name - * @return Statement - */ -GncSqlStatementPtr gnc_sql_create_select_statement (GncSqlBackend* be, - const gchar* table_name); - /** * Appends the ascii strings for a list of GUIDs to the end of an SQL string. * @@ -940,30 +924,6 @@ GncSqlStatementPtr gnc_sql_create_select_statement (GncSqlBackend* be, uint_t gnc_sql_append_guids_to_sql (std::stringstream& sql, const InstanceVec& instances); -/** - * Converts a Timespec value to a string value for the database. - * - * @param be SQL backend - * @param ts Timespec to be converted - * @return String representation of the Timespec - */ -gchar* gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, - Timespec ts); - -/** - * Upgrades a table to a new structure. The upgrade is done by creating a new - * table with the new structure, SELECTing the old data into the new table, - * deleting the old table, then renaming the new table. Therefore, this will - * only work if the new table structure is similar enough to the old table that - * the SELECT will work. - * - * @param be SQL backend - * @param table_name SQL table name - * @param col_table Column table - */ -void gnc_sql_upgrade_table (GncSqlBackend* be, const gchar* table_name, - const EntryVec& col_table); - void _retrieve_guid_ (gpointer pObject, gpointer pValue); gpointer gnc_sql_compile_query (QofBackend* pBEnd, QofQuery* pQuery); @@ -1058,5 +1018,5 @@ GncSqlColumnTableEntry::add_value_to_vec(const GncSqlBackend* be, #endif /* GNC_BACKEND_SQL_H */ /** - @} end of the SQL Backend Core doxygen group + @} end of the SQL Backend Core doxygen group */ diff --git a/src/backend/sql/gnc-bill-term-sql.cpp b/src/backend/sql/gnc-bill-term-sql.cpp index e01d9a8896..2317992716 100644 --- a/src/backend/sql/gnc-bill-term-sql.cpp +++ b/src/backend/sql/gnc-bill-term-sql.cpp @@ -238,7 +238,9 @@ GncSqlBillTermBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); InstanceVec instances; GList* l_billterms_needing_parents = NULL; @@ -315,7 +317,7 @@ GncSqlBillTermBackend::create_tables (GncSqlBackend* be) else if (version == 1) { /* Upgrade 64 bit int handling */ - gnc_sql_upgrade_table (be, TABLE_NAME, col_table); + be->upgrade_table(TABLE_NAME, col_table); be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Billterms table upgraded from version 1 to version %d\n", diff --git a/src/backend/sql/gnc-book-sql.cpp b/src/backend/sql/gnc-book-sql.cpp index 2e339c87fd..3fd70df42b 100644 --- a/src/backend/sql/gnc-book-sql.cpp +++ b/src/backend/sql/gnc-book-sql.cpp @@ -171,7 +171,9 @@ GncSqlBookBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, BOOK_TABLE); + std::stringstream sql; + sql << "SELECT * FROM " << BOOK_TABLE; + auto stmt = be->create_statement_from_sql(sql.str()); if (stmt != nullptr) { auto result = be->execute_select_statement(stmt); diff --git a/src/backend/sql/gnc-budget-sql.cpp b/src/backend/sql/gnc-budget-sql.cpp index 47a26341e5..df8f2f539a 100644 --- a/src/backend/sql/gnc-budget-sql.cpp +++ b/src/backend/sql/gnc-budget-sql.cpp @@ -236,19 +236,19 @@ static gboolean delete_budget_amounts (GncSqlBackend* be, GncBudget* budget) { gchar guid_buf[GUID_ENCODING_LENGTH + 1]; - gchar* sql; g_return_val_if_fail (be != NULL, FALSE); g_return_val_if_fail (budget != NULL, FALSE); (void)guid_to_string_buff (qof_instance_get_guid (QOF_INSTANCE (budget)), guid_buf); - sql = g_strdup_printf ("DELETE FROM %s WHERE budget_guid='%s'", AMOUNTS_TABLE, - guid_buf); - (void)gnc_sql_execute_nonselect_sql (be, sql); - g_free (sql); + std::stringstream sql; + sql << "DELETE FROM " << AMOUNTS_TABLE << " WHERE budget_guid='"<< + guid_buf << "'"; + auto stmt = be->create_statement_from_sql(sql.str()); + be->execute_nonselect_statement(stmt); - return TRUE; + return true; } /** @@ -335,10 +335,9 @@ GncSqlBudgetBackend::load_all (GncSqlBackend* be) InstanceVec instances; g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, BUDGET_TABLE); - if (stmt == nullptr) - return; - + std::stringstream sql; + sql << "SELECT * FROM " << BUDGET_TABLE; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); for (auto row : *result) { diff --git a/src/backend/sql/gnc-commodity-sql.cpp b/src/backend/sql/gnc-commodity-sql.cpp index 864b6bf667..ca40e45962 100644 --- a/src/backend/sql/gnc-commodity-sql.cpp +++ b/src/backend/sql/gnc-commodity-sql.cpp @@ -146,8 +146,9 @@ GncSqlCommodityBackend::load_all (GncSqlBackend* be) gnc_commodity_table* pTable; pTable = gnc_commodity_table_get_table (be->book()); - auto stmt = gnc_sql_create_select_statement (be, COMMODITIES_TABLE); - if (stmt == nullptr) return; + std::stringstream sql; + sql << "SELECT * FROM " << COMMODITIES_TABLE; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); for (auto row : *result) diff --git a/src/backend/sql/gnc-customer-sql.cpp b/src/backend/sql/gnc-customer-sql.cpp index 5dfbed6bec..e398e51832 100644 --- a/src/backend/sql/gnc-customer-sql.cpp +++ b/src/backend/sql/gnc-customer-sql.cpp @@ -126,7 +126,9 @@ GncSqlCustomerBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); InstanceVec instances; @@ -157,7 +159,7 @@ GncSqlCustomerBackend::create_tables (GncSqlBackend* be) else if (version == 1) { /* Upgrade 64 bit int handling */ - gnc_sql_upgrade_table (be, TABLE_NAME, col_table); + be->upgrade_table(TABLE_NAME, col_table); be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Customers table upgraded from version 1 to version %d\n", diff --git a/src/backend/sql/gnc-employee-sql.cpp b/src/backend/sql/gnc-employee-sql.cpp index 3922123a61..188824f9c5 100644 --- a/src/backend/sql/gnc-employee-sql.cpp +++ b/src/backend/sql/gnc-employee-sql.cpp @@ -112,7 +112,9 @@ GncSqlEmployeeBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); InstanceVec instances; @@ -144,7 +146,7 @@ GncSqlEmployeeBackend::create_tables (GncSqlBackend* be) else if (version == 1) { /* Upgrade 64 bit int handling */ - gnc_sql_upgrade_table (be, TABLE_NAME, col_table); + be->upgrade_table(TABLE_NAME, col_table); be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Employees table upgraded from version 1 to version %d\n", diff --git a/src/backend/sql/gnc-entry-sql.cpp b/src/backend/sql/gnc-entry-sql.cpp index 8d778cb0ff..00dd649f2c 100644 --- a/src/backend/sql/gnc-entry-sql.cpp +++ b/src/backend/sql/gnc-entry-sql.cpp @@ -194,7 +194,9 @@ GncSqlEntryBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); InstanceVec instances; @@ -228,7 +230,7 @@ GncSqlEntryBackend::create_tables (GncSqlBackend* be) 1->2: 64 bit int handling 2->3: "entered" -> "date_entered", and it can be NULL */ - gnc_sql_upgrade_table (be, TABLE_NAME, col_table); + be->upgrade_table(TABLE_NAME, col_table); be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Entries table upgraded from version %d to version %d\n", version, diff --git a/src/backend/sql/gnc-invoice-sql.cpp b/src/backend/sql/gnc-invoice-sql.cpp index c31a15d1f9..a70c038344 100644 --- a/src/backend/sql/gnc-invoice-sql.cpp +++ b/src/backend/sql/gnc-invoice-sql.cpp @@ -133,7 +133,9 @@ GncSqlInvoiceBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); InstanceVec instances; @@ -167,7 +169,7 @@ GncSqlInvoiceBackend::create_tables (GncSqlBackend* be) 1->2: 64 bit int handling 2->3: invoice open date can be NULL */ - gnc_sql_upgrade_table (be, TABLE_NAME, col_table); + be->upgrade_table(TABLE_NAME, col_table); be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Invoices table upgraded from version %d to version %d\n", version, diff --git a/src/backend/sql/gnc-job-sql.cpp b/src/backend/sql/gnc-job-sql.cpp index e8c0a86f4f..9c9af586ce 100644 --- a/src/backend/sql/gnc-job-sql.cpp +++ b/src/backend/sql/gnc-job-sql.cpp @@ -105,7 +105,9 @@ GncSqlJobBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); InstanceVec instances; diff --git a/src/backend/sql/gnc-lots-sql.cpp b/src/backend/sql/gnc-lots-sql.cpp index 893dcf7b68..e9bbf3724b 100644 --- a/src/backend/sql/gnc-lots-sql.cpp +++ b/src/backend/sql/gnc-lots-sql.cpp @@ -127,7 +127,9 @@ GncSqlLotsBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); if (stmt != nullptr) { auto result = be->execute_select_statement(stmt); @@ -165,7 +167,7 @@ GncSqlLotsBackend::create_tables (GncSqlBackend* be) Create a temporary table, copy the data from the old table, delete the old table, then rename the new one. */ - gnc_sql_upgrade_table (be, TABLE_NAME, col_table); + be->upgrade_table(TABLE_NAME, col_table); be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Lots table upgraded from version 1 to version %d\n", TABLE_VERSION); diff --git a/src/backend/sql/gnc-order-sql.cpp b/src/backend/sql/gnc-order-sql.cpp index 2159575a7b..dce95833d4 100644 --- a/src/backend/sql/gnc-order-sql.cpp +++ b/src/backend/sql/gnc-order-sql.cpp @@ -105,7 +105,9 @@ GncSqlOrderBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); InstanceVec instances; diff --git a/src/backend/sql/gnc-price-sql.cpp b/src/backend/sql/gnc-price-sql.cpp index 0ab58c4d88..84450c93f0 100644 --- a/src/backend/sql/gnc-price-sql.cpp +++ b/src/backend/sql/gnc-price-sql.cpp @@ -108,7 +108,9 @@ GncSqlPriceBackend::load_all (GncSqlBackend* be) pBook = be->book(); pPriceDB = gnc_pricedb_get_db (pBook); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); if (stmt != nullptr) { auto result = be->execute_select_statement(stmt); @@ -153,7 +155,7 @@ GncSqlPriceBackend::create_tables (GncSqlBackend* be) else if (version == 1) { /* Upgrade 64 bit int handling */ - gnc_sql_upgrade_table (be, TABLE_NAME, col_table); + be->upgrade_table(TABLE_NAME, col_table); be->set_table_version (TABLE_NAME, TABLE_VERSION); PINFO ("Prices table upgraded from version 1 to version %d\n", TABLE_VERSION); diff --git a/src/backend/sql/gnc-recurrence-sql.cpp b/src/backend/sql/gnc-recurrence-sql.cpp index cb79b6998e..c863735f33 100644 --- a/src/backend/sql/gnc-recurrence-sql.cpp +++ b/src/backend/sql/gnc-recurrence-sql.cpp @@ -388,17 +388,17 @@ upgrade_recurrence_table_1_2 (GncSqlBackend* be) /* Step 2: insert a default value in the newly created column */ { gchar* weekend_adj_str = recurrenceWeekendAdjustToString (WEEKEND_ADJ_NONE); - gchar* update_query = g_strdup_printf ("UPDATE %s SET %s = '%s';", - TABLE_NAME, - weekend_adjust_col_table[0]->name(), - weekend_adj_str); - (void)gnc_sql_execute_nonselect_sql (be, update_query); + std::stringstream sql; + sql << "UPDATE " << TABLE_NAME << " SET " << + weekend_adjust_col_table[0]->name() << "='" << + weekend_adj_str << "'"; + auto stmt = be->create_statement_from_sql(sql.str()); + be->execute_nonselect_statement(stmt); g_free (weekend_adj_str); - g_free (update_query); } /* Step 3: rewrite the table, requiring the weekend_adj column to be non-null */ - gnc_sql_upgrade_table (be, TABLE_NAME, col_table); + be->upgrade_table(TABLE_NAME, col_table); } diff --git a/src/backend/sql/gnc-schedxaction-sql.cpp b/src/backend/sql/gnc-schedxaction-sql.cpp index 53e7694605..0705ec6a1f 100644 --- a/src/backend/sql/gnc-schedxaction-sql.cpp +++ b/src/backend/sql/gnc-schedxaction-sql.cpp @@ -123,7 +123,9 @@ GncSqlSchedXactionBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, SCHEDXACTION_TABLE); + std::stringstream sql; + sql << "SELECT * FROM " << SCHEDXACTION_TABLE; + auto stmt = be->create_statement_from_sql(sql.str()); if (stmt == NULL) return; auto result = be->execute_select_statement(stmt); SchedXactions* sxes; diff --git a/src/backend/sql/gnc-slots-sql.cpp b/src/backend/sql/gnc-slots-sql.cpp index 195777b086..05985eb972 100644 --- a/src/backend/sql/gnc-slots-sql.cpp +++ b/src/backend/sql/gnc-slots-sql.cpp @@ -1017,7 +1017,7 @@ GncSqlSlotsBackend::create_tables (GncSqlBackend* be) */ if (version == 1) { - gnc_sql_upgrade_table (be, TABLE_NAME, col_table); + be->upgrade_table(TABLE_NAME, col_table); ok = be->create_index ("slots_guid_index", TABLE_NAME, obj_guid_col_table); if (!ok) diff --git a/src/backend/sql/gnc-tax-table-sql.cpp b/src/backend/sql/gnc-tax-table-sql.cpp index eca590e014..da4beb0330 100644 --- a/src/backend/sql/gnc-tax-table-sql.cpp +++ b/src/backend/sql/gnc-tax-table-sql.cpp @@ -294,7 +294,9 @@ GncSqlTaxTableBackend::load_all (GncSqlBackend* be) g_return_if_fail (be != NULL); /* First time, create the query */ - auto stmt = gnc_sql_create_select_statement (be, TT_TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TT_TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); GList* tt_needing_parents = NULL; @@ -341,7 +343,7 @@ GncSqlTaxTableBackend::create_tables (GncSqlBackend* be) else if (version == 1) { /* Upgrade 64 bit int handling */ - gnc_sql_upgrade_table (be, TT_TABLE_NAME, tt_col_table); + be->upgrade_table(TT_TABLE_NAME, tt_col_table); be->set_table_version (TT_TABLE_NAME, TT_TABLE_VERSION); PINFO ("Taxtables table upgraded from version 1 to version %d\n", TT_TABLE_VERSION); @@ -356,7 +358,7 @@ GncSqlTaxTableBackend::create_tables (GncSqlBackend* be) else if (version == 1) { /* Upgrade 64 bit int handling */ - gnc_sql_upgrade_table (be, TTENTRIES_TABLE_NAME, ttentries_col_table); + be->upgrade_table(TTENTRIES_TABLE_NAME, ttentries_col_table); be->set_table_version (TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION); PINFO ("Taxtable entries table upgraded from version 1 to version %d\n", TTENTRIES_TABLE_VERSION); diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index 74ddd1b576..250c94daf0 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -492,7 +492,7 @@ GncSqlTransBackend::create_tables (GncSqlBackend* be) 1->2: 64 bit int handling 2->3: allow dates to be NULL */ - gnc_sql_upgrade_table (be, m_table_name.c_str(), tx_col_table); + be->upgrade_table(m_table_name.c_str(), tx_col_table); be->set_table_version (m_table_name.c_str(), m_version); PINFO ("Transactions table upgraded from version %d to version %d\n", version, m_version); @@ -522,7 +522,7 @@ GncSqlSplitBackend::create_tables (GncSqlBackend* be) /* Upgrade: 1->2: 64 bit int handling 3->4: Split reconcile date can be NULL */ - gnc_sql_upgrade_table (be, m_table_name.c_str(), split_col_table); + be->upgrade_table(m_table_name.c_str(), split_col_table); if (!be->create_index("splits_tx_guid_index", m_table_name.c_str(), tx_guid_col_table)) @@ -969,9 +969,8 @@ convert_query_term_to_sql (const GncSqlBackend* be, const gchar* fieldName, else if (g_strcmp0 (pPredData->type_name, QOF_TYPE_DATE) == 0) { query_date_t date_data = (query_date_t)pPredData; - gchar* datebuf; - datebuf = gnc_sql_convert_timespec_to_string (be, date_data->date); + auto datebuf = be->time64_to_string (date_data->date.tv_sec); g_string_append_printf (sql, "'%s'", datebuf); } diff --git a/src/backend/sql/gnc-vendor-sql.cpp b/src/backend/sql/gnc-vendor-sql.cpp index 5aaa56bb75..c429f465b6 100644 --- a/src/backend/sql/gnc-vendor-sql.cpp +++ b/src/backend/sql/gnc-vendor-sql.cpp @@ -115,7 +115,9 @@ GncSqlVendorBackend::load_all (GncSqlBackend* be) { g_return_if_fail (be != NULL); - auto stmt = gnc_sql_create_select_statement (be, TABLE_NAME); + std::stringstream sql; + sql << "SELECT * FROM " << TABLE_NAME; + auto stmt = be->create_statement_from_sql(sql.str()); auto result = be->execute_select_statement(stmt); InstanceVec instances; diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index 27d3817ef3..f2922c1812 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -591,31 +591,29 @@ gnc_sql_add_objectref_guid_col_info_to_list (const GncSqlBackend* be,// 1 test_gnc_sql_add_objectref_guid_col_info_to_list (Fixture *fixture, gconstpointer pData) { }*/ -/* gnc_sql_convert_timespec_to_string -gchar* -gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, Timespec ts)// C: 1 */ +/* GncDbiBackend::time64_to_string +std::string +GncDbiBackend::time64_to_string (time64 t)// C: 1 */ #define numtests 6 static void -test_gnc_sql_convert_timespec_to_string () +test_time64_to_string () { GncSqlBackend be {nullptr, nullptr, "%4d-%02d-%02d %02d:%02d:%02d"}; - const char* date[numtests] = {"1995-03-11 19:17:26", + const char* dates[numtests] = {"1995-03-11 19:17:26", "2001-04-20 11:44:07", "1964-02-29 09:15:23", "1959-04-02 00:00:00", "2043-11-22 05:32:45", "2153-12-18 01:15:30" }; - int i; - for (i = 0; i < numtests; i++) + + for (auto date : dates) { - Timespec ts = gnc_iso8601_to_timespec_gmt (date[i]); - gchar* datestr = gnc_sql_convert_timespec_to_string (&be, ts); - g_assert_cmpstr (date[i], == , datestr); - - g_free (datestr); + Timespec ts = gnc_iso8601_to_timespec_gmt (date); + auto datestr = be.time64_to_string (ts.tv_sec); + g_assert_cmpstr (date, == , datestr.c_str()); } } @@ -937,8 +935,8 @@ test_suite_gnc_backend_sql (void) // GNC_TEST_ADD (suitename, "add value guid to vec", Fixture, nullptr, test_add_value_guid_to_vec, teardown); // GNC_TEST_ADD (suitename, "gnc sql add gvalue objectref guid to slist", Fixture, nullptr, test_gnc_sql_add_objectref_guid_to_vec, teardown); // GNC_TEST_ADD (suitename, "gnc sql add objectref guid col info to list", Fixture, nullptr, test_gnc_sql_add_objectref_guid_col_info_to_list, teardown); - GNC_TEST_ADD_FUNC (suitename, "gnc sql convert timespec to string", - test_gnc_sql_convert_timespec_to_string); + GNC_TEST_ADD_FUNC (suitename, "GncDbiBackend time64 to string", + test_time64_to_string); // GNC_TEST_ADD (suitename, "load timespec", Fixture, nullptr, test_load_timespec, teardown); // GNC_TEST_ADD (suitename, "add timespec col info to list", Fixture, nullptr, test_add_timespec_col_info_to_list, teardown); // GNC_TEST_ADD (suitename, "add value timespec to vec", Fixture, nullptr, test_add_value_timespec_to_vec, teardown); @@ -970,7 +968,6 @@ test_suite_gnc_backend_sql (void) // GNC_TEST_ADD (suitename, "build update statement", Fixture, nullptr, test_build_update_statement, teardown); // GNC_TEST_ADD (suitename, "build delete statement", Fixture, nullptr, test_build_delete_statement, teardown); // GNC_TEST_ADD (suitename, "do create table", Fixture, nullptr, test_do_create_table, teardown); -// GNC_TEST_ADD (suitename, "gnc sql create temp table", Fixture, nullptr, test_gnc_sql_create_temp_table, teardown); // GNC_TEST_ADD (suitename, "gnc sql create index", Fixture, nullptr, test_gnc_sql_create_index, teardown); // GNC_TEST_ADD (suitename, "gnc sql upgrade table", Fixture, nullptr, test_gnc_sql_upgrade_table, teardown); // GNC_TEST_ADD (suitename, "gnc sql add columns to table", Fixture, nullptr, test_gnc_sql_add_columns_to_table, teardown); From ccc1cc49ab542fb96660d81af354e96c4a20c1e1 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 25 Jul 2016 11:29:30 -0700 Subject: [PATCH 40/63] Separate DBI classes into their own files. --- src/backend/dbi/CMakeLists.txt | 10 +- src/backend/dbi/Makefile.am | 9 +- src/backend/dbi/gnc-backend-dbi.cpp | 431 +---------------------- src/backend/dbi/gnc-backend-dbi.hpp | 140 +------- src/backend/dbi/gnc-dbiprovider.hpp | 55 +++ src/backend/dbi/gnc-dbiproviderimpl.hpp | 293 +++++++++++++++ src/backend/dbi/gnc-dbisqlconnection.cpp | 3 +- src/backend/dbi/gnc-dbisqlconnection.hpp | 87 +++++ src/backend/dbi/gnc-dbisqlresult.cpp | 187 ++++++++++ src/backend/dbi/gnc-dbisqlresult.hpp | 77 ++++ src/backend/dbi/test/CMakeLists.txt | 1 + src/backend/dbi/test/Makefile.am | 3 +- src/backend/sql/gnc-address-sql.cpp | 2 +- src/backend/sql/gnc-transaction-sql.cpp | 2 +- 14 files changed, 739 insertions(+), 561 deletions(-) create mode 100644 src/backend/dbi/gnc-dbiprovider.hpp create mode 100644 src/backend/dbi/gnc-dbiproviderimpl.hpp create mode 100644 src/backend/dbi/gnc-dbisqlresult.cpp create mode 100644 src/backend/dbi/gnc-dbisqlresult.hpp diff --git a/src/backend/dbi/CMakeLists.txt b/src/backend/dbi/CMakeLists.txt index be5fc155d5..af6147434f 100644 --- a/src/backend/dbi/CMakeLists.txt +++ b/src/backend/dbi/CMakeLists.txt @@ -5,10 +5,16 @@ ADD_SUBDIRECTORY(test) # Source file gncmod-backend-dbi.c does not appear to be use in Makefile.in, so not included here. SET (backend_dbi_SOURCES - gnc-backend-dbi.cpp gnc-dbisqlconnection.cpp + gnc-backend-dbi.cpp + gnc-dbisqlresult.cpp + gnc-dbisqlconnection.cpp ) SET (backend_dbi_noinst_HEADERS - gnc-backend-dbi.h gnc-backend-dbi.hpp + gnc-backend-dbi.h + gnc-backend-dbi.hpp + gnc-dbisqlresult.hpp + gnc-dbisqlconnection.hpp + gnc-dbiprovider.hpp ) # Add dependency on config.h diff --git a/src/backend/dbi/Makefile.am b/src/backend/dbi/Makefile.am index a2a2baaed2..800f5eec36 100644 --- a/src/backend/dbi/Makefile.am +++ b/src/backend/dbi/Makefile.am @@ -22,11 +22,16 @@ AM_CPPFLAGS = \ libgncmod_backend_dbi_la_SOURCES = \ gnc-backend-dbi.cpp \ - gnc-dbisqlconnection.cpp + gnc-dbisqlconnection.cpp \ + gnc-dbisqlresult.cpp noinst_HEADERS = \ gnc-backend-dbi.h \ - gnc-backend-dbi.hpp + gnc-backend-dbi.hpp \ + gnc-dbisqlconnection.hpp \ + gnc-dbisqlresult.hpp \ + gnc-dbiprovider.hpp \ + gnc-dbiproviderimpl.hpp libgncmod_backend_dbi_la_LDFLAGS = -shared -avoid-version libgncmod_backend_dbi_la_LIBADD = \ diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index b194b635bf..d23593239e 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -68,18 +68,17 @@ extern "C" #include "splint-defs.h" #endif - - /* For direct access to dbi data structs, sadly needed for datetime */ -#include } #include #include -#include #include #include "gnc-backend-dbi.h" #include "gnc-backend-dbi.hpp" +#include "gnc-dbisqlresult.hpp" +#include "gnc-dbisqlconnection.hpp" + #if PLATFORM(WINDOWS) #ifdef __STRICT_ANSI_UNSET__ #undef __STRICT_ANSI_UNSET__ @@ -99,6 +98,8 @@ static dbi_inst dbi_instance = nullptr; #define TRANSACTION_NAME "trans" static QofLogModule log_module = G_LOG_DOMAIN; +// gnc-dbiproviderimpl.hpp has templates that need log_module defined. +#include "gnc-dbiproviderimpl.hpp" static gchar lock_table[] = "gnclock"; @@ -117,28 +118,6 @@ static gboolean save_may_clobber_data (QofBackend* qbe); static GncDbiTestResult conn_test_dbi_library (dbi_conn conn); -enum class DbType -{ - DBI_SQLITE, - DBI_MYSQL, - DBI_PGSQL -}; - - -template -class GncDbiProviderImpl : public GncDbiProvider -{ -public: - std::string create_table_ddl(const GncSqlConnection* conn, - const std::string& table_name, - const ColVec& info_vec); - StrVec get_table_list(dbi_conn conn, - const std::string& dbname); - void append_col_def(std::string& ddl, const GncSqlColumnInfo& info); - StrVec get_index_list (dbi_conn conn); - void drop_index(dbi_conn conn, const std::string& index); -}; - template class QofDbiBackendProvider : public QofBackendProvider { @@ -957,7 +936,6 @@ pgsql_error_fn (dbi_conn conn, void* user_data) { PINFO ("DBI error: %s\n", msg); be->set_exists(false); - be->set_error (ERR_BACKEND_NO_SUCH_DB, 0, FALSE); } else if (g_strrstr (msg, "server closed the connection unexpectedly")) // Connection lost @@ -971,17 +949,23 @@ pgsql_error_fn (dbi_conn conn, void* user_data) be->set_error (ERR_BACKEND_CONN_LOST, 1, true); be->retry_connection(msg); } - else if (be->connected() && - (g_str_has_prefix (msg, "connection pointer is NULL") || - g_str_has_prefix (msg, "could not connect to server"))) // No connection + else if (g_str_has_prefix (msg, "connection pointer is NULL") || + g_str_has_prefix (msg, "could not connect to server")) // No connection { - be->set_error(ERR_BACKEND_CANT_CONNECT, 1, true); - be->retry_connection (msg); + + if (!be->connected()) + qof_backend_set_error((QofBackend*)be, ERR_BACKEND_CANT_CONNECT); + else + { + be->set_error(ERR_BACKEND_CANT_CONNECT, 1, true); + be->retry_connection (msg); + } } else { PERR ("DBI error: %s\n", msg); - be->set_error (ERR_BACKEND_MISC, 0, false); + if (be->connected()) + be->set_error (ERR_BACKEND_MISC, 0, false); } } @@ -1678,387 +1662,6 @@ gnc_module_finalize_backend_dbi (void) } /* --------------------------------------------------------- */ -GncSqlRow& -GncDbiSqlResult::IteratorImpl::operator++() -{ - int status = dbi_result_next_row (m_inst->m_dbi_result); - if (status) - return m_inst->m_row; - int error = m_inst->dberror(); - if (error == DBI_ERROR_BADIDX || error == 0) //ran off the end of the results - return m_inst->m_sentinel; - PERR("Error %d incrementing results iterator.", error); - qof_backend_set_error (m_inst->m_conn->qbe(), ERR_BACKEND_SERVER_ERR); - return m_inst->m_sentinel; -} - -int64_t -GncDbiSqlResult::IteratorImpl::get_int_at_col(const char* col) const -{ - auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); - if(type != DBI_TYPE_INTEGER) - throw (std::invalid_argument{"Requested integer from non-integer column."}); - return dbi_result_get_longlong (m_inst->m_dbi_result, col); -} - -float -GncDbiSqlResult::IteratorImpl::get_float_at_col(const char* col) const -{ - auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); - auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); - if(type != DBI_TYPE_DECIMAL || - (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE4) - throw (std::invalid_argument{"Requested float from non-float column."}); - gnc_push_locale (LC_NUMERIC, "C"); - auto retval = dbi_result_get_float(m_inst->m_dbi_result, col); - gnc_pop_locale (LC_NUMERIC); - return retval; -} - -double -GncDbiSqlResult::IteratorImpl::get_double_at_col(const char* col) const -{ - auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); - auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); - if(type != DBI_TYPE_DECIMAL || - (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE8) - throw (std::invalid_argument{"Requested double from non-double column."}); - gnc_push_locale (LC_NUMERIC, "C"); - auto retval = dbi_result_get_double(m_inst->m_dbi_result, col); - gnc_pop_locale (LC_NUMERIC); - return retval; -} - -std::string -GncDbiSqlResult::IteratorImpl::get_string_at_col(const char* col) const -{ - auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); - auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); - if(type != DBI_TYPE_STRING) - throw (std::invalid_argument{"Requested string from non-string column."}); - gnc_push_locale (LC_NUMERIC, "C"); - auto strval = dbi_result_get_string(m_inst->m_dbi_result, col); - if (strval == nullptr) - { - gnc_pop_locale (LC_NUMERIC); - throw (std::invalid_argument{"Column empty."}); - } - auto retval = std::string{strval}; - gnc_pop_locale (LC_NUMERIC); - return retval; -} -time64 -GncDbiSqlResult::IteratorImpl::get_time64_at_col (const char* col) const -{ - auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); - auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); - if (type != DBI_TYPE_DATETIME) - throw (std::invalid_argument{"Requested double from non-double column."}); - gnc_push_locale (LC_NUMERIC, "C"); -#if HAVE_LIBDBI_TO_LONGLONG - /* A less evil hack than the one equrie by libdbi-0.8, but - * still necessary to work around the same bug. - */ - auto retval = dbi_result_get_as_longlong(dbi_row->result, - col_name); -#else - /* A seriously evil hack to work around libdbi bug #15 - * https://sourceforge.net/p/libdbi/bugs/15/. When libdbi - * v0.9 is widely available this can be replaced with - * dbi_result_get_as_longlong. - * Note: 0.9 is available in Debian Jessie and Fedora 21. - */ - auto result = (dbi_result_t*) (m_inst->m_dbi_result); - auto row = dbi_result_get_currow (result); - auto idx = dbi_result_get_field_idx (result, col) - 1; - time64 retval = result->rows[row]->field_values[idx].d_datetime; - if (retval < MINTIME || retval > MAXTIME) - retval = 0; -#endif //HAVE_LIBDBI_TO_LONGLONG - gnc_pop_locale (LC_NUMERIC); - return retval; -} - - -/* --------------------------------------------------------- */ - -GncDbiSqlResult::~GncDbiSqlResult() -{ - int status = dbi_result_free (m_dbi_result); - - if (status == 0) - return; - - PERR ("Error %d in dbi_result_free() result.", dberror() ); - qof_backend_set_error (m_conn->qbe(), ERR_BACKEND_SERVER_ERR); -} - -GncSqlRow& -GncDbiSqlResult::begin() -{ - - if (m_dbi_result == nullptr || - dbi_result_get_numrows(m_dbi_result) == 0) - return m_sentinel; - int status = dbi_result_first_row(m_dbi_result); - if (status) - return m_row; - int error = dberror(); // - - if (error != DBI_ERROR_BADIDX) //otherwise just an empty result set - { - PERR ("Error %d in dbi_result_first_row()", dberror()); - qof_backend_set_error (m_conn->qbe(), ERR_BACKEND_SERVER_ERR); - } - return m_sentinel; -} - -uint64_t -GncDbiSqlResult::size() const noexcept -{ - return dbi_result_get_numrows(m_dbi_result); -} - -/* --------------------------------------------------------- */ - -template<> void -GncDbiProviderImpl::append_col_def(std::string& ddl, - const GncSqlColumnInfo& info) -{ - const char* type_name = nullptr; - - if (info.m_type == BCT_INT) - { - type_name = "integer"; - } - else if (info.m_type == BCT_INT64) - { - type_name = "bigint"; - } - else if (info.m_type == BCT_DOUBLE) - { - type_name = "float8"; - } - else if (info.m_type == BCT_STRING || info.m_type == BCT_DATE - || info.m_type == BCT_DATETIME) - { - type_name = "text"; - } - else - { - PERR ("Unknown column type: %d\n", info.m_type); - type_name = ""; - } - ddl += (info.m_name + " " + type_name); - if (info.m_size != 0) - { - ddl += "(" + std::to_string(info.m_size) + ")"; - } - if (info.m_primary_key) - { - ddl += " PRIMARY KEY"; - } - if (info.m_autoinc) - { - ddl += " AUTOINCREMENT"; - } - if (info.m_not_null) - { - ddl += " NOT NULL"; - } -} - -template std::string -GncDbiProviderImpl

::create_table_ddl (const GncSqlConnection* conn, - const std::string& table_name, - const ColVec& info_vec) -{ - std::string ddl; - unsigned int col_num = 0; - - g_return_val_if_fail (conn != nullptr, ddl); - ddl += "CREATE TABLE " + table_name + "("; - for (auto const& info : info_vec) - { - if (col_num++ != 0) - { - ddl += ", "; - } - append_col_def (ddl, info); - } - ddl += ")"; - - return ddl; -} - -template<> void -GncDbiProviderImpl::append_col_def (std::string& ddl, - const GncSqlColumnInfo& info) -{ - const char* type_name = nullptr; - - if (info.m_type == BCT_INT) - { - type_name = "integer"; - } - else if (info.m_type == BCT_INT64) - { - type_name = "bigint"; - } - else if (info.m_type == BCT_DOUBLE) - { - type_name = "double"; - } - else if (info.m_type == BCT_STRING) - { - type_name = "varchar"; - } - else if (info.m_type == BCT_DATE) - { - type_name = "date"; - } - else if (info.m_type == BCT_DATETIME) - { - type_name = "TIMESTAMP NULL DEFAULT 0"; - } - else - { - PERR ("Unknown column type: %d\n", info.m_type); - type_name = ""; - } - ddl += info.m_name + " " + type_name; - if (info.m_size != 0 && info.m_type == BCT_STRING) - { - ddl += "(" + std::to_string(info.m_size) + ")"; - } - if (info.m_unicode) - { - ddl += " CHARACTER SET utf8"; - } - if (info.m_primary_key) - { - ddl += " PRIMARY KEY"; - } - if (info.m_autoinc) - { - ddl += " AUTO_INCREMENT"; - } - if (info.m_not_null) - { - ddl += " NOT NULL"; - } -} - - -template<> void -GncDbiProviderImpl::append_col_def (std::string& ddl, - const GncSqlColumnInfo& info) -{ - const char* type_name = nullptr; - - if (info.m_type == BCT_INT) - { - if (info.m_autoinc) - { - type_name = "serial"; - } - else - { - type_name = "integer"; - } - } - else if (info.m_type == BCT_INT64) - { - type_name = "int8"; - } - else if (info.m_type == BCT_DOUBLE) - - { - type_name = "double precision"; - } - else if (info.m_type == BCT_STRING) - { - type_name = "varchar"; - } - else if (info.m_type == BCT_DATE) - { - type_name = "date"; - } - else if (info.m_type == BCT_DATETIME) - { - type_name = "timestamp without time zone"; - } - else - { - PERR ("Unknown column type: %d\n", info.m_type); - type_name = ""; - } - ddl += info.m_name + " " + type_name; - if (info.m_size != 0 && info.m_type == BCT_STRING) - { - ddl += "(" + std::to_string(info.m_size) + ")"; - } - if (info.m_primary_key) - { - ddl += " PRIMARY KEY"; - } - if (info.m_not_null) - { - ddl += " NOT NULL"; - } -} - -static StrVec -conn_get_table_list (dbi_conn conn, const std::string& dbname) -{ - StrVec retval; - auto tables = dbi_conn_get_table_list (conn, dbname.c_str(), nullptr); - while (dbi_result_next_row (tables) != 0) - { - std::string table_name {dbi_result_get_string_idx (tables, 1)}; - retval.push_back(table_name); - } - dbi_result_free (tables); - return retval; -} - -template<> StrVec -GncDbiProviderImpl::get_table_list (dbi_conn conn, - const std::string& dbname) -{ - /* Return the list, but remove the tables that sqlite3 adds for - * its own use. */ - auto list = conn_get_table_list (conn, dbname); - auto end = std::remove(list.begin(), list.end(), "sqlite_sequence"); - list.erase(end, list.end()); - return list; -} - -template<> StrVec -GncDbiProviderImpl::get_table_list (dbi_conn conn, - const std::string& dbname) -{ - return conn_get_table_list (conn, dbname); -} - -template<> StrVec -GncDbiProviderImpl::get_table_list (dbi_conn conn, - const std::string& dbname) -{ - auto list = conn_get_table_list (conn, dbname); - auto end = std::remove_if (list.begin(), list.end(), - [](std::string& table_name){ - return table_name == "sql_features" || - table_name == "sql_implementation_info" || - table_name == "sql_languages" || - table_name == "sql_packages" || - table_name == "sql_parts" || - table_name == "sql_sizing" || - table_name == "sql_sizing_profiles"; - }); - list.erase(end, list.end()); - return list; -} /** Users discovered a bug in some distributions of libdbi, where if * it is compiled on certain versions of gcc with the -ffast-math diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index 75e4c5e876..b959f51f15 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -34,7 +34,8 @@ extern "C" #define GETPID() getpid() #endif } -#include +#include "gnc-backend-sql.h" + #define GNC_HOST_NAME_MAX 255 /** @@ -67,20 +68,6 @@ typedef enum GNC_DBI_FAIL_TEST } GncDbiTestResult; -class GncDbiProvider -{ -public: - virtual ~GncDbiProvider() = default; - virtual std::string create_table_ddl(const GncSqlConnection* conn, - const std::string& table_name, - const ColVec& info_vec) = 0; - virtual std::vector get_table_list(dbi_conn conn, - const std::string& dbname) = 0; - virtual void append_col_def(std::string& ddl, - const GncSqlColumnInfo& info) = 0; - virtual std::vector get_index_list (dbi_conn conn) = 0; - virtual void drop_index(dbi_conn conn, const std::string& index) = 0; -}; /** * Implementations of GncSqlBackend. @@ -112,135 +99,12 @@ private: bool m_exists; // Does the database exist? }; -class GncDbiSqlConnection : public GncSqlConnection -{ -public: - GncDbiSqlConnection (GncDbiProvider* provider, QofBackend* qbe, - dbi_conn conn, const char* lock_table) : - m_qbe{qbe}, m_conn{conn}, m_provider{provider}, m_conn_ok{true}, - m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, m_retry{false}, - m_lock_table{lock_table} {} - ~GncDbiSqlConnection() override; - GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr&) - noexcept override; - int execute_nonselect_statement (const GncSqlStatementPtr&) - noexcept override; - GncSqlStatementPtr create_statement_from_sql (const std::string&) - const noexcept override; - bool does_table_exist (const std::string&) const noexcept override; - bool begin_transaction () noexcept override; - bool rollback_transaction () const noexcept override; - bool commit_transaction () const noexcept override; - bool create_table (const std::string&, const ColVec&) const noexcept override; - bool create_index (const std::string&, const std::string&, const EntryVec&) - const noexcept override; - bool add_columns_to_table (const std::string&, const ColVec&) - const noexcept override; - std::string quote_string (const std::string&) const noexcept override; - int dberror() const noexcept override { - return dbi_conn_error(m_conn, nullptr); } - QofBackend* qbe () const noexcept { return m_qbe; } - dbi_conn conn() const noexcept { return m_conn; } - GncDbiProvider* provider() { return m_provider; } - inline void set_error(int error, int repeat, bool retry) noexcept override - { - m_last_error = error; - m_error_repeat = repeat; - m_retry = retry; - } - inline void init_error() noexcept - { - set_error(ERR_BACKEND_NO_ERR, 0, false); - } - /** Check if the dbi connection is valid. If not attempt to re-establish it - * Returns TRUE is there is a valid connection in the end or FALSE otherwise - */ - bool verify() noexcept override; - bool retry_connection(const char* msg) noexcept override; - dbi_result table_manage_backup(const std::string& table_name, TableOpType op); - /* FIXME: These three friend functions should really be members, but doing - * that is too invasive just yet. */ - bool table_operation (const StrVec& table_name_list, - TableOpType op) noexcept; - std::string add_columns_ddl(const std::string& table_name, - const ColVec& info_vec) const noexcept; - friend void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book); - -private: - QofBackend* m_qbe; - dbi_conn m_conn; - GncDbiProvider* m_provider; - /** Used by the error handler routines to flag if the connection is ok to - * use - */ - bool m_conn_ok; - /** Code of the last error that occurred. This is set in the error callback - * function. - */ - int m_last_error; - /** Used in case of transient errors. After such error, another attempt at - * the original call is allowed. error_repeat tracks the number of attempts - * and can be used to prevent infinite loops. - */ - int m_error_repeat; - /** Signals the calling function that it should retry (the error handler - * detected transient error and managed to resolve it, but it can't run the - * original query) - */ - gboolean m_retry; - const char* m_lock_table; - void unlock_database(); - -}; void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book); /* external access required for tests */ std::string adjust_sql_options_string(const std::string&); -/** - * An iterable wrapper for dbi_result; allows using C++11 range for. - */ -class GncDbiSqlResult : public GncSqlResult -{ -public: - GncDbiSqlResult(const GncDbiSqlConnection* conn, dbi_result result) : - m_conn{conn}, m_dbi_result{result}, m_iter{this}, m_row{&m_iter}, - m_sentinel{nullptr} {} - ~GncDbiSqlResult(); - uint64_t size() const noexcept; - int dberror() { return m_conn->dberror(); } - GncSqlRow& begin(); - GncSqlRow& end() { return m_sentinel; } -protected: - class IteratorImpl : public GncSqlResult::IteratorImpl - { - public: - ~IteratorImpl() = default; - IteratorImpl(GncDbiSqlResult* inst) : m_inst{inst} {} - virtual GncSqlRow& operator++(); - virtual GncSqlRow& operator++(int) { return ++(*this); }; - virtual GncSqlResult* operator*() { return m_inst; } - virtual int64_t get_int_at_col (const char* col) const; - virtual float get_float_at_col (const char* col) const; - virtual double get_double_at_col (const char* col) const; - virtual std::string get_string_at_col (const char* col)const; - virtual time64 get_time64_at_col (const char* col) const; - virtual bool is_col_null(const char* col) const noexcept - { - return dbi_result_field_is_null(m_inst->m_dbi_result, col); - } - private: - GncDbiSqlResult* m_inst; - }; -private: - const GncDbiSqlConnection* m_conn; - dbi_result m_dbi_result; - IteratorImpl m_iter; - GncSqlRow m_row; - GncSqlRow m_sentinel; - -}; #endif //GNC_BACKEND_DBI_HPP diff --git a/src/backend/dbi/gnc-dbiprovider.hpp b/src/backend/dbi/gnc-dbiprovider.hpp new file mode 100644 index 0000000000..21d749e713 --- /dev/null +++ b/src/backend/dbi/gnc-dbiprovider.hpp @@ -0,0 +1,55 @@ +/******************************************************************** + * gnc-dbiprovider.cpp: Encapsulate differences among Dbi backends. * + * * + * Copyright 2016 John Ralls * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ + +#ifndef __GNC_DBIPROVIDER_HPP__ +#define __GNC_DBIPROVIDER_HPP__ + +extern "C" +{ +#include +} +#include +#include + +/** + * Provides the primary abstraction for different DBI backends. + */ +class GncSqlConnection; +struct GncSqlColumnInfo; +using ColVec=std::vector; + +class GncDbiProvider +{ +public: + virtual ~GncDbiProvider() = default; + virtual std::string create_table_ddl(const GncSqlConnection* conn, + const std::string& table_name, + const ColVec& info_vec) = 0; + virtual StrVec get_table_list(dbi_conn conn, const std::string& dbname) = 0; + virtual void append_col_def(std::string& ddl, + const GncSqlColumnInfo& info) = 0; + virtual StrVec get_index_list (dbi_conn conn) = 0; + virtual void drop_index(dbi_conn conn, const std::string& index) = 0; +}; + +#endif //__GNC_DBIPROVIDER_HPP__ diff --git a/src/backend/dbi/gnc-dbiproviderimpl.hpp b/src/backend/dbi/gnc-dbiproviderimpl.hpp new file mode 100644 index 0000000000..2b9103a381 --- /dev/null +++ b/src/backend/dbi/gnc-dbiproviderimpl.hpp @@ -0,0 +1,293 @@ +/************************************************************************ + * gnc-dbiproviderimpl.hpp: Encapsulate differences among Dbi backends. * + * * + * Copyright 2016 John Ralls * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\***********************************************************************/ +#ifndef __GNC_DBISQLPROVIDERIMPL_HPP__ +#define __GNC_DBISQLPROVIDERIMPL_HPP__ +#include +extern "C" +{ +#include +} +#include "gnc-backend-dbi.hpp" +#include "gnc-dbiprovider.hpp" + +enum class DbType +{ + DBI_SQLITE, + DBI_MYSQL, + DBI_PGSQL +}; + +template +class GncDbiProviderImpl : public GncDbiProvider +{ +public: + std::string create_table_ddl(const GncSqlConnection* conn, + const std::string& table_name, + const ColVec& info_vec); + StrVec get_table_list(dbi_conn conn, + const std::string& dbname); + void append_col_def(std::string& ddl, const GncSqlColumnInfo& info); + StrVec get_index_list (dbi_conn conn); + void drop_index(dbi_conn conn, const std::string& index); +}; + +template<> void +GncDbiProviderImpl::append_col_def(std::string& ddl, + const GncSqlColumnInfo& info) +{ + const char* type_name = nullptr; + + if (info.m_type == BCT_INT) + { + type_name = "integer"; + } + else if (info.m_type == BCT_INT64) + { + type_name = "bigint"; + } + else if (info.m_type == BCT_DOUBLE) + { + type_name = "float8"; + } + else if (info.m_type == BCT_STRING || info.m_type == BCT_DATE + || info.m_type == BCT_DATETIME) + { + type_name = "text"; + } + else + { + PERR ("Unknown column type: %d\n", info.m_type); + type_name = ""; + } + ddl += (info.m_name + " " + type_name); + if (info.m_size != 0) + { + ddl += "(" + std::to_string(info.m_size) + ")"; + } + if (info.m_primary_key) + { + ddl += " PRIMARY KEY"; + } + if (info.m_autoinc) + { + ddl += " AUTOINCREMENT"; + } + if (info.m_not_null) + { + ddl += " NOT NULL"; + } +} + +template std::string +GncDbiProviderImpl

::create_table_ddl (const GncSqlConnection* conn, + const std::string& table_name, + const ColVec& info_vec) +{ + std::string ddl; + unsigned int col_num = 0; + + g_return_val_if_fail (conn != nullptr, ddl); + ddl += "CREATE TABLE " + table_name + "("; + for (auto const& info : info_vec) + { + if (col_num++ != 0) + { + ddl += ", "; + } + append_col_def (ddl, info); + } + ddl += ")"; + + return ddl; +} + +template<> void +GncDbiProviderImpl::append_col_def (std::string& ddl, + const GncSqlColumnInfo& info) +{ + const char* type_name = nullptr; + + if (info.m_type == BCT_INT) + { + type_name = "integer"; + } + else if (info.m_type == BCT_INT64) + { + type_name = "bigint"; + } + else if (info.m_type == BCT_DOUBLE) + { + type_name = "double"; + } + else if (info.m_type == BCT_STRING) + { + type_name = "varchar"; + } + else if (info.m_type == BCT_DATE) + { + type_name = "date"; + } + else if (info.m_type == BCT_DATETIME) + { + type_name = "TIMESTAMP NULL DEFAULT 0"; + } + else + { + PERR ("Unknown column type: %d\n", info.m_type); + type_name = ""; + } + ddl += info.m_name + " " + type_name; + if (info.m_size != 0 && info.m_type == BCT_STRING) + { + ddl += "(" + std::to_string(info.m_size) + ")"; + } + if (info.m_unicode) + { + ddl += " CHARACTER SET utf8"; + } + if (info.m_primary_key) + { + ddl += " PRIMARY KEY"; + } + if (info.m_autoinc) + { + ddl += " AUTO_INCREMENT"; + } + if (info.m_not_null) + { + ddl += " NOT NULL"; + } +} + + +template<> void +GncDbiProviderImpl::append_col_def (std::string& ddl, + const GncSqlColumnInfo& info) +{ + const char* type_name = nullptr; + + if (info.m_type == BCT_INT) + { + if (info.m_autoinc) + { + type_name = "serial"; + } + else + { + type_name = "integer"; + } + } + else if (info.m_type == BCT_INT64) + { + type_name = "int8"; + } + else if (info.m_type == BCT_DOUBLE) + + { + type_name = "double precision"; + } + else if (info.m_type == BCT_STRING) + { + type_name = "varchar"; + } + else if (info.m_type == BCT_DATE) + { + type_name = "date"; + } + else if (info.m_type == BCT_DATETIME) + { + type_name = "timestamp without time zone"; + } + else + { + PERR ("Unknown column type: %d\n", info.m_type); + type_name = ""; + } + ddl += info.m_name + " " + type_name; + if (info.m_size != 0 && info.m_type == BCT_STRING) + { + ddl += "(" + std::to_string(info.m_size) + ")"; + } + if (info.m_primary_key) + { + ddl += " PRIMARY KEY"; + } + if (info.m_not_null) + { + ddl += " NOT NULL"; + } +} + +static StrVec +conn_get_table_list (dbi_conn conn, const std::string& dbname) +{ + StrVec retval; + auto tables = dbi_conn_get_table_list (conn, dbname.c_str(), nullptr); + while (dbi_result_next_row (tables) != 0) + { + std::string table_name {dbi_result_get_string_idx (tables, 1)}; + retval.push_back(table_name); + } + dbi_result_free (tables); + return retval; +} + +template<> StrVec +GncDbiProviderImpl::get_table_list (dbi_conn conn, + const std::string& dbname) +{ + /* Return the list, but remove the tables that sqlite3 adds for + * its own use. */ + auto list = conn_get_table_list (conn, dbname); + auto end = std::remove(list.begin(), list.end(), "sqlite_sequence"); + list.erase(end, list.end()); + return list; +} + +template<> StrVec +GncDbiProviderImpl::get_table_list (dbi_conn conn, + const std::string& dbname) +{ + return conn_get_table_list (conn, dbname); +} + +template<> StrVec +GncDbiProviderImpl::get_table_list (dbi_conn conn, + const std::string& dbname) +{ + auto list = conn_get_table_list (conn, dbname); + auto end = std::remove_if (list.begin(), list.end(), + [](std::string& table_name){ + return table_name == "sql_features" || + table_name == "sql_implementation_info" || + table_name == "sql_languages" || + table_name == "sql_packages" || + table_name == "sql_parts" || + table_name == "sql_sizing" || + table_name == "sql_sizing_profiles"; + }); + list.erase(end, list.end()); + return list; +} + +#endif //__GNC_DBISQLPROVIDERIMPL_HPP__ diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index fabc26fbfe..aa53d6a349 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -28,13 +28,12 @@ extern "C" #include #include } -#include "gnc-backend-dbi.hpp" +#include "gnc-dbisqlconnection.hpp" static QofLogModule log_module = G_LOG_DOMAIN; static const unsigned int DBI_MAX_CONN_ATTEMPTS = 5; - /* --------------------------------------------------------- */ class GncDbiSqlStatement : public GncSqlStatement { diff --git a/src/backend/dbi/gnc-dbisqlconnection.hpp b/src/backend/dbi/gnc-dbisqlconnection.hpp index 64aedb0d60..547ae2b295 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.hpp +++ b/src/backend/dbi/gnc-dbisqlconnection.hpp @@ -22,8 +22,95 @@ \********************************************************************/ #ifndef _GNC_DBISQLCONNECTION_HPP_ #define _GNC_DBISQLCONNECTION_HPP_ + +#include "gnc-backend-dbi.hpp" +#include "gnc-dbisqlresult.hpp" +#include "gnc-dbiprovider.hpp" + +class GncDbiProvider; + /** * Encapsulate a libdbi dbi_conn connection. */ +class GncDbiSqlConnection : public GncSqlConnection +{ +public: + GncDbiSqlConnection (GncDbiProvider* provider, QofBackend* qbe, + dbi_conn conn, const char* lock_table) : + m_qbe{qbe}, m_conn{conn}, m_provider{provider}, m_conn_ok{true}, + m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, m_retry{false}, + m_lock_table{lock_table} {} + ~GncDbiSqlConnection() override; + GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr&) + noexcept override; + int execute_nonselect_statement (const GncSqlStatementPtr&) + noexcept override; + GncSqlStatementPtr create_statement_from_sql (const std::string&) + const noexcept override; + bool does_table_exist (const std::string&) const noexcept override; + bool begin_transaction () noexcept override; + bool rollback_transaction () const noexcept override; + bool commit_transaction () const noexcept override; + bool create_table (const std::string&, const ColVec&) const noexcept override; + bool create_index (const std::string&, const std::string&, const EntryVec&) + const noexcept override; + bool add_columns_to_table (const std::string&, const ColVec&) + const noexcept override; + std::string quote_string (const std::string&) const noexcept override; + int dberror() const noexcept override { + return dbi_conn_error(m_conn, nullptr); } + QofBackend* qbe () const noexcept { return m_qbe; } + dbi_conn conn() const noexcept { return m_conn; } + GncDbiProvider* provider() { return m_provider; } + inline void set_error(int error, int repeat, bool retry) noexcept override + { + m_last_error = error; + m_error_repeat = repeat; + m_retry = retry; + } + inline void init_error() noexcept + { + set_error(ERR_BACKEND_NO_ERR, 0, false); + } + /** Check if the dbi connection is valid. If not attempt to re-establish it + * Returns TRUE is there is a valid connection in the end or FALSE otherwise + */ + bool verify() noexcept override; + bool retry_connection(const char* msg) noexcept override; + dbi_result table_manage_backup(const std::string& table_name, TableOpType op); + /* FIXME: These three friend functions should really be members, but doing + * that is too invasive just yet. */ + bool table_operation (const StrVec& table_name_list, + TableOpType op) noexcept; + std::string add_columns_ddl(const std::string& table_name, + const ColVec& info_vec) const noexcept; + friend void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book); + +private: + QofBackend* m_qbe; + dbi_conn m_conn; + GncDbiProvider* m_provider; + /** Used by the error handler routines to flag if the connection is ok to + * use + */ + bool m_conn_ok; + /** Code of the last error that occurred. This is set in the error callback + * function. + */ + int m_last_error; + /** Used in case of transient errors. After such error, another attempt at + * the original call is allowed. error_repeat tracks the number of attempts + * and can be used to prevent infinite loops. + */ + int m_error_repeat; + /** Signals the calling function that it should retry (the error handler + * detected transient error and managed to resolve it, but it can't run the + * original query) + */ + gboolean m_retry; + const char* m_lock_table; + void unlock_database(); + +}; #endif //_GNC_DBISQLCONNECTION_HPP_ diff --git a/src/backend/dbi/gnc-dbisqlresult.cpp b/src/backend/dbi/gnc-dbisqlresult.cpp new file mode 100644 index 0000000000..07e7fa3535 --- /dev/null +++ b/src/backend/dbi/gnc-dbisqlresult.cpp @@ -0,0 +1,187 @@ +/******************************************************************** + * gnc-dbisqlresult.cpp: Encapsulate libdbi dbi_result * + * * + * Copyright 2016 John Ralls * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ + +#include +extern "C" +{ +#include +#include +#include +/* For direct access to dbi data structs, sadly needed for datetime */ +#include +} +#include +#include +#include "gnc-dbisqlresult.hpp" +#include "gnc-dbisqlconnection.hpp" + +static QofLogModule log_module = G_LOG_DOMAIN; + +GncDbiSqlResult::~GncDbiSqlResult() +{ + int status = dbi_result_free (m_dbi_result); + + if (status == 0) + return; + + PERR ("Error %d in dbi_result_free() result.", m_conn->dberror() ); + qof_backend_set_error (m_conn->qbe(), ERR_BACKEND_SERVER_ERR); +} + +int +GncDbiSqlResult::dberror() const noexcept +{ + return m_conn->dberror(); +} + +GncSqlRow& +GncDbiSqlResult::begin() +{ + + if (m_dbi_result == nullptr || + dbi_result_get_numrows(m_dbi_result) == 0) + return m_sentinel; + int status = dbi_result_first_row(m_dbi_result); + if (status) + return m_row; + int error = dberror(); // + + if (error != DBI_ERROR_BADIDX) //otherwise just an empty result set + { + PERR ("Error %d in dbi_result_first_row()", dberror()); + qof_backend_set_error (m_conn->qbe(), ERR_BACKEND_SERVER_ERR); + } + return m_sentinel; +} + +uint64_t +GncDbiSqlResult::size() const noexcept +{ + return dbi_result_get_numrows(m_dbi_result); +} +/* --------------------------------------------------------- */ + +GncSqlRow& +GncDbiSqlResult::IteratorImpl::operator++() +{ + int status = dbi_result_next_row (m_inst->m_dbi_result); + if (status) + return m_inst->m_row; + int error = m_inst->dberror(); + if (error == DBI_ERROR_BADIDX || error == 0) //ran off the end of the results + return m_inst->m_sentinel; + PERR("Error %d incrementing results iterator.", error); + qof_backend_set_error (m_inst->m_conn->qbe(), ERR_BACKEND_SERVER_ERR); + return m_inst->m_sentinel; +} + +int64_t +GncDbiSqlResult::IteratorImpl::get_int_at_col(const char* col) const +{ + auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); + if(type != DBI_TYPE_INTEGER) + throw (std::invalid_argument{"Requested integer from non-integer column."}); + return dbi_result_get_longlong (m_inst->m_dbi_result, col); +} + +float +GncDbiSqlResult::IteratorImpl::get_float_at_col(const char* col) const +{ + auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); + auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); + if(type != DBI_TYPE_DECIMAL || + (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE4) + throw (std::invalid_argument{"Requested float from non-float column."}); + gnc_push_locale (LC_NUMERIC, "C"); + auto retval = dbi_result_get_float(m_inst->m_dbi_result, col); + gnc_pop_locale (LC_NUMERIC); + return retval; +} + +double +GncDbiSqlResult::IteratorImpl::get_double_at_col(const char* col) const +{ + auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); + auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); + if(type != DBI_TYPE_DECIMAL || + (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE8) + throw (std::invalid_argument{"Requested double from non-double column."}); + gnc_push_locale (LC_NUMERIC, "C"); + auto retval = dbi_result_get_double(m_inst->m_dbi_result, col); + gnc_pop_locale (LC_NUMERIC); + return retval; +} + +std::string +GncDbiSqlResult::IteratorImpl::get_string_at_col(const char* col) const +{ + auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); + auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); + if(type != DBI_TYPE_STRING) + throw (std::invalid_argument{"Requested string from non-string column."}); + gnc_push_locale (LC_NUMERIC, "C"); + auto strval = dbi_result_get_string(m_inst->m_dbi_result, col); + if (strval == nullptr) + { + gnc_pop_locale (LC_NUMERIC); + throw (std::invalid_argument{"Column empty."}); + } + auto retval = std::string{strval}; + gnc_pop_locale (LC_NUMERIC); + return retval; +} +time64 +GncDbiSqlResult::IteratorImpl::get_time64_at_col (const char* col) const +{ + auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); + auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); + if (type != DBI_TYPE_DATETIME) + throw (std::invalid_argument{"Requested double from non-double column."}); + gnc_push_locale (LC_NUMERIC, "C"); +#if HAVE_LIBDBI_TO_LONGLONG + /* A less evil hack than the one equrie by libdbi-0.8, but + * still necessary to work around the same bug. + */ + auto retval = dbi_result_get_as_longlong(dbi_row->result, + col_name); +#else + /* A seriously evil hack to work around libdbi bug #15 + * https://sourceforge.net/p/libdbi/bugs/15/. When libdbi + * v0.9 is widely available this can be replaced with + * dbi_result_get_as_longlong. + * Note: 0.9 is available in Debian Jessie and Fedora 21. + */ + auto result = (dbi_result_t*) (m_inst->m_dbi_result); + auto row = dbi_result_get_currow (result); + auto idx = dbi_result_get_field_idx (result, col) - 1; + time64 retval = result->rows[row]->field_values[idx].d_datetime; + if (retval < MINTIME || retval > MAXTIME) + retval = 0; +#endif //HAVE_LIBDBI_TO_LONGLONG + gnc_pop_locale (LC_NUMERIC); + return retval; +} + + +/* --------------------------------------------------------- */ + diff --git a/src/backend/dbi/gnc-dbisqlresult.hpp b/src/backend/dbi/gnc-dbisqlresult.hpp new file mode 100644 index 0000000000..acb658d9e0 --- /dev/null +++ b/src/backend/dbi/gnc-dbisqlresult.hpp @@ -0,0 +1,77 @@ +/******************************************************************** + * gnc-dbisqlresult.hpp: Iterable wrapper for dbi_result. * + * * + * Copyright 2016 John Ralls m_dbi_result, col); + } + private: + GncDbiSqlResult* m_inst; + }; + +private: + const GncDbiSqlConnection* m_conn; + dbi_result m_dbi_result; + IteratorImpl m_iter; + GncSqlRow m_row; + GncSqlRow m_sentinel; + +}; + +#endif //__GNC_DBISQLRESULT_HPP__ diff --git a/src/backend/dbi/test/CMakeLists.txt b/src/backend/dbi/test/CMakeLists.txt index cc09d9dfe0..68c859cc84 100644 --- a/src/backend/dbi/test/CMakeLists.txt +++ b/src/backend/dbi/test/CMakeLists.txt @@ -20,6 +20,7 @@ SET(test_dbi_backend_SOURCES test-dbi-stuff.cpp ../gnc-backend-dbi.cpp ../gnc-dbisqlconnection.cpp + ../gnc-dbisqlresult.cpp ) # This test does not work on Win32 diff --git a/src/backend/dbi/test/Makefile.am b/src/backend/dbi/test/Makefile.am index cd6a5f44a4..50c5fb5113 100644 --- a/src/backend/dbi/test/Makefile.am +++ b/src/backend/dbi/test/Makefile.am @@ -62,7 +62,8 @@ test_backend_dbi_SOURCES = \ test-dbi-stuff.cpp \ test-dbi-business-stuff.cpp \ ../gnc-dbisqlconnection.cpp \ - ../gnc-backend-dbi.cpp + ../gnc-backend-dbi.cpp \ + ../gnc-dbisqlresult.cpp test_backend_dbi_CPPFLAGS = \ -DDBI_TEST_XML_FILENAME=\"${srcdir}/test-dbi.xml\" \ diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index c60ff7223d..cd6dd70220 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -84,7 +84,7 @@ GncSqlColumnTableEntryImpl::load (const GncSqlBackend* be, g_return_if_fail (be != NULL); g_return_if_fail (pObject != NULL); - auto addr = gncAddressCreate (be->book, QOF_INSTANCE(pObject)); + auto addr = gncAddressCreate (be->book(), QOF_INSTANCE(pObject)); for (auto const& subtable_row : col_table) { diff --git a/src/backend/sql/gnc-transaction-sql.cpp b/src/backend/sql/gnc-transaction-sql.cpp index 250c94daf0..1ac88aec0b 100644 --- a/src/backend/sql/gnc-transaction-sql.cpp +++ b/src/backend/sql/gnc-transaction-sql.cpp @@ -971,7 +971,7 @@ convert_query_term_to_sql (const GncSqlBackend* be, const gchar* fieldName, query_date_t date_data = (query_date_t)pPredData; auto datebuf = be->time64_to_string (date_data->date.tv_sec); - g_string_append_printf (sql, "'%s'", datebuf); + g_string_append_printf (sql, "'%s'", datebuf.c_str()); } else if (strcmp (pPredData->type_name, QOF_TYPE_INT32) == 0) From 431b704c92f4d2abc90b07ebc9a2c42c9a8a2d52 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 26 Jul 2016 10:13:16 -0700 Subject: [PATCH 41/63] Abstract setting database string-value options to function set_options. --- src/backend/dbi/gnc-backend-dbi.cpp | 184 ++++++++++++++-------------- 1 file changed, 92 insertions(+), 92 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index d23593239e..aa681feb9e 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -147,6 +147,24 @@ create_tables(const OBEEntry& entry, GncDbiBackend* be) obe->create_tables (be); } +static void +set_options(dbi_conn conn, const PairVec& options) +{ + for (auto option : options) + { + auto opt = option.first.c_str(); + auto val = option.second.c_str(); + auto result = dbi_conn_set_option(conn, opt, val); + if (result < 0) + { + const char *msg = nullptr; + int err = dbi_conn_error(conn, &msg); + PERR("Error setting %s option to %s: %s", opt, val, msg); + throw std::runtime_error(msg); + } + } +} + void sqlite3_error_fn (dbi_conn conn, void* user_data) { @@ -171,7 +189,8 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, const char* msg = nullptr; gboolean file_exists; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; - + PairVec options; + g_return_if_fail (qbe != nullptr); g_return_if_fail (session != nullptr); g_return_if_fail (book_id != nullptr); @@ -221,24 +240,15 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, basename = g_path_get_basename (filepath); dbi_conn_error_handler (conn, sqlite3_error_fn, be); /* dbi-sqlite3 documentation says that sqlite3 doesn't take a "host" option */ - result = dbi_conn_set_option (conn, "host", "localhost"); - if (result < 0) - { - PERR ("Error setting 'host' option\n"); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + + options.push_back(std::make_pair("host", "localhost")); + options.push_back(std::make_pair("dbname", basename)); + options.push_back(std::make_pair("sqlite3_dbdir", dirname)); + try { + set_options(conn, options); } - result = dbi_conn_set_option (conn, "dbname", basename); - if (result < 0) + catch (std::runtime_error& err) { - PERR ("Error setting 'dbname' option\n"); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; - } - result = dbi_conn_set_option (conn, "sqlite3_dbdir", dirname); - if (result < 0) - { - PERR ("Error setting 'sqlite3_dbdir' option\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } @@ -398,58 +408,40 @@ mysql_error_fn (dbi_conn conn, void* user_data) * @param password Password * @return TRUE if successful, FALSE if error */ -static gboolean +static bool set_standard_connection_options (QofBackend* qbe, dbi_conn conn, - const gchar* host, int port, - const gchar* dbname, const gchar* username, const gchar* password) + const std::string& host, int port, + const std::string& dbname, + const std::string& username, + const std::string& password) { gint result; - - result = dbi_conn_set_option (conn, "host", host); - if (result < 0) + PairVec options; + options.push_back(std::make_pair("host", host)); + options.push_back(std::make_pair("dbname", dbname)); + options.push_back(std::make_pair("username", username)); + options.push_back(std::make_pair("password", password)); + options.push_back(std::make_pair("encoding", "UTF-8")); + try { - PERR ("Error setting 'host' option\n"); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - return FALSE; + set_options(conn, options); + auto result = dbi_conn_set_option_numeric(conn, "port", port); + if (result < 0) + { + const char *msg = nullptr; + auto err = dbi_conn_error(conn, &msg); + PERR("Error setting port option to %d: %s", port, msg); + throw std::runtime_error(msg); + } } - result = dbi_conn_set_option_numeric (conn, "port", port); - if (result < 0) + catch (std::runtime_error& err) { - PERR ("Error setting 'port' option\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - return FALSE; - } - result = dbi_conn_set_option (conn, "dbname", dbname); - if (result < 0) - { - PERR ("Error setting 'dbname' option\n"); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - return FALSE; - } - result = dbi_conn_set_option (conn, "username", username); - if (result < 0) - { - PERR ("Error setting 'username' option\n"); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - return FALSE; - } - result = dbi_conn_set_option (conn, "password", password); - if (result < 0) - { - PERR ("Error setting 'password' option\n"); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - return FALSE; + return false; } - result = dbi_conn_set_option (conn, "encoding", "UTF-8"); - if (result < 0) - { - PERR ("Error setting 'encoding' option\n"); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - return FALSE; - } - - return TRUE; + + return true; } /* FIXME: Move to GncDbiSqlConnection. */ @@ -616,27 +608,27 @@ adjust_sql_options (dbi_conn connection) else PINFO("Sql_mode isn't set."); } - else + else { - PINFO("Initial sql_mode: %s", str.c_str()); + PINFO("Initial sql_mode: %s", str.c_str()); if(str.find(SQL_OPTION_TO_REMOVE) != std::string::npos) { - std::string adjusted_str{adjust_sql_options_string(str)}; - PINFO("Setting sql_mode to %s", adjusted_str.c_str()); - std::string set_str{"SET sql_mode=" + std::move(adjusted_str)}; - dbi_result set_result = dbi_conn_query(connection, - set_str.c_str()); - if (set_result) - { - dbi_result_free(set_result); - } - else - { - const char* errmsg; - int err = dbi_conn_error(connection, &errmsg); - PERR("Unable to set sql_mode %d : %s", err, errmsg); - } - } + std::string adjusted_str{adjust_sql_options_string(str)}; + PINFO("Setting sql_mode to %s", adjusted_str.c_str()); + std::string set_str{"SET sql_mode=" + std::move(adjusted_str)}; + dbi_result set_result = dbi_conn_query(connection, + set_str.c_str()); + if (set_result) + { + dbi_result_free(set_result); + } + else + { + const char* errmsg; + int err = dbi_conn_error(connection, &errmsg); + PERR("Unable to set sql_mode %d : %s", err, errmsg); + } + } } dbi_result_free(result); } @@ -665,6 +657,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, gint result; gboolean success = FALSE; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; + PairVec options; g_return_if_fail (qbe != nullptr); g_return_if_fail (session != nullptr); @@ -752,14 +745,17 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, // The db does not already exist. Connect to the 'mysql' db and try to create it. if (create) { - dbi_result dresult; - result = dbi_conn_set_option (conn, "dbname", "mysql"); - if (result < 0) + options.push_back(std::make_pair("dbname", "mysql")); + try + { + set_options(conn, options); + } + catch (std::runtime_error& err) { - PERR ("Error setting 'dbname' option\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } + result = dbi_conn_connect (conn); if (result < 0) { @@ -768,9 +764,9 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, goto exit; } adjust_sql_options (conn); - dresult = dbi_conn_queryf (conn, - "CREATE DATABASE %s CHARACTER SET utf8", - dbname); + auto dresult = dbi_conn_queryf (conn, + "CREATE DATABASE %s CHARACTER SET utf8", + dbname); if (dresult == nullptr) { PERR ("Unable to create database '%s'\n", dbname); @@ -986,7 +982,8 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, gboolean success = FALSE; gint portnum = 0; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; - + PairVec options; + g_return_if_fail (qbe != nullptr); g_return_if_fail (session != nullptr); g_return_if_fail (book_id != nullptr); @@ -1080,14 +1077,17 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, // The db does not already exist. Connect to the 'postgres' db and try to create it. if (create) { - dbi_result dresult; - result = dbi_conn_set_option (conn, "dbname", "postgres"); - if (result < 0) + options.push_back(std::make_pair("dbname", "postgres")); + try + { + set_options(conn, options); + } + catch (std::runtime_error& err) { - PERR ("Error setting 'dbname' option\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } + result = dbi_conn_connect (conn); if (result < 0) { @@ -1095,8 +1095,8 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); goto exit; } - dresult = dbi_conn_queryf (conn, - "CREATE DATABASE %s WITH TEMPLATE template0 ENCODING 'UTF8'", dbnamelc); + auto dresult = dbi_conn_queryf (conn, + "CREATE DATABASE %s WITH TEMPLATE template0 ENCODING 'UTF8'", dbnamelc); if (dresult == nullptr) { PERR ("Unable to create database '%s'\n", dbname); From d8556ca7b540cceb7aa82e75f63b518b797dc112 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 26 Jul 2016 10:13:55 -0700 Subject: [PATCH 42/63] Reformat adjust_sql_options a bit to reduce nesting. --- src/backend/dbi/gnc-backend-dbi.cpp | 66 ++++++++++++++--------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index aa681feb9e..abefc32cdc 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -595,48 +595,44 @@ static void adjust_sql_options (dbi_conn connection) { dbi_result result = dbi_conn_query( connection, "SELECT @@sql_mode"); - if (result) + if (result == nullptr) { - dbi_result_first_row(result); - std::string str{dbi_result_get_string_idx(result, 1)}; - if (str.empty()) - { - const char* errmsg; - int err = dbi_conn_error(connection, &errmsg); - if (err) - PERR("Unable to get sql_mode %d : %s", err, errmsg); - else - PINFO("Sql_mode isn't set."); - } + const char* errmsg; + int err = dbi_conn_error(connection, &errmsg); + PERR("Unable to read sql_mode %d : %s", err, errmsg); + return; + } + dbi_result_first_row(result); + std::string str{dbi_result_get_string_idx(result, 1)}; + dbi_result_free(result); + if (str.empty()) + { + const char* errmsg; + int err = dbi_conn_error(connection, &errmsg); + if (err) + PERR("Unable to get sql_mode %d : %s", err, errmsg); else - { - PINFO("Initial sql_mode: %s", str.c_str()); - if(str.find(SQL_OPTION_TO_REMOVE) != std::string::npos) - { - std::string adjusted_str{adjust_sql_options_string(str)}; - PINFO("Setting sql_mode to %s", adjusted_str.c_str()); - std::string set_str{"SET sql_mode=" + std::move(adjusted_str)}; - dbi_result set_result = dbi_conn_query(connection, - set_str.c_str()); - if (set_result) - { - dbi_result_free(set_result); - } - else - { - const char* errmsg; - int err = dbi_conn_error(connection, &errmsg); - PERR("Unable to set sql_mode %d : %s", err, errmsg); - } - } - } - dbi_result_free(result); + PINFO("Sql_mode isn't set."); + return; + } + PINFO("Initial sql_mode: %s", str.c_str()); + if(str.find(SQL_OPTION_TO_REMOVE) == std::string::npos) + return; + + std::string adjusted_str{adjust_sql_options_string(str)}; + PINFO("Setting sql_mode to %s", adjusted_str.c_str()); + std::string set_str{"SET sql_mode=" + std::move(adjusted_str)}; + dbi_result set_result = dbi_conn_query(connection, + set_str.c_str()); + if (set_result) + { + dbi_result_free(set_result); } else { const char* errmsg; int err = dbi_conn_error(connection, &errmsg); - PERR("Unable to read sql_mode %d : %s", err, errmsg); + PERR("Unable to set sql_mode %d : %s", err, errmsg); } } From b38be9fe20689cdc0e1e6dac4236de47d5e70ce1 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 26 Jul 2016 11:50:51 -0700 Subject: [PATCH 43/63] Get rid of gotos. By replacing all of the char*s on the heap to std::strings, mostly in a new UriString struct. Also lets us simplify the call to set_standard_connection_options. --- src/backend/dbi/gnc-backend-dbi.cpp | 283 ++++++++++++++++------------ 1 file changed, 158 insertions(+), 125 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index abefc32cdc..de41bd75a5 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -135,6 +135,50 @@ public: /* ================================================================= */ /* ================================================================= */ +struct UriStrings +{ + UriStrings(const std::string& uri); + std::string basename() const noexcept; + const char* dbname() const noexcept; + std::string m_protocol; + std::string m_host; + std::string m_dbname; + std::string m_username; + std::string m_password; + std::string m_basename; + int m_portnum; +}; + +UriStrings::UriStrings(const std::string& uri) +{ + gchar *protocol, *host, *username, *password, *dbname; + int portnum; + gnc_uri_get_components(uri.c_str(), &protocol, &host, &portnum, &username, + &password, &dbname); + m_protocol = std::string{protocol}; + m_host = std::string{host}; + m_dbname = std::string{dbname}; + m_username = std::string{username}; + m_password = std::string{password}; + m_portnum = portnum; + g_free(protocol); + g_free(host); + g_free(username); + g_free(password); + g_free(dbname); +} + +std::string +UriStrings::basename() const noexcept +{ + return m_protocol + "_" + m_host + "_" + m_username + "_" + m_dbname; +} + +const char* +UriStrings::dbname() const noexcept +{ + return m_dbname.c_str(); +} static void create_tables(const OBEEntry& entry, GncDbiBackend* be) @@ -183,14 +227,11 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, { GncDbiBackend* be = (GncDbiBackend*)qbe; gint result; - gchar* dirname = nullptr; - gchar* basename = nullptr; - gchar* filepath = nullptr; const char* msg = nullptr; gboolean file_exists; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; PairVec options; - + g_return_if_fail (qbe != nullptr); g_return_if_fail (session != nullptr); g_return_if_fail (book_id != nullptr); @@ -198,16 +239,20 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, ENTER (" "); /* Remove uri type if present */ - filepath = gnc_uri_get_path (book_id); + auto path = gnc_uri_get_path (book_id); + std::string filepath{path}; + g_free(path); GFileTest ftest = static_cast ( G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS) ; - file_exists = g_file_test (filepath, ftest); + file_exists = g_file_test (filepath.c_str(), ftest); if (!create && !file_exists) { qof_backend_set_error (qbe, ERR_FILEIO_FILE_NOT_FOUND); - qof_backend_set_message (qbe, "Sqlite3 file %s not found", filepath); - PWARN ("Sqlite3 file %s not found", filepath); - goto exit; + qof_backend_set_message (qbe, "Sqlite3 file %s not found", + filepath.c_str()); + PWARN ("Sqlite3 file %s not found", filepath.c_str()); + LEAVE("Error"); + return; } if (create && !force && file_exists) @@ -215,7 +260,8 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS); msg = "Might clobber, no force"; PWARN ("%s", msg); - goto exit; + LEAVE("Error"); + return; } be->connect(nullptr); @@ -233,24 +279,28 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, { PERR ("Unable to create sqlite3 dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); - goto exit; + LEAVE("Error"); + return; } - dirname = g_path_get_dirname (filepath); - basename = g_path_get_basename (filepath); dbi_conn_error_handler (conn, sqlite3_error_fn, be); /* dbi-sqlite3 documentation says that sqlite3 doesn't take a "host" option */ - options.push_back(std::make_pair("host", "localhost")); + auto dirname = g_path_get_dirname (filepath.c_str()); + auto basename = g_path_get_basename (filepath.c_str()); options.push_back(std::make_pair("dbname", basename)); options.push_back(std::make_pair("sqlite3_dbdir", dirname)); + if (basename != nullptr) g_free (basename); + if (dirname != nullptr) g_free (dirname); + try { set_options(conn, options); } catch (std::runtime_error& err) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } result = dbi_conn_connect (conn); @@ -258,7 +308,8 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, { PERR ("Unable to connect to %s: %d\n", book_id, result); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); - goto exit; + LEAVE("Error"); + return; } dbi_test_result = conn_test_dbi_library (conn); @@ -286,16 +337,18 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, /* does now, and we don't want to */ dbi_conn_close (conn); /* leave it lying around. */ conn = nullptr; - g_unlink (filepath); + g_unlink (filepath.c_str()); } msg = "Bad DBI Library"; - goto exit; + LEAVE("Error"); + return; } if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) { qof_backend_set_error (qbe, ERR_BACKEND_LOCKED); msg = "Locked"; - goto exit; + LEAVE("Error"); + return; } be->connect(nullptr); @@ -305,13 +358,9 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, /* We should now have a proper session set up. * Let's start logging */ - xaccLogSetBaseName (filepath); - PINFO ("logpath=%s", filepath ? filepath : "(null)"); + xaccLogSetBaseName (filepath.c_str()); + PINFO ("logpath=%s", filepath.c_str() ? filepath.c_str() : "(null)"); -exit: - if (filepath != nullptr) g_free (filepath); - if (basename != nullptr) g_free (basename); - if (dirname != nullptr) g_free (dirname); LEAVE ("%s", msg); } @@ -410,27 +459,25 @@ mysql_error_fn (dbi_conn conn, void* user_data) */ static bool set_standard_connection_options (QofBackend* qbe, dbi_conn conn, - const std::string& host, int port, - const std::string& dbname, - const std::string& username, - const std::string& password) + const UriStrings& uri) + { gint result; PairVec options; - options.push_back(std::make_pair("host", host)); - options.push_back(std::make_pair("dbname", dbname)); - options.push_back(std::make_pair("username", username)); - options.push_back(std::make_pair("password", password)); + options.push_back(std::make_pair("host", uri.m_host)); + options.push_back(std::make_pair("dbname", uri.m_dbname)); + options.push_back(std::make_pair("username", uri.m_username)); + options.push_back(std::make_pair("password", uri.m_password)); options.push_back(std::make_pair("encoding", "UTF-8")); try { set_options(conn, options); - auto result = dbi_conn_set_option_numeric(conn, "port", port); + auto result = dbi_conn_set_option_numeric(conn, "port", uri.m_portnum); if (result < 0) { const char *msg = nullptr; auto err = dbi_conn_error(conn, &msg); - PERR("Error setting port option to %d: %s", port, msg); + PERR("Error setting port option to %d: %s", uri.m_portnum, msg); throw std::runtime_error(msg); } } @@ -636,20 +683,15 @@ adjust_sql_options (dbi_conn connection) } } + static void gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, const gchar* book_id, gboolean ignore_lock, gboolean create, gboolean force) { GncDbiBackend* be = (GncDbiBackend*)qbe; - gchar* protocol = nullptr; - gchar* host = nullptr; - gchar* dbname = nullptr; - gchar* username = nullptr; - gchar* password = nullptr; gchar* basename = nullptr; gchar* translog_path = nullptr; - gint portnum = 0; gint result; gboolean success = FALSE; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; @@ -664,8 +706,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, /* Split the book-id * Format is protocol://username:password@hostname:port/dbname where username, password and port are optional) */ - gnc_uri_get_components (book_id, &protocol, &host, &portnum, - &username, &password, &dbname); + UriStrings uri(book_id); // Try to connect to the db. If it doesn't exist and the create // flag is TRUE, we'll need to connect to the 'mysql' db and execute the @@ -684,13 +725,14 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, { PERR ("Unable to create mysql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); - goto exit; + LEAVE("Error"); + return; } dbi_conn_error_handler (conn, mysql_error_fn, be); - if (!set_standard_connection_options (qbe, conn, host, portnum, dbname, - username, password)) + if (!set_standard_connection_options (qbe, conn, uri)) { - goto exit; + LEAVE("Error"); + return; } be->set_exists(true); result = dbi_conn_connect (conn); @@ -717,13 +759,15 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, } if (GNC_DBI_PASS != dbi_test_result) { - goto exit; + LEAVE("Error"); + return; } if (create && !force && save_may_clobber_data (qbe)) { qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS); PWARN ("Databse already exists, Might clobber it."); - goto exit; + LEAVE("Error"); + return; } success = gnc_dbi_lock_database (qbe, conn, ignore_lock); @@ -733,9 +777,10 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, if (be->exists()) { - PERR ("Unable to connect to database '%s'\n", dbname); + PERR ("Unable to connect to database '%s'\n", uri.dbname()); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } // The db does not already exist. Connect to the 'mysql' db and try to create it. @@ -749,7 +794,8 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, catch (std::runtime_error& err) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } result = dbi_conn_connect (conn); @@ -757,17 +803,19 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, { PERR ("Unable to connect to 'mysql' database\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } adjust_sql_options (conn); auto dresult = dbi_conn_queryf (conn, "CREATE DATABASE %s CHARACTER SET utf8", - dbname); + uri.dbname()); if (dresult == nullptr) { - PERR ("Unable to create database '%s'\n", dbname); + PERR ("Unable to create database '%s'\n", uri.dbname()); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } dbi_conn_close (conn); conn = nullptr; @@ -786,20 +834,23 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, { PERR ("Unable to create mysql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); - goto exit; + LEAVE("Error"); + return; } dbi_conn_error_handler (conn, mysql_error_fn, be); - if (!set_standard_connection_options (qbe, conn, host, 0, dbname, - username, password)) + uri.m_portnum = 0; + if (!set_standard_connection_options (qbe, conn, uri)) { - goto exit; + LEAVE("Error: Failed to set options."); + return; } result = dbi_conn_connect (conn); if (result < 0) { - PERR ("Unable to create database '%s'\n", dbname); + PERR ("Unable to create database '%s'\n", uri.dbname()); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } adjust_sql_options (conn); dbi_test_result = conn_test_dbi_library (conn); @@ -822,21 +873,20 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, } if (dbi_test_result != GNC_DBI_PASS) { - dbi_conn_queryf (conn, "DROP DATABASE %s", dbname); - goto exit; + dbi_conn_queryf (conn, "DROP DATABASE %s", uri.dbname()); + return; } success = gnc_dbi_lock_database (qbe, conn, ignore_lock); } else { qof_backend_set_error (qbe, ERR_BACKEND_NO_SUCH_DB); - qof_backend_set_message (qbe, "Database %s not found", dbname); + qof_backend_set_message (qbe, "Database %s not found", uri.dbname()); } } if (success) { - dbi_result dresult; be->connect(nullptr); be->connect( new GncDbiSqlConnection (new GncDbiProviderImpl, @@ -845,19 +895,10 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, /* We should now have a proper session set up. * Let's start logging */ - basename = g_strjoin ("_", protocol, host, username, dbname, nullptr); - translog_path = gnc_build_translog_path (basename); + translog_path = gnc_build_translog_path (uri.basename().c_str()); xaccLogSetBaseName (translog_path); PINFO ("logpath=%s", translog_path ? translog_path : "(null)"); - -exit: - g_free (protocol); - g_free (host); - g_free (username); - g_free (password); - g_free (basename); g_free (translog_path); - g_free (dbname); LEAVE (" "); } @@ -968,15 +1009,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, { GncDbiBackend* be = (GncDbiBackend*)qbe; gint result = 0; - gchar* protocol = nullptr; - gchar* host = nullptr; - gchar* dbname = nullptr, *dbnamelc = nullptr; - gchar* username = nullptr; - gchar* password = nullptr; - gchar* basename = nullptr; - gchar* translog_path = nullptr; gboolean success = FALSE; - gint portnum = 0; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; PairVec options; @@ -989,16 +1022,16 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, /* Split the book-id * Format is protocol://username:password@hostname:port/dbname where username, password and port are optional) */ - gnc_uri_get_components (book_id, &protocol, &host, &portnum, - &username, &password, &dbname); - if (portnum == 0) - portnum = PGSQL_DEFAULT_PORT; + UriStrings uri(book_id); + if (uri.m_portnum == 0) + uri.m_portnum = PGSQL_DEFAULT_PORT; /* Postgres's SQL interface coerces identifiers to lower case, but the * C interface is case-sensitive. This results in a mixed-case dbname * being created (with a lower case name) but then dbi can't conect to * it. To work around this, coerce the name to lowercase first. */ - dbnamelc = g_utf8_strdown (dbname, -1); - + auto lcname = g_utf8_strdown (uri.dbname(), -1); + uri.m_dbname = std::string{lcname}; + g_free(lcname); // Try to connect to the db. If it doesn't exist and the create // flag is TRUE, we'll need to connect to the 'postgres' db and execute the // CREATE DATABASE ddl statement there. @@ -1017,13 +1050,14 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, { PERR ("Unable to create pgsql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); - goto exit; + LEAVE("Error"); + return; } dbi_conn_error_handler (conn, pgsql_error_fn, be); - if (!set_standard_connection_options (qbe, conn, host, portnum, dbnamelc, - username, password)) + if (!set_standard_connection_options (qbe, conn, uri)) { - goto exit; + LEAVE("Error"); + return; } be->set_exists(true); result = dbi_conn_connect (conn); @@ -1049,13 +1083,15 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, } if (dbi_test_result != GNC_DBI_PASS) { - goto exit; + LEAVE("Error"); + return; } if (create && !force && save_may_clobber_data (qbe)) { qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS); PWARN ("Databse already exists, Might clobber it."); - goto exit; + LEAVE("Error"); + return; } success = gnc_dbi_lock_database (qbe, conn, ignore_lock); @@ -1065,9 +1101,10 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, if (be->exists()) { - PERR ("Unable to connect to database '%s'\n", dbname); + PERR ("Unable to connect to database '%s'\n", uri.dbname()); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } // The db does not already exist. Connect to the 'postgres' db and try to create it. @@ -1081,7 +1118,8 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, catch (std::runtime_error& err) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } result = dbi_conn_connect (conn); @@ -1089,18 +1127,20 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, { PERR ("Unable to connect to 'postgres' database\n"); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } auto dresult = dbi_conn_queryf (conn, - "CREATE DATABASE %s WITH TEMPLATE template0 ENCODING 'UTF8'", dbnamelc); + "CREATE DATABASE %s WITH TEMPLATE template0 ENCODING 'UTF8'", uri.dbname()); if (dresult == nullptr) { - PERR ("Unable to create database '%s'\n", dbname); + PERR ("Unable to create database '%s'\n", uri.dbname()); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } dbi_conn_queryf (conn, - "ALTER DATABASE %s SET standard_conforming_strings TO on", dbnamelc); + "ALTER DATABASE %s SET standard_conforming_strings TO on", uri.dbname()); dbi_conn_close (conn); // Try again to connect to the db @@ -1117,21 +1157,23 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, { PERR ("Unable to create pgsql dbi connection\n"); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); - goto exit; + LEAVE("Error"); + return; } dbi_conn_error_handler (conn, pgsql_error_fn, be); - if (!set_standard_connection_options (qbe, conn, host, - PGSQL_DEFAULT_PORT, - dbnamelc, username, password)) + uri.m_portnum = PGSQL_DEFAULT_PORT; + if (!set_standard_connection_options (qbe, conn, uri)) { - goto exit; + LEAVE("Error"); + return; } result = dbi_conn_connect (conn); if (result < 0) { - PERR ("Unable to create database '%s'\n", dbname); + PERR ("Unable to create database '%s'\n", uri.dbname()); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - goto exit; + LEAVE("Error"); + return; } dbi_test_result = conn_test_dbi_library (conn); switch (dbi_test_result) @@ -1154,15 +1196,16 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, if (GNC_DBI_PASS != dbi_test_result) { dbi_conn_select_db (conn, "template1"); - dbi_conn_queryf (conn, "DROP DATABASE %s", dbnamelc); - goto exit; + dbi_conn_queryf (conn, "DROP DATABASE %s", uri.dbname()); + LEAVE("Error"); + return; } success = gnc_dbi_lock_database (qbe, conn, ignore_lock); } else { qof_backend_set_error (qbe, ERR_BACKEND_NO_SUCH_DB); - qof_backend_set_message (qbe, "Database %s not found", dbname); + qof_backend_set_message (qbe, "Database %s not found", uri.dbname()); } } if (success) @@ -1175,20 +1218,10 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, /* We should now have a proper session set up. * Let's start logging */ - basename = g_strjoin ("_", protocol, host, username, dbname, nullptr); - translog_path = gnc_build_translog_path (basename); + auto translog_path = gnc_build_translog_path (uri.basename().c_str()); xaccLogSetBaseName (translog_path); PINFO ("logpath=%s", translog_path ? translog_path : "(null)"); - -exit: - g_free (protocol); - g_free (host); - g_free (username); - g_free (password); - g_free (basename); g_free (translog_path); - g_free (dbname); - g_free (dbnamelc); LEAVE (" "); } From 5074bd590fdf9604781b1cf193e2f6a40a793d2f Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 26 Jul 2016 13:28:22 -0700 Subject: [PATCH 44/63] Don't leak the quoted string returned from dbi_conn_quote_string_copy. --- src/backend/dbi/gnc-dbisqlconnection.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index aa53d6a349..c866cb5069 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -414,14 +414,11 @@ GncDbiSqlConnection::quote_string (const std::string& unquoted_str) size = dbi_conn_quote_string_copy (m_conn, unquoted_str.c_str(), "ed_str); - if (size != 0) - { - return std::string{quoted_str}; - } - else - { + if (quoted_str == nullptr) return std::string{""}; - } + std::string retval{quoted_str}; + free(quoted_str); + return retval; } From 37d425733613aaf9c11272989d7d7305f9b075dd Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 26 Jul 2016 13:54:45 -0700 Subject: [PATCH 45/63] Extract-function conn_test_dbi_library. Renaming the previous so-named function dbi_library_test. --- src/backend/dbi/gnc-backend-dbi.cpp | 127 +++++++--------------------- 1 file changed, 30 insertions(+), 97 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index de41bd75a5..339baca854 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -116,7 +116,7 @@ static gchar lock_table[] = "gnclock"; static gboolean gnc_dbi_lock_database (QofBackend*, dbi_conn, gboolean); static gboolean save_may_clobber_data (QofBackend* qbe); -static GncDbiTestResult conn_test_dbi_library (dbi_conn conn); +static bool conn_test_dbi_library (dbi_conn conn, QofBackend* qbe); template class QofDbiBackendProvider : public QofBackendProvider @@ -312,25 +312,7 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, return; } - dbi_test_result = conn_test_dbi_library (conn); - switch (dbi_test_result) - { - case GNC_DBI_PASS: - break; - - case GNC_DBI_FAIL_SETUP: - qof_backend_set_error (qbe, ERR_SQL_DBI_UNTESTABLE); - qof_backend_set_message (qbe, - "SQLite3: Failed to setup for large number test"); - break; - - case GNC_DBI_FAIL_TEST: - qof_backend_set_error (qbe, ERR_SQL_BAD_DBI); - qof_backend_set_message (qbe, - "SQLite3 DBI library fails large number test"); - break; - } - if (dbi_test_result != GNC_DBI_PASS) + if (!conn_test_dbi_library(conn, qbe)) { if (create && !file_exists) /* File didn't exist before, but it */ { @@ -739,25 +721,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, if (result == 0) { adjust_sql_options (conn); - dbi_test_result = conn_test_dbi_library (conn); - switch (dbi_test_result) - { - case GNC_DBI_PASS: - break; - - case GNC_DBI_FAIL_SETUP: - qof_backend_set_error (qbe, ERR_SQL_DBI_UNTESTABLE); - qof_backend_set_message (qbe, - "DBI library large number test incomplete"); - break; - - case GNC_DBI_FAIL_TEST: - qof_backend_set_error (qbe, ERR_SQL_BAD_DBI); - qof_backend_set_message (qbe, - "DBI library fails large number test"); - break; - } - if (GNC_DBI_PASS != dbi_test_result) + if(!conn_test_dbi_library(conn, qbe)) { LEAVE("Error"); return; @@ -853,25 +817,7 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, return; } adjust_sql_options (conn); - dbi_test_result = conn_test_dbi_library (conn); - switch (dbi_test_result) - { - case GNC_DBI_PASS: - break; - - case GNC_DBI_FAIL_SETUP: - qof_backend_set_error (qbe, ERR_SQL_DBI_UNTESTABLE); - qof_backend_set_message (qbe, - "MySql: Failed to setup for large number test"); - break; - - case GNC_DBI_FAIL_TEST: - qof_backend_set_error (qbe, ERR_SQL_BAD_DBI); - qof_backend_set_message (qbe, - "MySql DBI library fails large number test"); - break; - } - if (dbi_test_result != GNC_DBI_PASS) + if (!conn_test_dbi_library(conn, qbe)) { dbi_conn_queryf (conn, "DROP DATABASE %s", uri.dbname()); return; @@ -1063,25 +1009,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, result = dbi_conn_connect (conn); if (result == 0) { - dbi_test_result = conn_test_dbi_library (conn); - switch (dbi_test_result) - { - case GNC_DBI_PASS: - break; - - case GNC_DBI_FAIL_SETUP: - qof_backend_set_error (qbe, ERR_SQL_DBI_UNTESTABLE); - qof_backend_set_message (qbe, - "Postgresql: Failed to setup for large number test"); - break; - - case GNC_DBI_FAIL_TEST: - qof_backend_set_error (qbe, ERR_SQL_BAD_DBI); - qof_backend_set_message (qbe, - "Postgresql DBI library fails large number test"); - break; - } - if (dbi_test_result != GNC_DBI_PASS) + if (!conn_test_dbi_library(conn, qbe)) { LEAVE("Error"); return; @@ -1175,25 +1103,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, LEAVE("Error"); return; } - dbi_test_result = conn_test_dbi_library (conn); - switch (dbi_test_result) - { - case GNC_DBI_PASS: - break; - - case GNC_DBI_FAIL_SETUP: - qof_backend_set_error (qbe, ERR_SQL_DBI_UNTESTABLE); - qof_backend_set_message (qbe, - "DBI library large number test incomplete"); - break; - - case GNC_DBI_FAIL_TEST: - qof_backend_set_error (qbe, ERR_SQL_BAD_DBI); - qof_backend_set_message (qbe, - "DBI library fails large number test"); - break; - } - if (GNC_DBI_PASS != dbi_test_result) + if (!conn_test_dbi_library(conn, qbe)) { dbi_conn_select_db (conn, "template1"); dbi_conn_queryf (conn, "DROP DATABASE %s", uri.dbname()); @@ -1702,7 +1612,7 @@ gnc_module_finalize_backend_dbi (void) * GNC_DBI_FAIL_TEST if the bug was found. */ static GncDbiTestResult -conn_test_dbi_library (dbi_conn conn) +dbi_library_test (dbi_conn conn) { gint64 testlonglong = -9223372036854775807LL, resultlonglong = 0; guint64 testulonglong = 9223372036854775807LLU, resultulonglong = 0; @@ -1777,5 +1687,28 @@ conn_test_dbi_library (dbi_conn conn) return retval; } +static bool +conn_test_dbi_library(dbi_conn conn, QofBackend* qbe) +{ + auto result = dbi_library_test (conn); + switch (result) + { + case GNC_DBI_PASS: + break; + + case GNC_DBI_FAIL_SETUP: + qof_backend_set_error (qbe, ERR_SQL_DBI_UNTESTABLE); + qof_backend_set_message (qbe, + "DBI library large number test incomplete"); + break; + + case GNC_DBI_FAIL_TEST: + qof_backend_set_error (qbe, ERR_SQL_BAD_DBI); + qof_backend_set_message (qbe, + "DBI library fails large number test"); + break; + } + return result == GNC_DBI_PASS; +} /* ========================== END OF FILE ===================== */ From 31c73a141e94d8ff1ff1cf4a12d44defe70eb616 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 26 Jul 2016 16:15:14 -0700 Subject: [PATCH 46/63] Extract functions conn_setup and create_database. --- src/backend/dbi/gnc-backend-dbi.cpp | 448 ++++++++++++---------------- 1 file changed, 188 insertions(+), 260 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 339baca854..eb518d02da 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -113,6 +113,7 @@ static gchar lock_table[] = "gnclock"; #define MYSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" #define PGSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d %02d%02d%02d" +static void adjust_sql_options (dbi_conn connection); static gboolean gnc_dbi_lock_database (QofBackend*, dbi_conn, gboolean); static gboolean save_may_clobber_data (QofBackend* qbe); @@ -137,7 +138,9 @@ public: /* ================================================================= */ struct UriStrings { + UriStrings() = default; UriStrings(const std::string& uri); + ~UriStrings() = default; std::string basename() const noexcept; const char* dbname() const noexcept; std::string m_protocol; @@ -209,6 +212,146 @@ set_options(dbi_conn conn, const PairVec& options) } } +/** + * Sets standard db options in a dbi_conn. + * + * @param qbe QOF backend + * @param conn dbi_conn connection + * @param uri UriStrings containing the needed paramters. + * @return TRUE if successful, FALSE if error + */ +static bool +set_standard_connection_options (QofBackend* qbe, dbi_conn conn, + const UriStrings& uri) + +{ + gint result; + PairVec options; + options.push_back(std::make_pair("host", uri.m_host)); + options.push_back(std::make_pair("dbname", uri.m_dbname)); + options.push_back(std::make_pair("username", uri.m_username)); + options.push_back(std::make_pair("password", uri.m_password)); + options.push_back(std::make_pair("encoding", "UTF-8")); + try + { + set_options(conn, options); + auto result = dbi_conn_set_option_numeric(conn, "port", uri.m_portnum); + if (result < 0) + { + const char *msg = nullptr; + auto err = dbi_conn_error(conn, &msg); + PERR("Error setting port option to %d: %s", uri.m_portnum, msg); + throw std::runtime_error(msg); + } + } + catch (std::runtime_error& err) + { + qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); + return false; + } + + return true; +} +static dbi_conn +conn_setup (const char* dbtype, QofBackend* qbe, + dbi_conn_error_handler_func err_handler, PairVec& options, + UriStrings& uri) +{ +#if HAVE_LIBDBI_R + dbi_conn conn; + if (dbi_instance) + conn = dbi_conn_new_r (dbtype, dbi_instance); + else + PERR ("Attempt to connect with an uninitialized dbi_instance"); +#else + auto conn = dbi_conn_new (dbtype); +#endif + + if (conn == nullptr) + { + PERR ("Unable to create %s dbi connection", dbtype); + qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); + return nullptr; + } + + dbi_conn_error_handler (conn, err_handler, qbe); + + if (!uri.m_dbname.empty() && + !set_standard_connection_options(qbe, conn, uri)) + { + dbi_conn_close(conn); + return nullptr; + } + if(!options.empty()) + { + try { + set_options(conn, options); + } + catch (std::runtime_error& err) + { + dbi_conn_close(conn); + qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); + return nullptr; + } + } + + return conn; +} + +static bool +create_database(DbType type, QofBackend *qbe, dbi_conn conn, const char* db) +{ + const char *dbname; + const char *dbcreate; + if (type == DbType::DBI_MYSQL) + { + dbname = "mysql"; + dbcreate = "CREATE DATABASE %s CHARACTER SET utf8"; + } + else + { + dbname = "postgres"; + dbcreate = "CREATE DATABASE %s WITH TEMPLATE template0 ENCODING 'UTF8'"; + } + PairVec options; + options.push_back(std::make_pair("dbname", dbname)); + try + { + set_options(conn, options); + } + catch (std::runtime_error& err) + { + qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); + return false; + } + + auto result = dbi_conn_connect (conn); + if (result < 0) + { + PERR ("Unable to connect to %s database", dbname); + qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); + return false; + } + if (type == DbType::DBI_MYSQL) + adjust_sql_options(conn); + auto dresult = dbi_conn_queryf (conn, dbcreate, db); + if (dresult == nullptr) + { + PERR ("Unable to create database '%s'\n", db); + qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); + return false; + } + if (type == DbType::DBI_PGSQL) + { + const char *alterdb = "ALTER DATABASE %s SET " + "standard_conforming_strings TO on"; + dbi_conn_queryf (conn, alterdb, db); + } + dbi_conn_close(conn); + conn = nullptr; + return true; +} + void sqlite3_error_fn (dbi_conn conn, void* user_data) { @@ -226,10 +369,8 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, gboolean create, gboolean force) { GncDbiBackend* be = (GncDbiBackend*)qbe; - gint result; const char* msg = nullptr; gboolean file_exists; - GncDbiTestResult dbi_test_result = GNC_DBI_PASS; PairVec options; g_return_if_fail (qbe != nullptr); @@ -265,25 +406,6 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, } be->connect(nullptr); - dbi_conn conn; -#if HAVE_LIBDBI_R - if (dbi_instance) - conn = dbi_conn_new_r ("sqlite3", dbi_instance); - else - PERR ("Attempt to connect with an uninitialized dbi_instance"); -#else - conn = dbi_conn_new ("sqlite3"); -#endif - - if (conn == nullptr) - { - PERR ("Unable to create sqlite3 dbi connection\n"); - qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); - LEAVE("Error"); - return; - } - - dbi_conn_error_handler (conn, sqlite3_error_fn, be); /* dbi-sqlite3 documentation says that sqlite3 doesn't take a "host" option */ options.push_back(std::make_pair("host", "localhost")); auto dirname = g_path_get_dirname (filepath.c_str()); @@ -292,20 +414,19 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, options.push_back(std::make_pair("sqlite3_dbdir", dirname)); if (basename != nullptr) g_free (basename); if (dirname != nullptr) g_free (dirname); - - try { - set_options(conn, options); - } - catch (std::runtime_error& err) + UriStrings uri; + auto conn = conn_setup ("sqlite3", qbe, sqlite3_error_fn, options, uri); + if (conn == nullptr) { - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); LEAVE("Error"); - return; + return; } - result = dbi_conn_connect (conn); + + auto result = dbi_conn_connect (conn); if (result < 0) { + dbi_conn_close(conn); PERR ("Unable to connect to %s: %d\n", book_id, result); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); LEAVE("Error"); @@ -314,22 +435,22 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, if (!conn_test_dbi_library(conn, qbe)) { - if (create && !file_exists) /* File didn't exist before, but it */ + if (create && !file_exists) { - /* does now, and we don't want to */ - dbi_conn_close (conn); /* leave it lying around. */ + /* File didn't exist before, but it does now, and we don't want to + * leave it lying around. + */ + dbi_conn_close (conn); conn = nullptr; g_unlink (filepath.c_str()); } - msg = "Bad DBI Library"; - LEAVE("Error"); + LEAVE("Bad DBI Library"); return; } if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) { qof_backend_set_error (qbe, ERR_BACKEND_LOCKED); - msg = "Locked"; - LEAVE("Error"); + LEAVE("Locked"); return; } @@ -343,7 +464,7 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, xaccLogSetBaseName (filepath.c_str()); PINFO ("logpath=%s", filepath.c_str() ? filepath.c_str() : "(null)"); - LEAVE ("%s", msg); + LEAVE (""); } template<> StrVec @@ -427,51 +548,6 @@ mysql_error_fn (dbi_conn conn, void* user_data) } } -/** - * Sets standard db options in a dbi_conn. - * - * @param qbe QOF backend - * @param conn dbi_conn connection - * @param host Hostname - * @param port Port number - * @param dbname Database name - * @param username User name - * @param password Password - * @return TRUE if successful, FALSE if error - */ -static bool -set_standard_connection_options (QofBackend* qbe, dbi_conn conn, - const UriStrings& uri) - -{ - gint result; - PairVec options; - options.push_back(std::make_pair("host", uri.m_host)); - options.push_back(std::make_pair("dbname", uri.m_dbname)); - options.push_back(std::make_pair("username", uri.m_username)); - options.push_back(std::make_pair("password", uri.m_password)); - options.push_back(std::make_pair("encoding", "UTF-8")); - try - { - set_options(conn, options); - auto result = dbi_conn_set_option_numeric(conn, "port", uri.m_portnum); - if (result < 0) - { - const char *msg = nullptr; - auto err = dbi_conn_error(conn, &msg); - PERR("Error setting port option to %d: %s", uri.m_portnum, msg); - throw std::runtime_error(msg); - } - } - catch (std::runtime_error& err) - { - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - return false; - } - - - return true; -} /* FIXME: Move to GncDbiSqlConnection. */ static gboolean @@ -672,10 +748,6 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, gboolean create, gboolean force) { GncDbiBackend* be = (GncDbiBackend*)qbe; - gchar* basename = nullptr; - gchar* translog_path = nullptr; - gint result; - gboolean success = FALSE; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; PairVec options; @@ -690,34 +762,17 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, where username, password and port are optional) */ UriStrings uri(book_id); - // Try to connect to the db. If it doesn't exist and the create - // flag is TRUE, we'll need to connect to the 'mysql' db and execute the - // CREATE DATABASE ddl statement there. be->connect(nullptr); - dbi_conn conn; -#if HAVE_LIBDBI_R - if (dbi_instance) - conn = dbi_conn_new_r ("mysql", dbi_instance); - else - PERR ("Attempt to connect with an uninitialized dbi_instance"); -#else - conn = dbi_conn_new ("mysql"); -#endif + + auto conn = conn_setup("mysql", qbe, mysql_error_fn, options, uri); if (conn == nullptr) { - PERR ("Unable to create mysql dbi connection\n"); - qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); LEAVE("Error"); return; } - dbi_conn_error_handler (conn, mysql_error_fn, be); - if (!set_standard_connection_options (qbe, conn, uri)) - { - LEAVE("Error"); - return; - } - be->set_exists(true); - result = dbi_conn_connect (conn); + + be->set_exists(true); //May be unset in the error handler. + auto result = dbi_conn_connect (conn); if (result == 0) { adjust_sql_options (conn); @@ -734,7 +789,8 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, return; } - success = gnc_dbi_lock_database (qbe, conn, ignore_lock); + if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) + return; } else { @@ -747,67 +803,14 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, return; } - // The db does not already exist. Connect to the 'mysql' db and try to create it. if (create) { - options.push_back(std::make_pair("dbname", "mysql")); - try + if (!create_database(DbType::DBI_MYSQL, qbe, conn, uri.dbname())) { - set_options(conn, options); - } - catch (std::runtime_error& err) - { - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); LEAVE("Error"); return; } - - result = dbi_conn_connect (conn); - if (result < 0) - { - PERR ("Unable to connect to 'mysql' database\n"); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - LEAVE("Error"); - return; - } - adjust_sql_options (conn); - auto dresult = dbi_conn_queryf (conn, - "CREATE DATABASE %s CHARACTER SET utf8", - uri.dbname()); - if (dresult == nullptr) - { - PERR ("Unable to create database '%s'\n", uri.dbname()); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - LEAVE("Error"); - return; - } - dbi_conn_close (conn); - conn = nullptr; - - // Try again to connect to the db -#if HAVE_LIBDBI_R - if (dbi_instance) - conn = dbi_conn_new_r ("mysql", dbi_instance); - else - PERR ("Attempt to connect with an uninitialized dbi_instance"); -#else - conn = dbi_conn_new ("mysql"); -#endif - - if (conn == nullptr) - { - PERR ("Unable to create mysql dbi connection\n"); - qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); - LEAVE("Error"); - return; - } - dbi_conn_error_handler (conn, mysql_error_fn, be); - uri.m_portnum = 0; - if (!set_standard_connection_options (qbe, conn, uri)) - { - LEAVE("Error: Failed to set options."); - return; - } + conn = conn_setup("mysql", qbe, mysql_error_fn, options, uri); result = dbi_conn_connect (conn); if (result < 0) { @@ -822,7 +825,8 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, dbi_conn_queryf (conn, "DROP DATABASE %s", uri.dbname()); return; } - success = gnc_dbi_lock_database (qbe, conn, ignore_lock); + if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) + return; } else { @@ -831,17 +835,14 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, } } - if (success) - { - be->connect(nullptr); - be->connect( - new GncDbiSqlConnection (new GncDbiProviderImpl, - qbe, conn, lock_table)); - } + be->connect(nullptr); + be->connect( + new GncDbiSqlConnection (new GncDbiProviderImpl, + qbe, conn, lock_table)); /* We should now have a proper session set up. * Let's start logging */ - translog_path = gnc_build_translog_path (uri.basename().c_str()); + auto translog_path = gnc_build_translog_path (uri.basename().c_str()); xaccLogSetBaseName (translog_path); PINFO ("logpath=%s", translog_path ? translog_path : "(null)"); g_free (translog_path); @@ -954,9 +955,7 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, gboolean create, gboolean force) { GncDbiBackend* be = (GncDbiBackend*)qbe; - gint result = 0; - gboolean success = FALSE; - GncDbiTestResult dbi_test_result = GNC_DBI_PASS; + bool success = false; PairVec options; g_return_if_fail (qbe != nullptr); @@ -978,35 +977,17 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, auto lcname = g_utf8_strdown (uri.dbname(), -1); uri.m_dbname = std::string{lcname}; g_free(lcname); - // Try to connect to the db. If it doesn't exist and the create - // flag is TRUE, we'll need to connect to the 'postgres' db and execute the - // CREATE DATABASE ddl statement there. be->connect(nullptr); - dbi_conn conn; -#if HAVE_LIBDBI_R - if (dbi_instance) - conn = dbi_conn_new_r ("pgsql", dbi_instance); - else - PERR ("Attempt to connect with an uninitialized dbi_instance"); -#else - conn = dbi_conn_new ("pgsql"); -#endif + auto conn = conn_setup("pgsql", qbe, pgsql_error_fn, options, uri); if (conn == nullptr) { - PERR ("Unable to create pgsql dbi connection\n"); - qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); LEAVE("Error"); - return; + return; } - dbi_conn_error_handler (conn, pgsql_error_fn, be); - if (!set_standard_connection_options (qbe, conn, uri)) - { - LEAVE("Error"); - return; - } - be->set_exists(true); - result = dbi_conn_connect (conn); + + be->set_exists(true); //May be unset in the error handler. + auto result = dbi_conn_connect (conn); if (result == 0) { if (!conn_test_dbi_library(conn, qbe)) @@ -1022,7 +1003,8 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, return; } - success = gnc_dbi_lock_database (qbe, conn, ignore_lock); + if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) + return; } else { @@ -1035,66 +1017,14 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, return; } - // The db does not already exist. Connect to the 'postgres' db and try to create it. if (create) { - options.push_back(std::make_pair("dbname", "postgres")); - try - { - set_options(conn, options); - } - catch (std::runtime_error& err) - { - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - LEAVE("Error"); - return; - } - - result = dbi_conn_connect (conn); - if (result < 0) - { - PERR ("Unable to connect to 'postgres' database\n"); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - LEAVE("Error"); - return; - } - auto dresult = dbi_conn_queryf (conn, - "CREATE DATABASE %s WITH TEMPLATE template0 ENCODING 'UTF8'", uri.dbname()); - if (dresult == nullptr) - { - PERR ("Unable to create database '%s'\n", uri.dbname()); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - LEAVE("Error"); - return; - } - dbi_conn_queryf (conn, - "ALTER DATABASE %s SET standard_conforming_strings TO on", uri.dbname()); - dbi_conn_close (conn); - - // Try again to connect to the db -#if HAVE_LIBDBI_R - if (dbi_instance) - conn = dbi_conn_new_r ("pgsql", dbi_instance); - else - PERR ("Attempt to connect with an uninitialized dbi_instance"); -#else - conn = dbi_conn_new ("pgsql"); -#endif - - if (conn == nullptr) - { - PERR ("Unable to create pgsql dbi connection\n"); - qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); - LEAVE("Error"); - return; - } - dbi_conn_error_handler (conn, pgsql_error_fn, be); - uri.m_portnum = PGSQL_DEFAULT_PORT; - if (!set_standard_connection_options (qbe, conn, uri)) + if (!create_database(DbType::DBI_PGSQL, qbe, conn, uri.dbname())) { LEAVE("Error"); return; } + conn = conn_setup("pgsql", qbe, pgsql_error_fn, options, uri); result = dbi_conn_connect (conn); if (result < 0) { @@ -1110,7 +1040,8 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, LEAVE("Error"); return; } - success = gnc_dbi_lock_database (qbe, conn, ignore_lock); + if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) + return; } else { @@ -1118,13 +1049,10 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, qof_backend_set_message (qbe, "Database %s not found", uri.dbname()); } } - if (success) - { - be->connect(nullptr); - be->connect( + be->connect(nullptr); + be->connect( new GncDbiSqlConnection (new GncDbiProviderImpl, qbe, conn, lock_table)); - } /* We should now have a proper session set up. * Let's start logging */ From 61beed5686d840405325a278d2835e72fe927230 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 26 Jul 2016 17:38:11 -0700 Subject: [PATCH 47/63] Make sure that all of the GncDbiProviderImpl functions are in the right file. Also merge create_table_ddl back into the only function that used it. --- src/backend/dbi/gnc-backend-dbi.cpp | 103 ----------------- src/backend/dbi/gnc-backend-dbi.hpp | 9 ++ src/backend/dbi/gnc-dbiprovider.hpp | 3 - src/backend/dbi/gnc-dbiproviderimpl.hpp | 139 +++++++++++++++++------ src/backend/dbi/gnc-dbisqlconnection.cpp | 15 ++- src/backend/dbi/gnc-dbisqlconnection.hpp | 2 - 6 files changed, 129 insertions(+), 142 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index eb518d02da..f4216d9cc8 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -467,34 +467,6 @@ gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, LEAVE (""); } -template<> StrVec -GncDbiProviderImpl::get_index_list (dbi_conn conn) -{ - StrVec retval; - const char* errmsg; - dbi_result result = dbi_conn_query (conn, - "SELECT name FROM sqlite_master WHERE type = 'index' AND name NOT LIKE 'sqlite_autoindex%'"); - if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) - { - PWARN ("Index Table Retrieval Error: %s\n", errmsg); - return retval; - } - while (dbi_result_next_row (result) != 0) - { - std::string index_name {dbi_result_get_string_idx (result, 1)}; - retval.push_back(index_name); - } - dbi_result_free (result); - return retval; -} - -template void -GncDbiProviderImpl

::drop_index(dbi_conn conn, const std::string& index) -{ - dbi_result result = dbi_conn_queryf (conn, "DROP INDEX %s", index.c_str()); - if (result) - dbi_result_free (result); -} static void mysql_error_fn (dbi_conn conn, void* user_data) @@ -850,60 +822,6 @@ gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, LEAVE (" "); } -template<> StrVec -GncDbiProviderImpl::get_index_list (dbi_conn conn) -{ - StrVec retval; - const char* errmsg; - auto dbname = dbi_conn_get_option (conn, "dbname"); - auto table_list = dbi_conn_get_table_list (conn, dbname, nullptr); - if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) - { - PWARN ("Table Retrieval Error: %s\n", errmsg); - return retval; - } - while (dbi_result_next_row (table_list) != 0) - { - auto table_name = dbi_result_get_string_idx (table_list, 1); - auto result = dbi_conn_queryf (conn, - "SHOW INDEXES IN %s WHERE Key_name != 'PRIMARY'", - table_name); - if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) - { - PWARN ("Index Table Retrieval Error: %s on table %s\n", - errmsg, table_name); - continue; - } - - while (dbi_result_next_row (result) != 0) - { - std::string index_name {dbi_result_get_string_idx (result, 3)}; - retval.push_back(index_name + " " + table_name); - } - dbi_result_free (result); - } - - return retval; -} - -template<> void -GncDbiProviderImpl::drop_index (dbi_conn conn, const std::string& index) -{ - auto sep = index.find(' ', 0); - if (index.find(' ', sep + 1) != std::string::npos) - { - PWARN("Drop index error: invalid MySQL index format (

): %s", - index.c_str()); - return; - } - - auto result = dbi_conn_queryf (conn, "DROP INDEX %s ON %s", - index.substr(0, sep).c_str(), - index.substr(sep + 1).c_str()); - if (result) - dbi_result_free (result); -} - static void pgsql_error_fn (dbi_conn conn, void* user_data) { @@ -1064,27 +982,6 @@ gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, LEAVE (" "); } -template<> StrVec -GncDbiProviderImpl::get_index_list (dbi_conn conn) -{ - StrVec retval; - const char* errmsg; - PINFO ("Retrieving postgres index list\n"); - auto result = dbi_conn_query (conn, - "SELECT relname FROM pg_class AS a INNER JOIN pg_index AS b ON (b.indexrelid = a.oid) INNER JOIN pg_namespace AS c ON (a.relnamespace = c.oid) WHERE reltype = '0' AND indisprimary = 'f' AND nspname = 'public'"); - if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) - { - PWARN("Index Table Retrieval Error: %s\n", errmsg); - return retval; - } - while (dbi_result_next_row (result) != 0) - { - std::string index_name {dbi_result_get_string_idx (result, 1)}; - retval.push_back(index_name); - } - dbi_result_free (result); - return retval; -} /* ================================================================= */ diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index b959f51f15..b3e30462fa 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -68,6 +68,15 @@ typedef enum GNC_DBI_FAIL_TEST } GncDbiTestResult; +/** + * Supported Dbi Backends. + */ +enum class DbType +{ + DBI_SQLITE, /**< Sqlite3 */ + DBI_MYSQL, /**< MySQL and probably MariaDB */ + DBI_PGSQL /**< Postgresql */ +}; /** * Implementations of GncSqlBackend. diff --git a/src/backend/dbi/gnc-dbiprovider.hpp b/src/backend/dbi/gnc-dbiprovider.hpp index 21d749e713..453b911a67 100644 --- a/src/backend/dbi/gnc-dbiprovider.hpp +++ b/src/backend/dbi/gnc-dbiprovider.hpp @@ -42,9 +42,6 @@ class GncDbiProvider { public: virtual ~GncDbiProvider() = default; - virtual std::string create_table_ddl(const GncSqlConnection* conn, - const std::string& table_name, - const ColVec& info_vec) = 0; virtual StrVec get_table_list(dbi_conn conn, const std::string& dbname) = 0; virtual void append_col_def(std::string& ddl, const GncSqlColumnInfo& info) = 0; diff --git a/src/backend/dbi/gnc-dbiproviderimpl.hpp b/src/backend/dbi/gnc-dbiproviderimpl.hpp index 2b9103a381..f991be649b 100644 --- a/src/backend/dbi/gnc-dbiproviderimpl.hpp +++ b/src/backend/dbi/gnc-dbiproviderimpl.hpp @@ -30,22 +30,12 @@ extern "C" #include "gnc-backend-dbi.hpp" #include "gnc-dbiprovider.hpp" -enum class DbType -{ - DBI_SQLITE, - DBI_MYSQL, - DBI_PGSQL -}; template class GncDbiProviderImpl : public GncDbiProvider { public: - std::string create_table_ddl(const GncSqlConnection* conn, - const std::string& table_name, - const ColVec& info_vec); - StrVec get_table_list(dbi_conn conn, - const std::string& dbname); + StrVec get_table_list(dbi_conn conn, const std::string& dbname); void append_col_def(std::string& ddl, const GncSqlColumnInfo& info); StrVec get_index_list (dbi_conn conn); void drop_index(dbi_conn conn, const std::string& index); @@ -98,28 +88,6 @@ GncDbiProviderImpl::append_col_def(std::string& ddl, } } -template std::string -GncDbiProviderImpl

::create_table_ddl (const GncSqlConnection* conn, - const std::string& table_name, - const ColVec& info_vec) -{ - std::string ddl; - unsigned int col_num = 0; - - g_return_val_if_fail (conn != nullptr, ddl); - ddl += "CREATE TABLE " + table_name + "("; - for (auto const& info : info_vec) - { - if (col_num++ != 0) - { - ddl += ", "; - } - append_col_def (ddl, info); - } - ddl += ")"; - - return ddl; -} template<> void GncDbiProviderImpl::append_col_def (std::string& ddl, @@ -290,4 +258,109 @@ GncDbiProviderImpl::get_table_list (dbi_conn conn, return list; } +template<> StrVec +GncDbiProviderImpl::get_index_list (dbi_conn conn) +{ + StrVec retval; + const char* errmsg; + dbi_result result = dbi_conn_query (conn, + "SELECT name FROM sqlite_master WHERE type = 'index' AND name NOT LIKE 'sqlite_autoindex%'"); + if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) + { + PWARN ("Index Table Retrieval Error: %s\n", errmsg); + return retval; + } + while (dbi_result_next_row (result) != 0) + { + std::string index_name {dbi_result_get_string_idx (result, 1)}; + retval.push_back(index_name); + } + dbi_result_free (result); + return retval; +} + +template<> StrVec +GncDbiProviderImpl::get_index_list (dbi_conn conn) +{ + StrVec retval; + const char* errmsg; + auto dbname = dbi_conn_get_option (conn, "dbname"); + auto table_list = dbi_conn_get_table_list (conn, dbname, nullptr); + if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) + { + PWARN ("Table Retrieval Error: %s\n", errmsg); + return retval; + } + while (dbi_result_next_row (table_list) != 0) + { + auto table_name = dbi_result_get_string_idx (table_list, 1); + auto result = dbi_conn_queryf (conn, + "SHOW INDEXES IN %s WHERE Key_name != 'PRIMARY'", + table_name); + if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) + { + PWARN ("Index Table Retrieval Error: %s on table %s\n", + errmsg, table_name); + continue; + } + + while (dbi_result_next_row (result) != 0) + { + std::string index_name {dbi_result_get_string_idx (result, 3)}; + retval.push_back(index_name + " " + table_name); + } + dbi_result_free (result); + } + + return retval; +} + +template<> StrVec +GncDbiProviderImpl::get_index_list (dbi_conn conn) +{ + StrVec retval; + const char* errmsg; + PINFO ("Retrieving postgres index list\n"); + auto result = dbi_conn_query (conn, + "SELECT relname FROM pg_class AS a INNER JOIN pg_index AS b ON (b.indexrelid = a.oid) INNER JOIN pg_namespace AS c ON (a.relnamespace = c.oid) WHERE reltype = '0' AND indisprimary = 'f' AND nspname = 'public'"); + if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) + { + PWARN("Index Table Retrieval Error: %s\n", errmsg); + return retval; + } + while (dbi_result_next_row (result) != 0) + { + std::string index_name {dbi_result_get_string_idx (result, 1)}; + retval.push_back(index_name); + } + dbi_result_free (result); + return retval; +} + +template void +GncDbiProviderImpl

::drop_index(dbi_conn conn, const std::string& index) +{ + dbi_result result = dbi_conn_queryf (conn, "DROP INDEX %s", index.c_str()); + if (result) + dbi_result_free (result); +} + +template<> void +GncDbiProviderImpl::drop_index (dbi_conn conn, const std::string& index) +{ + + auto sep = index.find(' ', 0); + if (index.find(' ', sep + 1) != std::string::npos) + { + PWARN("Drop index error: invalid MySQL index format (

): %s", + index.c_str()); + return; + } + + auto result = dbi_conn_queryf (conn, "DROP INDEX %s ON %s", + index.substr(0, sep).c_str(), + index.substr(sep + 1).c_str()); + if (result) + dbi_result_free (result); +} #endif //__GNC_DBISQLPROVIDERIMPL_HPP__ diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index c866cb5069..454e72ceb0 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -330,7 +330,20 @@ bool GncDbiSqlConnection::create_table (const std::string& table_name, const ColVec& info_vec) const noexcept { - auto ddl = m_provider->create_table_ddl(this, table_name, info_vec); + std::string ddl; + unsigned int col_num = 0; + + ddl += "CREATE TABLE " + table_name + "("; + for (auto const& info : info_vec) + { + if (col_num++ != 0) + { + ddl += ", "; + } + m_provider->append_col_def (ddl, info); + } + ddl += ")"; + if (ddl.empty()) return false; diff --git a/src/backend/dbi/gnc-dbisqlconnection.hpp b/src/backend/dbi/gnc-dbisqlconnection.hpp index 547ae2b295..87e9b34cab 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.hpp +++ b/src/backend/dbi/gnc-dbisqlconnection.hpp @@ -78,8 +78,6 @@ public: bool verify() noexcept override; bool retry_connection(const char* msg) noexcept override; dbi_result table_manage_backup(const std::string& table_name, TableOpType op); - /* FIXME: These three friend functions should really be members, but doing - * that is too invasive just yet. */ bool table_operation (const StrVec& table_name_list, TableOpType op) noexcept; std::string add_columns_ddl(const std::string& table_name, From fc47b63265f33794720c5988e65da798000c35a5 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 26 Jul 2016 17:40:29 -0700 Subject: [PATCH 48/63] Templatize the session_begin functions and new_backend(). Thus removing the need for specializations of QofDbiBackendProvider::create_backend(). --- src/backend/dbi/gnc-backend-dbi.cpp | 96 ++++++++++++++--------------- 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index f4216d9cc8..1f87d80483 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -109,16 +109,51 @@ static gchar lock_table[] = "gnclock"; #define SQLITE3_URI_PREFIX (SQLITE3_URI_TYPE "://") #define PGSQL_DEFAULT_PORT 5432 -#define SQLITE3_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" -#define MYSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d" -#define PGSQL_TIMESPEC_STR_FORMAT "%04d%02d%02d %02d%02d%02d" +constexpr const char* SQLITE3_TIMESPEC_STR_FORMAT = "%04d%02d%02d%02d%02d%02d"; +constexpr const char* MYSQL_TIMESPEC_STR_FORMAT = "%04d%02d%02d%02d%02d%02d"; +constexpr const char* PGSQL_TIMESPEC_STR_FORMAT = "%04d%02d%02d %02d%02d%02d"; static void adjust_sql_options (dbi_conn connection); static gboolean gnc_dbi_lock_database (QofBackend*, dbi_conn, gboolean); static gboolean save_may_clobber_data (QofBackend* qbe); +static void init_sql_backend (GncDbiBackend* dbi_be); static bool conn_test_dbi_library (dbi_conn conn, QofBackend* qbe); +template void gnc_dbi_session_begin(QofBackend* qbe, + QofSession* session, + const gchar* book_id, + gboolean ignore_lock, + gboolean create, gboolean force); +template QofBackend* +new_backend () +{ + QofBackend* be; + const char* format; + switch (Type) + { + case (DbType::DBI_SQLITE): + format = SQLITE3_TIMESPEC_STR_FORMAT; + break; + case (DbType::DBI_MYSQL): + format = MYSQL_TIMESPEC_STR_FORMAT; + break; + case (DbType::DBI_PGSQL): + format = PGSQL_TIMESPEC_STR_FORMAT; + break; + } + auto dbi_be = new GncDbiBackend(nullptr, nullptr, format); + g_assert (dbi_be != nullptr); + + be = (QofBackend*)dbi_be; + qof_backend_init (be); + + be->session_begin = gnc_dbi_session_begin; + init_sql_backend (dbi_be); + + return be; +} + template class QofDbiBackendProvider : public QofBackendProvider { @@ -130,7 +165,7 @@ public: QofDbiBackendProvider(QofDbiBackendProvider&&) = delete; QofDbiBackendProvider operator=(QofDbiBackendProvider&&) = delete; ~QofDbiBackendProvider () = default; - QofBackend* create_backend(void); + QofBackend* create_backend(void) { return new_backend(); } bool type_check(const char* type) { return true; } }; @@ -363,8 +398,8 @@ sqlite3_error_fn (dbi_conn conn, void* user_data) be->set_error (ERR_BACKEND_MISC, 0, false); } -void -gnc_dbi_sqlite3_session_begin (QofBackend* qbe, QofSession* session, +template <> void +gnc_dbi_session_begin(QofBackend* qbe, QofSession* session, const gchar* book_id, gboolean ignore_lock, gboolean create, gboolean force) { @@ -714,8 +749,8 @@ adjust_sql_options (dbi_conn connection) } -static void -gnc_dbi_mysql_session_begin (QofBackend* qbe, QofSession* session, +template <> void +gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, const gchar* book_id, gboolean ignore_lock, gboolean create, gboolean force) { @@ -867,8 +902,8 @@ pgsql_error_fn (dbi_conn conn, void* user_data) } } -static void -gnc_dbi_postgres_session_begin (QofBackend* qbe, QofSession* session, +template <>void +gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, const gchar* book_id, gboolean ignore_lock, gboolean create, gboolean force) { @@ -1207,47 +1242,6 @@ init_sql_backend (GncDbiBackend* dbi_be) gnc_sql_init (dbi_be); } -static QofBackend* -new_backend (void (*session_begin) (QofBackend*, QofSession*, const gchar*, - gboolean, gboolean, gboolean), - const char* format) -{ - QofBackend* be; - - auto dbi_be = new GncDbiBackend(nullptr, nullptr, format); - g_assert (dbi_be != nullptr); - - be = (QofBackend*)dbi_be; - qof_backend_init (be); - - be->session_begin = session_begin; - init_sql_backend (dbi_be); - - return be; -} - -template<> QofBackend* -QofDbiBackendProvider::create_backend() -{ - return new_backend (gnc_dbi_sqlite3_session_begin, - SQLITE3_TIMESPEC_STR_FORMAT); -} - -template<> QofBackend* -QofDbiBackendProvider::create_backend() -{ - return new_backend (gnc_dbi_mysql_session_begin, - MYSQL_TIMESPEC_STR_FORMAT); -} - -template<> QofBackend* -QofDbiBackendProvider::create_backend() -{ - return new_backend (gnc_dbi_postgres_session_begin, - PGSQL_TIMESPEC_STR_FORMAT); -} - - /* * Checks to see whether the file is an sqlite file or not *1980 From 00e0a6e8b62cab8be1c2a4503fcecd056c28ee63 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Thu, 28 Jul 2016 09:18:25 -0700 Subject: [PATCH 49/63] Change parameter of save_may_clobber_data from QofBackend to dbi_conn. It actually needs the dbi_conn and that's known to its caller. Plus, the backend's conn parameter hasn't actually been set so it was somewhat coincidental that it worked. --- src/backend/dbi/gnc-backend-dbi.cpp | 19 ++++++++----------- src/backend/dbi/gnc-backend-dbi.hpp | 2 -- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 1f87d80483..1d1ee0487d 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -115,7 +115,7 @@ constexpr const char* PGSQL_TIMESPEC_STR_FORMAT = "%04d%02d%02d %02d%02d%02d"; static void adjust_sql_options (dbi_conn connection); static gboolean gnc_dbi_lock_database (QofBackend*, dbi_conn, gboolean); -static gboolean save_may_clobber_data (QofBackend* qbe); +static bool save_may_clobber_data (dbi_conn conn); static void init_sql_backend (GncDbiBackend* dbi_be); static bool conn_test_dbi_library (dbi_conn conn, QofBackend* qbe); @@ -788,7 +788,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, LEAVE("Error"); return; } - if (create && !force && save_may_clobber_data (qbe)) + if (create && !force && save_may_clobber_data (conn)) { qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS); PWARN ("Databse already exists, Might clobber it."); @@ -948,7 +948,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, LEAVE("Error"); return; } - if (create && !force && save_may_clobber_data (qbe)) + if (create && !force && save_may_clobber_data(conn)) { qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS); PWARN ("Databse already exists, Might clobber it."); @@ -1106,17 +1106,14 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) /* ================================================================= */ -static gboolean -save_may_clobber_data (QofBackend* qbe) +static bool +save_may_clobber_data (dbi_conn conn) { - GncDbiBackend* be = (GncDbiBackend*)qbe; - const gchar* dbname; - dbi_result result; - gboolean retval = FALSE; /* Data may be clobbered iff the number of tables != 0 */ - dbname = dbi_conn_get_option (be->conn(), "dbname"); - result = dbi_conn_get_table_list (be->conn(), dbname, nullptr); + auto dbname = dbi_conn_get_option (conn, "dbname"); + auto result = dbi_conn_get_table_list (conn, dbname, nullptr); + bool retval = false; if (result) { retval = dbi_result_get_numrows (result) > 0; diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index b3e30462fa..cf1b1abae2 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -97,8 +97,6 @@ public: { m_conn->retry_connection(msg); } - /* Worst of all: */ - GncSqlConnection* conn() { return m_conn; } /*-----*/ bool exists() { return m_exists; } void set_exists(bool exists) { m_exists = exists; } From 314a5e10c2380bc29398d91afd3fdfcc2ae28146 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Thu, 28 Jul 2016 15:45:38 -0700 Subject: [PATCH 50/63] Make gnc_lock_database a GncDbiSqlConnection member function. Called from the constructor, so effective RAII with unlock_database called from the destructor. --- src/backend/dbi/gnc-backend-dbi.cpp | 185 ++++------------------- src/backend/dbi/gnc-dbiprovider.hpp | 2 + src/backend/dbi/gnc-dbiproviderimpl.hpp | 7 +- src/backend/dbi/gnc-dbisqlconnection.cpp | 112 +++++++++++++- src/backend/dbi/gnc-dbisqlconnection.hpp | 18 ++- 5 files changed, 152 insertions(+), 172 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 1d1ee0487d..1e2ad4d239 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -101,8 +101,6 @@ static QofLogModule log_module = G_LOG_DOMAIN; // gnc-dbiproviderimpl.hpp has templates that need log_module defined. #include "gnc-dbiproviderimpl.hpp" -static gchar lock_table[] = "gnclock"; - #define FILE_URI_TYPE "file" #define FILE_URI_PREFIX (FILE_URI_TYPE "://") #define SQLITE3_URI_TYPE "sqlite3" @@ -114,7 +112,6 @@ constexpr const char* MYSQL_TIMESPEC_STR_FORMAT = "%04d%02d%02d%02d%02d%02d"; constexpr const char* PGSQL_TIMESPEC_STR_FORMAT = "%04d%02d%02d %02d%02d%02d"; static void adjust_sql_options (dbi_conn connection); -static gboolean gnc_dbi_lock_database (QofBackend*, dbi_conn, gboolean); static bool save_may_clobber_data (dbi_conn conn); static void init_sql_backend (GncDbiBackend* dbi_be); @@ -480,19 +477,18 @@ gnc_dbi_session_begin(QofBackend* qbe, QofSession* session, g_unlink (filepath.c_str()); } LEAVE("Bad DBI Library"); - return; - } - if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) - { - qof_backend_set_error (qbe, ERR_BACKEND_LOCKED); - LEAVE("Locked"); - return; } be->connect(nullptr); - be->connect( - new GncDbiSqlConnection (new GncDbiProviderImpl, - qbe, conn, lock_table)); + try + { + be->connect(new GncDbiSqlConnection(make_dbi_provider(), + qbe, conn, ignore_lock)); + } + catch (std::runtime_error& err) + { + return; + } /* We should now have a proper session set up. * Let's start logging */ @@ -555,136 +551,6 @@ mysql_error_fn (dbi_conn conn, void* user_data) } } - -/* FIXME: Move to GncDbiSqlConnection. */ -static gboolean -gnc_dbi_lock_database (QofBackend* qbe, dbi_conn conn, gboolean ignore_lock) -{ - - GncDbiBackend* qe = (GncDbiBackend*)qbe; - - dbi_result result; - const gchar* dbname = dbi_conn_get_option (conn, "dbname"); - /* Create the table if it doesn't exist */ - result = dbi_conn_get_table_list (conn, dbname, lock_table); - if (! (result && dbi_result_get_numrows (result))) - { - if (result) - { - dbi_result_free (result); - result = nullptr; - } - result = dbi_conn_queryf (conn, - "CREATE TABLE %s ( Hostname varchar(%d), PID int )", lock_table, - GNC_HOST_NAME_MAX); - if (dbi_conn_error (conn, nullptr)) - { - const gchar* errstr; - dbi_conn_error (conn, &errstr); - PERR ("Error %s creating lock table", errstr); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - if (result) - { - dbi_result_free (result); - result = nullptr; - } - return FALSE; - } - if (result) - { - dbi_result_free (result); - result = nullptr; - } - } - if (result) - { - dbi_result_free (result); - result = nullptr; - } - - /* Protect everything with a single transaction to prevent races */ - if ((result = dbi_conn_query (conn, "BEGIN"))) - { - /* Check for an existing entry; delete it if ignore_lock is true, otherwise fail */ - gchar hostname[ GNC_HOST_NAME_MAX + 1 ]; - if (result) - { - dbi_result_free (result); - result = nullptr; - } - result = dbi_conn_queryf (conn, "SELECT * FROM %s", lock_table); - if (result && dbi_result_get_numrows (result)) - { - dbi_result_free (result); - result = nullptr; - if (!ignore_lock) - { - qof_backend_set_error (qbe, ERR_BACKEND_LOCKED); - /* FIXME: After enhancing the qof_backend_error mechanism, report in the dialog what is the hostname of the machine holding the lock. */ - dbi_conn_query (conn, "ROLLBACK"); - return FALSE; - } - result = dbi_conn_queryf (conn, "DELETE FROM %s", lock_table); - if (!result) - { - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - qof_backend_set_message (qbe, "Failed to delete lock record"); - result = dbi_conn_query (conn, "ROLLBACK"); - if (result) - { - dbi_result_free (result); - result = nullptr; - } - return FALSE; - } - if (result) - { - dbi_result_free (result); - result = nullptr; - } - } - /* Add an entry and commit the transaction */ - memset (hostname, 0, sizeof (hostname)); - gethostname (hostname, GNC_HOST_NAME_MAX); - result = dbi_conn_queryf (conn, - "INSERT INTO %s VALUES ('%s', '%d')", - lock_table, hostname, (int)GETPID ()); - if (!result) - { - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - qof_backend_set_message (qbe, "Failed to create lock record"); - result = dbi_conn_query (conn, "ROLLBACK"); - if (result) - { - dbi_result_free (result); - result = nullptr; - } - return FALSE; - } - if (result) - { - dbi_result_free (result); - result = nullptr; - } - result = dbi_conn_query (conn, "COMMIT"); - if (result) - { - dbi_result_free (result); - result = nullptr; - } - return TRUE; - } - /* Couldn't get a transaction (probably couldn't get a lock), so fail */ - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - qof_backend_set_message (qbe, "SQL Backend failed to obtain a transaction"); - if (result) - { - dbi_result_free (result); - result = nullptr; - } - return FALSE; -} - #define SQL_OPTION_TO_REMOVE "NO_ZERO_DATE" /* Given an sql_options string returns a copy of the string adjusted as @@ -796,8 +662,6 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, return; } - if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) - return; } else { @@ -832,8 +696,6 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, dbi_conn_queryf (conn, "DROP DATABASE %s", uri.dbname()); return; } - if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) - return; } else { @@ -843,10 +705,15 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, } be->connect(nullptr); - be->connect( - new GncDbiSqlConnection (new GncDbiProviderImpl, - qbe, conn, lock_table)); - + try + { + be->connect(new GncDbiSqlConnection(make_dbi_provider(), + qbe, conn, ignore_lock)); + } + catch (std::runtime_error& err) + { + return; + } /* We should now have a proper session set up. * Let's start logging */ auto translog_path = gnc_build_translog_path (uri.basename().c_str()); @@ -956,8 +823,6 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, return; } - if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) - return; } else { @@ -993,8 +858,6 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, LEAVE("Error"); return; } - if (!gnc_dbi_lock_database (qbe, conn, ignore_lock)) - return; } else { @@ -1003,9 +866,15 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, } } be->connect(nullptr); - be->connect( - new GncDbiSqlConnection (new GncDbiProviderImpl, - qbe, conn, lock_table)); + try + { + be->connect(new GncDbiSqlConnection(make_dbi_provider(), + qbe, conn, ignore_lock)); + } + catch (std::runtime_error& err) + { + return; + } /* We should now have a proper session set up. * Let's start logging */ diff --git a/src/backend/dbi/gnc-dbiprovider.hpp b/src/backend/dbi/gnc-dbiprovider.hpp index 453b911a67..e0a25616bb 100644 --- a/src/backend/dbi/gnc-dbiprovider.hpp +++ b/src/backend/dbi/gnc-dbiprovider.hpp @@ -49,4 +49,6 @@ public: virtual void drop_index(dbi_conn conn, const std::string& index) = 0; }; +using GncDbiProviderPtr = std::unique_ptr; + #endif //__GNC_DBIPROVIDER_HPP__ diff --git a/src/backend/dbi/gnc-dbiproviderimpl.hpp b/src/backend/dbi/gnc-dbiproviderimpl.hpp index f991be649b..a96461b91b 100644 --- a/src/backend/dbi/gnc-dbiproviderimpl.hpp +++ b/src/backend/dbi/gnc-dbiproviderimpl.hpp @@ -30,7 +30,6 @@ extern "C" #include "gnc-backend-dbi.hpp" #include "gnc-dbiprovider.hpp" - template class GncDbiProviderImpl : public GncDbiProvider { @@ -41,6 +40,12 @@ public: void drop_index(dbi_conn conn, const std::string& index); }; +template GncDbiProviderPtr +make_dbi_provider() +{ + return GncDbiProviderPtr(new GncDbiProviderImpl); +} + template<> void GncDbiProviderImpl::append_col_def(std::string& ddl, const GncSqlColumnInfo& info) diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index 454e72ceb0..98b9617fda 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -33,6 +33,7 @@ extern "C" static QofLogModule log_module = G_LOG_DOMAIN; static const unsigned int DBI_MAX_CONN_ATTEMPTS = 5; +constexpr const char *lock_table_name = "gnclock"; /* --------------------------------------------------------- */ class GncDbiSqlStatement : public GncSqlStatement @@ -70,6 +71,108 @@ GncDbiSqlStatement::add_where_cond(QofIdTypeConst type_name, } } +bool +GncDbiSqlConnection::lock_database (bool ignore_lock) +{ + + auto dbname = dbi_conn_get_option (m_conn, "dbname"); + /* Create the table if it doesn't exist */ + auto result = dbi_conn_get_table_list (m_conn, dbname, lock_table_name); + int numrows = 0; + const char* errstr; + if (result) { + numrows = dbi_result_get_numrows (result); + dbi_result_free (result); + result = nullptr; + } + if (numrows == 0) + { + result = dbi_conn_queryf (m_conn, + "CREATE TABLE %s ( Hostname varchar(%d), PID int )", lock_table_name, + GNC_HOST_NAME_MAX); + if (result) + { + dbi_result_free (result); + result = nullptr; + } + if (dbi_conn_error (m_conn, &errstr)) + { + PERR ("Error %s creating lock table", errstr); + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + return false; + } + } + + /* Protect everything with a single transaction to prevent races */ + result = dbi_conn_query (m_conn, "BEGIN"); + if (dbi_conn_error (m_conn, &errstr)) + { + /* Couldn't get a transaction (probably couldn't get a lock), so fail */ + std::string err{"SQL Backend failed to obtain a transaction: "}; + err += errstr; + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_message (m_qbe, err.c_str()); + return false; + } + dbi_result_free(result); + result = nullptr; + /* Check for an existing entry; delete it if ignore_lock is true, otherwise fail */ + char hostname[ GNC_HOST_NAME_MAX + 1 ]; + result = dbi_conn_queryf (m_conn, "SELECT * FROM %s", lock_table_name); + if (result && dbi_result_get_numrows (result)) + { + dbi_result_free (result); + result = nullptr; + if (!ignore_lock) + { + qof_backend_set_error (m_qbe, ERR_BACKEND_LOCKED); + /* FIXME: After enhancing the qof_backend_error mechanism, report in the dialog what is the hostname of the machine holding the lock. */ + dbi_conn_query (m_conn, "ROLLBACK"); + return false; + } + result = dbi_conn_queryf (m_conn, "DELETE FROM %s", lock_table_name); + if (!result) + { + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_message (m_qbe, "Failed to delete lock record"); + result = dbi_conn_query (m_conn, "ROLLBACK"); + if (result) + dbi_result_free (result); + return false; + } + dbi_result_free (result); + result = nullptr; + } + /* Add an entry and commit the transaction */ + memset (hostname, 0, sizeof (hostname)); + gethostname (hostname, GNC_HOST_NAME_MAX); + result = dbi_conn_queryf (m_conn, + "INSERT INTO %s VALUES ('%s', '%d')", + lock_table_name, hostname, (int)GETPID ()); + if (!result) + { + qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); + qof_backend_set_message (m_qbe, "Failed to create lock record"); + result = dbi_conn_query (m_conn, "ROLLBACK"); + if (result) + dbi_result_free (result); + return false; + } + dbi_result_free (result); + result = dbi_conn_query (m_conn, "COMMIT"); + if (!result) + { + auto errnum = dbi_conn_error(m_conn, &errstr); + qof_backend_set_error(m_qbe, ERR_BACKEND_SERVER_ERR); + std::string err{"Failed to commit transaction: "}; + err += errstr; + qof_backend_set_message(m_qbe, err.c_str()); + return false; + } + dbi_result_free (result); + return true; +} + void GncDbiSqlConnection::unlock_database () { @@ -81,7 +184,7 @@ GncDbiSqlConnection::unlock_database () auto dbname = dbi_conn_get_option (m_conn, "dbname"); /* Check if the lock table exists */ g_return_if_fail (dbname != nullptr); - auto result = dbi_conn_get_table_list (m_conn, dbname, m_lock_table); + auto result = dbi_conn_get_table_list (m_conn, dbname, lock_table_name); if (! (result && dbi_result_get_numrows (result))) { if (result) @@ -105,7 +208,7 @@ GncDbiSqlConnection::unlock_database () memset (hostname, 0, sizeof (hostname)); gethostname (hostname, GNC_HOST_NAME_MAX); result = dbi_conn_queryf (m_conn, - "SELECT * FROM %s WHERE Hostname = '%s' AND PID = '%d'", m_lock_table, hostname, + "SELECT * FROM %s WHERE Hostname = '%s' AND PID = '%d'", lock_table_name, hostname, (int)GETPID ()); if (result && dbi_result_get_numrows (result)) { @@ -114,7 +217,7 @@ GncDbiSqlConnection::unlock_database () dbi_result_free (result); result = nullptr; } - result = dbi_conn_queryf (m_conn, "DELETE FROM %s", m_lock_table); + result = dbi_conn_queryf (m_conn, "DELETE FROM %s", lock_table_name); if (!result) { PERR ("Failed to delete the lock entry"); @@ -166,7 +269,6 @@ GncDbiSqlConnection::~GncDbiSqlConnection() dbi_conn_close(m_conn); m_conn = nullptr; } - delete m_provider; } GncSqlResultPtr @@ -542,7 +644,7 @@ GncDbiSqlConnection::table_operation(const StrVec& table_names, TableOpType op) noexcept { const char* dbname = dbi_conn_get_option (m_conn, "dbname"); - std::string lock_table{m_lock_table}; + std::string lock_table{lock_table_name}; g_return_val_if_fail (!table_names.empty(), FALSE); bool retval{true}; for (auto table : table_names) diff --git a/src/backend/dbi/gnc-dbisqlconnection.hpp b/src/backend/dbi/gnc-dbisqlconnection.hpp index 87e9b34cab..2118fe2fca 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.hpp +++ b/src/backend/dbi/gnc-dbisqlconnection.hpp @@ -35,11 +35,14 @@ class GncDbiProvider; class GncDbiSqlConnection : public GncSqlConnection { public: - GncDbiSqlConnection (GncDbiProvider* provider, QofBackend* qbe, - dbi_conn conn, const char* lock_table) : - m_qbe{qbe}, m_conn{conn}, m_provider{provider}, m_conn_ok{true}, - m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, m_retry{false}, - m_lock_table{lock_table} {} + GncDbiSqlConnection (std::unique_ptr provider, + QofBackend* qbe, dbi_conn conn, bool ignore_lock) : + m_qbe{qbe}, m_conn{conn}, m_provider{std::move(provider)}, + m_conn_ok{true}, m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, + m_retry{false} { + if (!lock_database(ignore_lock)) + throw std::runtime_error("Failed to lock database!"); + } ~GncDbiSqlConnection() override; GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr&) noexcept override; @@ -61,7 +64,6 @@ public: return dbi_conn_error(m_conn, nullptr); } QofBackend* qbe () const noexcept { return m_qbe; } dbi_conn conn() const noexcept { return m_conn; } - GncDbiProvider* provider() { return m_provider; } inline void set_error(int error, int repeat, bool retry) noexcept override { m_last_error = error; @@ -87,7 +89,7 @@ public: private: QofBackend* m_qbe; dbi_conn m_conn; - GncDbiProvider* m_provider; + std::unique_ptr m_provider; /** Used by the error handler routines to flag if the connection is ok to * use */ @@ -106,7 +108,7 @@ private: * original query) */ gboolean m_retry; - const char* m_lock_table; + bool lock_database(bool ignore_lock); void unlock_database(); }; From 5d38c7a7291cef83246bc0652d3e78fa44b995b5 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 29 Jul 2016 10:44:46 -0700 Subject: [PATCH 51/63] Make conn_setup and the error handler functions templates on DbType. --- src/backend/dbi/gnc-backend-dbi.cpp | 43 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 1e2ad4d239..afff9420e8 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -284,29 +284,34 @@ set_standard_connection_options (QofBackend* qbe, dbi_conn conn, return true; } -static dbi_conn -conn_setup (const char* dbtype, QofBackend* qbe, - dbi_conn_error_handler_func err_handler, PairVec& options, - UriStrings& uri) + +template void error_handler(void* conn, void* data); +void error_handler(void* conn, void* data); + +template dbi_conn +conn_setup (QofBackend* qbe, PairVec& options, + UriStrings& uri) { + const char* dbstr = (Type == DbType::DBI_SQLITE ? "sqlite3" : + Type == DbType::DBI_MYSQL ? "mysql" : "pgsql"); #if HAVE_LIBDBI_R dbi_conn conn; if (dbi_instance) - conn = dbi_conn_new_r (dbtype, dbi_instance); + conn = dbi_conn_new_r (dbstr, dbi_instance); else PERR ("Attempt to connect with an uninitialized dbi_instance"); #else - auto conn = dbi_conn_new (dbtype); + auto conn = dbi_conn_new (dbstr); #endif if (conn == nullptr) { - PERR ("Unable to create %s dbi connection", dbtype); + PERR ("Unable to create %s dbi connection", dbstr); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); return nullptr; } - dbi_conn_error_handler (conn, err_handler, qbe); + dbi_conn_error_handler (conn, error_handler, qbe); if (!uri.m_dbname.empty() && !set_standard_connection_options(qbe, conn, uri)) @@ -384,8 +389,8 @@ create_database(DbType type, QofBackend *qbe, dbi_conn conn, const char* db) return true; } -void -sqlite3_error_fn (dbi_conn conn, void* user_data) +template <> void +error_handler (dbi_conn conn, void* user_data) { const gchar* msg; GncDbiBackend *be = static_cast(user_data); @@ -447,7 +452,7 @@ gnc_dbi_session_begin(QofBackend* qbe, QofSession* session, if (basename != nullptr) g_free (basename); if (dirname != nullptr) g_free (dirname); UriStrings uri; - auto conn = conn_setup ("sqlite3", qbe, sqlite3_error_fn, options, uri); + auto conn = conn_setup(qbe, options, uri); if (conn == nullptr) { LEAVE("Error"); @@ -499,8 +504,8 @@ gnc_dbi_session_begin(QofBackend* qbe, QofSession* session, } -static void -mysql_error_fn (dbi_conn conn, void* user_data) +template <> void +error_handler (dbi_conn conn, void* user_data) { GncDbiBackend* be = (GncDbiBackend*)user_data; const char* msg; @@ -637,7 +642,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, be->connect(nullptr); - auto conn = conn_setup("mysql", qbe, mysql_error_fn, options, uri); + auto conn = conn_setup(qbe, options, uri); if (conn == nullptr) { LEAVE("Error"); @@ -681,7 +686,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, LEAVE("Error"); return; } - conn = conn_setup("mysql", qbe, mysql_error_fn, options, uri); + conn = conn_setup(qbe, options, uri); result = dbi_conn_connect (conn); if (result < 0) { @@ -724,8 +729,8 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, LEAVE (" "); } -static void -pgsql_error_fn (dbi_conn conn, void* user_data) +template<> void +error_handler (dbi_conn conn, void* user_data) { GncDbiBackend* be = (GncDbiBackend*)user_data; const gchar* msg; @@ -799,7 +804,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, g_free(lcname); be->connect(nullptr); - auto conn = conn_setup("pgsql", qbe, pgsql_error_fn, options, uri); + auto conn = conn_setup(qbe, options, uri); if (conn == nullptr) { LEAVE("Error"); @@ -842,7 +847,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, LEAVE("Error"); return; } - conn = conn_setup("pgsql", qbe, pgsql_error_fn, options, uri); + conn = conn_setup(qbe, options, uri); result = dbi_conn_connect (conn); if (result < 0) { From c141711425fd337aaa24efc4eca4c5702a89b5ba Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 29 Jul 2016 13:10:40 -0700 Subject: [PATCH 52/63] Move creation of the provider to GncDbiSqlConnection's constructor. Making GncDbiProviderImpl private to GncDbiSqlConnection. --- src/backend/dbi/gnc-backend-dbi.cpp | 10 ++++------ src/backend/dbi/gnc-dbisqlconnection.cpp | 17 +++++++++++++++++ src/backend/dbi/gnc-dbisqlconnection.hpp | 10 ++-------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index afff9420e8..ad5f0349bc 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -98,8 +98,6 @@ static dbi_inst dbi_instance = nullptr; #define TRANSACTION_NAME "trans" static QofLogModule log_module = G_LOG_DOMAIN; -// gnc-dbiproviderimpl.hpp has templates that need log_module defined. -#include "gnc-dbiproviderimpl.hpp" #define FILE_URI_TYPE "file" #define FILE_URI_PREFIX (FILE_URI_TYPE "://") @@ -288,7 +286,7 @@ set_standard_connection_options (QofBackend* qbe, dbi_conn conn, template void error_handler(void* conn, void* data); void error_handler(void* conn, void* data); -template dbi_conn +template dbi_conn conn_setup (QofBackend* qbe, PairVec& options, UriStrings& uri) { @@ -487,7 +485,7 @@ gnc_dbi_session_begin(QofBackend* qbe, QofSession* session, be->connect(nullptr); try { - be->connect(new GncDbiSqlConnection(make_dbi_provider(), + be->connect(new GncDbiSqlConnection(DbType::DBI_SQLITE, qbe, conn, ignore_lock)); } catch (std::runtime_error& err) @@ -712,7 +710,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, be->connect(nullptr); try { - be->connect(new GncDbiSqlConnection(make_dbi_provider(), + be->connect(new GncDbiSqlConnection(DbType::DBI_MYSQL, qbe, conn, ignore_lock)); } catch (std::runtime_error& err) @@ -873,7 +871,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, be->connect(nullptr); try { - be->connect(new GncDbiSqlConnection(make_dbi_provider(), + be->connect(new GncDbiSqlConnection(DbType::DBI_PGSQL, qbe, conn, ignore_lock)); } catch (std::runtime_error& err) diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index 98b9617fda..3f68e1e3e2 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -31,6 +31,8 @@ extern "C" #include "gnc-dbisqlconnection.hpp" static QofLogModule log_module = G_LOG_DOMAIN; +// gnc-dbiproviderimpl.hpp has templates that need log_module defined. +#include "gnc-dbiproviderimpl.hpp" static const unsigned int DBI_MAX_CONN_ATTEMPTS = 5; constexpr const char *lock_table_name = "gnclock"; @@ -71,6 +73,21 @@ GncDbiSqlStatement::add_where_cond(QofIdTypeConst type_name, } } +GncDbiSqlConnection::GncDbiSqlConnection (DbType type, QofBackend* qbe, + dbi_conn conn, bool ignore_lock) : + m_qbe{qbe}, m_conn{conn}, + m_provider{std::move(type == DbType::DBI_SQLITE ? + make_dbi_provider() : + type == DbType::DBI_MYSQL ? + make_dbi_provider() : + make_dbi_provider())}, + m_conn_ok{true}, m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, + m_retry{false} +{ + if (!lock_database(ignore_lock)) + throw std::runtime_error("Failed to lock database!"); +} + bool GncDbiSqlConnection::lock_database (bool ignore_lock) { diff --git a/src/backend/dbi/gnc-dbisqlconnection.hpp b/src/backend/dbi/gnc-dbisqlconnection.hpp index 2118fe2fca..b97520fbc5 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.hpp +++ b/src/backend/dbi/gnc-dbisqlconnection.hpp @@ -35,14 +35,8 @@ class GncDbiProvider; class GncDbiSqlConnection : public GncSqlConnection { public: - GncDbiSqlConnection (std::unique_ptr provider, - QofBackend* qbe, dbi_conn conn, bool ignore_lock) : - m_qbe{qbe}, m_conn{conn}, m_provider{std::move(provider)}, - m_conn_ok{true}, m_last_error{ERR_BACKEND_NO_ERR}, m_error_repeat{0}, - m_retry{false} { - if (!lock_database(ignore_lock)) - throw std::runtime_error("Failed to lock database!"); - } + GncDbiSqlConnection (DbType type, QofBackend* qbe, dbi_conn conn, + bool ignore_lock); ~GncDbiSqlConnection() override; GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr&) noexcept override; From 5065bce45c39c6281904139b63954947c3bdf552 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 29 Jul 2016 13:29:51 -0700 Subject: [PATCH 53/63] Combine Postgres and MySql gnc_dbi_session_begin into a single template. --- src/backend/dbi/gnc-backend-dbi.cpp | 158 ++++++---------------------- 1 file changed, 30 insertions(+), 128 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index ad5f0349bc..ae22fcaf50 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -482,7 +482,6 @@ gnc_dbi_session_begin(QofBackend* qbe, QofSession* session, LEAVE("Bad DBI Library"); } - be->connect(nullptr); try { be->connect(new GncDbiSqlConnection(DbType::DBI_SQLITE, @@ -618,8 +617,8 @@ adjust_sql_options (dbi_conn connection) } -template <> void -gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, +template void +gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, const gchar* book_id, gboolean ignore_lock, gboolean create, gboolean force) { @@ -638,9 +637,21 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, where username, password and port are optional) */ UriStrings uri(book_id); + if (T == DbType::DBI_PGSQL) + { + if (uri.m_portnum == 0) + uri.m_portnum = PGSQL_DEFAULT_PORT; + /* Postgres's SQL interface coerces identifiers to lower case, but the + * C interface is case-sensitive. This results in a mixed-case dbname + * being created (with a lower case name) but then dbi can't conect to + * it. To work around this, coerce the name to lowercase first. */ + auto lcname = g_utf8_strdown (uri.dbname(), -1); + uri.m_dbname = std::string{lcname}; + g_free(lcname); + } be->connect(nullptr); - auto conn = conn_setup(qbe, options, uri); + auto conn = conn_setup(qbe, options, uri); if (conn == nullptr) { LEAVE("Error"); @@ -651,9 +662,11 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, auto result = dbi_conn_connect (conn); if (result == 0) { - adjust_sql_options (conn); + if (T == DbType::DBI_MYSQL) + adjust_sql_options (conn); if(!conn_test_dbi_library(conn, qbe)) { + dbi_conn_close(conn); LEAVE("Error"); return; } @@ -661,6 +674,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, { qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS); PWARN ("Databse already exists, Might clobber it."); + dbi_conn_close(conn); LEAVE("Error"); return; } @@ -673,30 +687,37 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, { PERR ("Unable to connect to database '%s'\n", uri.dbname()); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); + dbi_conn_close(conn); LEAVE("Error"); return; } if (create) { - if (!create_database(DbType::DBI_MYSQL, qbe, conn, uri.dbname())) + if (!create_database(T, qbe, conn, uri.dbname())) { + dbi_conn_close(conn); LEAVE("Error"); return; } - conn = conn_setup(qbe, options, uri); + conn = conn_setup(qbe, options, uri); result = dbi_conn_connect (conn); if (result < 0) { PERR ("Unable to create database '%s'\n", uri.dbname()); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); + dbi_conn_close(conn); LEAVE("Error"); return; } - adjust_sql_options (conn); + if (T == DbType::DBI_MYSQL) + adjust_sql_options (conn); if (!conn_test_dbi_library(conn, qbe)) { + if (T == DbType::DBI_PGSQL) + dbi_conn_select_db (conn, "template1"); dbi_conn_queryf (conn, "DROP DATABASE %s", uri.dbname()); + dbi_conn_close(conn); return; } } @@ -710,8 +731,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, be->connect(nullptr); try { - be->connect(new GncDbiSqlConnection(DbType::DBI_MYSQL, - qbe, conn, ignore_lock)); + be->connect(new GncDbiSqlConnection(T, qbe, conn, ignore_lock)); } catch (std::runtime_error& err) { @@ -772,124 +792,6 @@ error_handler (dbi_conn conn, void* user_data) } } -template <>void -gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, - const gchar* book_id, gboolean ignore_lock, - gboolean create, gboolean force) -{ - GncDbiBackend* be = (GncDbiBackend*)qbe; - bool success = false; - PairVec options; - - g_return_if_fail (qbe != nullptr); - g_return_if_fail (session != nullptr); - g_return_if_fail (book_id != nullptr); - - ENTER (" "); - - /* Split the book-id - * Format is protocol://username:password@hostname:port/dbname - where username, password and port are optional) */ - UriStrings uri(book_id); - if (uri.m_portnum == 0) - uri.m_portnum = PGSQL_DEFAULT_PORT; - /* Postgres's SQL interface coerces identifiers to lower case, but the - * C interface is case-sensitive. This results in a mixed-case dbname - * being created (with a lower case name) but then dbi can't conect to - * it. To work around this, coerce the name to lowercase first. */ - auto lcname = g_utf8_strdown (uri.dbname(), -1); - uri.m_dbname = std::string{lcname}; - g_free(lcname); - be->connect(nullptr); - - auto conn = conn_setup(qbe, options, uri); - if (conn == nullptr) - { - LEAVE("Error"); - return; - } - - be->set_exists(true); //May be unset in the error handler. - auto result = dbi_conn_connect (conn); - if (result == 0) - { - if (!conn_test_dbi_library(conn, qbe)) - { - LEAVE("Error"); - return; - } - if (create && !force && save_may_clobber_data(conn)) - { - qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS); - PWARN ("Databse already exists, Might clobber it."); - LEAVE("Error"); - return; - } - - } - else - { - - if (be->exists()) - { - PERR ("Unable to connect to database '%s'\n", uri.dbname()); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - LEAVE("Error"); - return; - } - - if (create) - { - if (!create_database(DbType::DBI_PGSQL, qbe, conn, uri.dbname())) - { - LEAVE("Error"); - return; - } - conn = conn_setup(qbe, options, uri); - result = dbi_conn_connect (conn); - if (result < 0) - { - PERR ("Unable to create database '%s'\n", uri.dbname()); - qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); - LEAVE("Error"); - return; - } - if (!conn_test_dbi_library(conn, qbe)) - { - dbi_conn_select_db (conn, "template1"); - dbi_conn_queryf (conn, "DROP DATABASE %s", uri.dbname()); - LEAVE("Error"); - return; - } - } - else - { - qof_backend_set_error (qbe, ERR_BACKEND_NO_SUCH_DB); - qof_backend_set_message (qbe, "Database %s not found", uri.dbname()); - } - } - be->connect(nullptr); - try - { - be->connect(new GncDbiSqlConnection(DbType::DBI_PGSQL, - qbe, conn, ignore_lock)); - } - catch (std::runtime_error& err) - { - return; - } - - /* We should now have a proper session set up. - * Let's start logging */ - auto translog_path = gnc_build_translog_path (uri.basename().c_str()); - xaccLogSetBaseName (translog_path); - PINFO ("logpath=%s", translog_path ? translog_path : "(null)"); - g_free (translog_path); - - LEAVE (" "); -} - - /* ================================================================= */ static void From 451f3ffe4df5229d0fe597ec52a0b28dd3ecf382 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 29 Jul 2016 13:36:45 -0700 Subject: [PATCH 54/63] DBI: Convert all of the gchar to char, remove a few gratuitous g_funcs. Except where we're explicitly using other GLib functions. --- src/backend/dbi/gnc-backend-dbi.cpp | 24 ++++++++++++------------ src/backend/dbi/gnc-dbisqlconnection.cpp | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index ae22fcaf50..dbaa7677ee 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -117,7 +117,7 @@ static bool conn_test_dbi_library (dbi_conn conn, QofBackend* qbe); template void gnc_dbi_session_begin(QofBackend* qbe, QofSession* session, - const gchar* book_id, + const char* book_id, gboolean ignore_lock, gboolean create, gboolean force); template QofBackend* @@ -138,7 +138,7 @@ new_backend () break; } auto dbi_be = new GncDbiBackend(nullptr, nullptr, format); - g_assert (dbi_be != nullptr); + assert (dbi_be != nullptr); be = (QofBackend*)dbi_be; qof_backend_init (be); @@ -390,7 +390,7 @@ create_database(DbType type, QofBackend *qbe, dbi_conn conn, const char* db) template <> void error_handler (dbi_conn conn, void* user_data) { - const gchar* msg; + const char* msg; GncDbiBackend *be = static_cast(user_data); int errnum = dbi_conn_error (conn, &msg); PERR ("DBI error: %s\n", msg); @@ -400,7 +400,7 @@ error_handler (dbi_conn conn, void* user_data) template <> void gnc_dbi_session_begin(QofBackend* qbe, QofSession* session, - const gchar* book_id, gboolean ignore_lock, + const char* book_id, gboolean ignore_lock, gboolean create, gboolean force) { GncDbiBackend* be = (GncDbiBackend*)qbe; @@ -619,7 +619,7 @@ adjust_sql_options (dbi_conn connection) template void gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, - const gchar* book_id, gboolean ignore_lock, + const char* book_id, gboolean ignore_lock, gboolean create, gboolean force) { GncDbiBackend* be = (GncDbiBackend*)qbe; @@ -751,7 +751,7 @@ template<> void error_handler (dbi_conn conn, void* user_data) { GncDbiBackend* be = (GncDbiBackend*)user_data; - const gchar* msg; + const char* msg; (void)dbi_conn_error (conn, &msg); if (g_str_has_prefix (msg, "FATAL: database") && @@ -848,7 +848,7 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) // Set up table version information be->init_version_info (); - g_assert (be->m_book == nullptr); + assert (be->m_book == nullptr); // Call all object backends to create any required tables auto registry = gnc_sql_get_backend_registry(); @@ -1061,7 +1061,7 @@ QofDbiBackendProvider::type_check(const char *uri) void gnc_module_init_backend_dbi (void) { - const gchar* driver_dir; + const char* driver_dir; int num_drivers; gboolean have_sqlite3_driver = FALSE; gboolean have_mysql_driver = FALSE; @@ -1204,11 +1204,11 @@ gnc_module_finalize_backend_dbi (void) static GncDbiTestResult dbi_library_test (dbi_conn conn) { - gint64 testlonglong = -9223372036854775807LL, resultlonglong = 0; - guint64 testulonglong = 9223372036854775807LLU, resultulonglong = 0; - gdouble testdouble = 1.7976921348623157E+307, resultdouble = 0.0; + int64_t testlonglong = -9223372036854775807LL, resultlonglong = 0; + uint64_t testulonglong = 9223372036854775807LLU, resultulonglong = 0; + double testdouble = 1.7976921348623157E+307, resultdouble = 0.0; dbi_result result; - gchar doublestr[G_ASCII_DTOSTR_BUF_SIZE], *querystr; + char doublestr[G_ASCII_DTOSTR_BUF_SIZE], *querystr; GncDbiTestResult retval = GNC_DBI_PASS; memset (doublestr, 0, sizeof (doublestr)); diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index 3f68e1e3e2..aa9d3786a2 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -218,7 +218,7 @@ GncDbiSqlConnection::unlock_database () if (result) { /* Delete the entry if it's our hostname and PID */ - gchar hostname[ GNC_HOST_NAME_MAX + 1 ]; + char hostname[ GNC_HOST_NAME_MAX + 1 ]; dbi_result_free (result); result = nullptr; @@ -541,7 +541,7 @@ std::string GncDbiSqlConnection::quote_string (const std::string& unquoted_str) const noexcept { - gchar* quoted_str; + char* quoted_str; size_t size; size = dbi_conn_quote_string_copy (m_conn, unquoted_str.c_str(), From 02d173d2e781d371d6648a2a97e58a19efc5de4e Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 29 Jul 2016 14:23:36 -0700 Subject: [PATCH 55/63] Replace g_str functions in dbi_library_test with std::stringstream. --- src/backend/dbi/gnc-backend-dbi.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index dbaa7677ee..9d1dae0408 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -44,6 +44,7 @@ extern "C" #include #endif +#include #include #include #include @@ -71,6 +72,7 @@ extern "C" } #include #include +#include #include #include "gnc-backend-dbi.h" @@ -479,7 +481,9 @@ gnc_dbi_session_begin(QofBackend* qbe, QofSession* session, conn = nullptr; g_unlink (filepath.c_str()); } + dbi_conn_close(conn); LEAVE("Bad DBI Library"); + return; } try @@ -1208,9 +1212,7 @@ dbi_library_test (dbi_conn conn) uint64_t testulonglong = 9223372036854775807LLU, resultulonglong = 0; double testdouble = 1.7976921348623157E+307, resultdouble = 0.0; dbi_result result; - char doublestr[G_ASCII_DTOSTR_BUF_SIZE], *querystr; GncDbiTestResult retval = GNC_DBI_PASS; - memset (doublestr, 0, sizeof (doublestr)); result = dbi_conn_query (conn, "CREATE TEMPORARY TABLE numtest " "( test_int BIGINT, test_unsigned BIGINT," @@ -1221,12 +1223,12 @@ dbi_library_test (dbi_conn conn) return GNC_DBI_FAIL_SETUP; } dbi_result_free (result); - g_ascii_dtostr (doublestr, sizeof (doublestr), testdouble); - querystr = g_strdup_printf ("INSERT INTO numtest VALUES (%" G_GINT64_FORMAT - ", %" G_GUINT64_FORMAT ", %s)", - testlonglong, testulonglong, doublestr); - result = dbi_conn_query (conn, querystr); - g_free (querystr); + std::stringstream querystr; + querystr << "INSERT INTO numtest VALUES (" << testlonglong << + ", " << testulonglong << ", " << std::setprecision(12) << + testdouble << ")"; + auto query = querystr.str(); + result = dbi_conn_query (conn, query.c_str()); if (result == nullptr) { PWARN ("Test_DBI_Library: Failed to insert test row into table"); @@ -1254,16 +1256,14 @@ dbi_library_test (dbi_conn conn) gnc_pop_locale (LC_NUMERIC); if (testlonglong != resultlonglong) { - PWARN ("Test_DBI_Library: LongLong Failed %" G_GINT64_FORMAT " != % " - G_GINT64_FORMAT, + PWARN ("Test_DBI_Library: LongLong Failed %" PRId64 " != % " PRId64, testlonglong, resultlonglong); retval = GNC_DBI_FAIL_TEST; } if (testulonglong != resultulonglong) { - PWARN ("Test_DBI_Library: Unsigned longlong Failed %" G_GUINT64_FORMAT " != %" - G_GUINT64_FORMAT, - testulonglong, resultulonglong); + PWARN ("Test_DBI_Library: Unsigned longlong Failed %" PRIu64 " != %" + PRIu64, testulonglong, resultulonglong); retval = GNC_DBI_FAIL_TEST; } /* A bug in libdbi stores only 7 digits of precision */ From 7ff6e51a725cbeddb9d3e0f99d4ec42c0653d448 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 9 Aug 2016 09:30:46 -0700 Subject: [PATCH 56/63] Use GncDbiProvider::get_table_list instead of calling out to libdbi. GncDbiProvider can figure out the dbname for itself so change the function signature to replace dbname with a particular table to search for. Pass an empty string ("" works) to get the full list. --- src/backend/dbi/gnc-backend-dbi.cpp | 3 +- src/backend/dbi/gnc-dbiprovider.hpp | 2 +- src/backend/dbi/gnc-dbiproviderimpl.hpp | 36 ++++++------- src/backend/dbi/gnc-dbisqlconnection.cpp | 69 +++++++----------------- 4 files changed, 39 insertions(+), 71 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 9d1dae0408..17830c7db8 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -921,8 +921,7 @@ gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book) g_return_if_fail (book != nullptr); ENTER ("book=%p, primary=%p", book, be->m_book); - auto dbname = dbi_conn_get_option (conn->conn(), "dbname"); - auto table_list = conn->m_provider->get_table_list (conn->conn(), dbname); + auto table_list = conn->m_provider->get_table_list (conn->conn(), ""); if (!conn->table_operation (table_list, backup)) { qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); diff --git a/src/backend/dbi/gnc-dbiprovider.hpp b/src/backend/dbi/gnc-dbiprovider.hpp index e0a25616bb..2f168d8702 100644 --- a/src/backend/dbi/gnc-dbiprovider.hpp +++ b/src/backend/dbi/gnc-dbiprovider.hpp @@ -42,7 +42,7 @@ class GncDbiProvider { public: virtual ~GncDbiProvider() = default; - virtual StrVec get_table_list(dbi_conn conn, const std::string& dbname) = 0; + virtual StrVec get_table_list(dbi_conn conn, const std::string& table) = 0; virtual void append_col_def(std::string& ddl, const GncSqlColumnInfo& info) = 0; virtual StrVec get_index_list (dbi_conn conn) = 0; diff --git a/src/backend/dbi/gnc-dbiproviderimpl.hpp b/src/backend/dbi/gnc-dbiproviderimpl.hpp index a96461b91b..9158de5789 100644 --- a/src/backend/dbi/gnc-dbiproviderimpl.hpp +++ b/src/backend/dbi/gnc-dbiproviderimpl.hpp @@ -34,7 +34,7 @@ template class GncDbiProviderImpl : public GncDbiProvider { public: - StrVec get_table_list(dbi_conn conn, const std::string& dbname); + StrVec get_table_list(dbi_conn conn, const std::string& table); void append_col_def(std::string& ddl, const GncSqlColumnInfo& info); StrVec get_index_list (dbi_conn conn); void drop_index(dbi_conn conn, const std::string& index); @@ -212,10 +212,12 @@ GncDbiProviderImpl::append_col_def (std::string& ddl, } static StrVec -conn_get_table_list (dbi_conn conn, const std::string& dbname) +conn_get_table_list (dbi_conn conn, const std::string& dbname, + const std::string& table) { StrVec retval; - auto tables = dbi_conn_get_table_list (conn, dbname.c_str(), nullptr); + const char* tableptr = (table.empty() ? nullptr : table.c_str()); + auto tables = dbi_conn_get_table_list (conn, dbname.c_str(), tableptr); while (dbi_result_next_row (tables) != 0) { std::string table_name {dbi_result_get_string_idx (tables, 1)}; @@ -227,11 +229,12 @@ conn_get_table_list (dbi_conn conn, const std::string& dbname) template<> StrVec GncDbiProviderImpl::get_table_list (dbi_conn conn, - const std::string& dbname) + const std::string& table) { /* Return the list, but remove the tables that sqlite3 adds for * its own use. */ - auto list = conn_get_table_list (conn, dbname); + std::string dbname (dbi_conn_get_option (conn, "dbname")); + auto list = conn_get_table_list (conn, dbname, table); auto end = std::remove(list.begin(), list.end(), "sqlite_sequence"); list.erase(end, list.end()); return list; @@ -239,16 +242,18 @@ GncDbiProviderImpl::get_table_list (dbi_conn conn, template<> StrVec GncDbiProviderImpl::get_table_list (dbi_conn conn, - const std::string& dbname) + const std::string& table) { - return conn_get_table_list (conn, dbname); + std::string dbname (dbi_conn_get_option (conn, "dbname")); + return conn_get_table_list (conn, dbname, table); } template<> StrVec GncDbiProviderImpl::get_table_list (dbi_conn conn, - const std::string& dbname) + const std::string& table) { - auto list = conn_get_table_list (conn, dbname); + std::string dbname (dbi_conn_get_option (conn, "dbname")); + auto list = conn_get_table_list (conn, dbname, table); auto end = std::remove_if (list.begin(), list.end(), [](std::string& table_name){ return table_name == "sql_features" || @@ -289,19 +294,12 @@ GncDbiProviderImpl::get_index_list (dbi_conn conn) { StrVec retval; const char* errmsg; - auto dbname = dbi_conn_get_option (conn, "dbname"); - auto table_list = dbi_conn_get_table_list (conn, dbname, nullptr); - if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) + auto tables = get_table_list(conn, ""); + for (auto table_name : tables) { - PWARN ("Table Retrieval Error: %s\n", errmsg); - return retval; - } - while (dbi_result_next_row (table_list) != 0) - { - auto table_name = dbi_result_get_string_idx (table_list, 1); auto result = dbi_conn_queryf (conn, "SHOW INDEXES IN %s WHERE Key_name != 'PRIMARY'", - table_name); + table_name.c_str()); if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) { PWARN ("Index Table Retrieval Error: %s on table %s\n", diff --git a/src/backend/dbi/gnc-dbisqlconnection.cpp b/src/backend/dbi/gnc-dbisqlconnection.cpp index aa9d3786a2..c785ac828f 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.cpp +++ b/src/backend/dbi/gnc-dbisqlconnection.cpp @@ -35,7 +35,7 @@ static QofLogModule log_module = G_LOG_DOMAIN; #include "gnc-dbiproviderimpl.hpp" static const unsigned int DBI_MAX_CONN_ATTEMPTS = 5; -constexpr const char *lock_table_name = "gnclock"; +const std::string lock_table = "gnclock"; /* --------------------------------------------------------- */ class GncDbiSqlStatement : public GncSqlStatement @@ -91,22 +91,14 @@ GncDbiSqlConnection::GncDbiSqlConnection (DbType type, QofBackend* qbe, bool GncDbiSqlConnection::lock_database (bool ignore_lock) { - - auto dbname = dbi_conn_get_option (m_conn, "dbname"); - /* Create the table if it doesn't exist */ - auto result = dbi_conn_get_table_list (m_conn, dbname, lock_table_name); - int numrows = 0; - const char* errstr; - if (result) { - numrows = dbi_result_get_numrows (result); - dbi_result_free (result); - result = nullptr; - } - if (numrows == 0) + const char *errstr; + auto tables = m_provider->get_table_list(m_conn, lock_table); + if (tables.empty()) { - result = dbi_conn_queryf (m_conn, - "CREATE TABLE %s ( Hostname varchar(%d), PID int )", lock_table_name, - GNC_HOST_NAME_MAX); + auto result = dbi_conn_queryf (m_conn, + "CREATE TABLE %s ( Hostname varchar(%d), PID int )", + lock_table.c_str(), + GNC_HOST_NAME_MAX); if (result) { dbi_result_free (result); @@ -121,7 +113,7 @@ GncDbiSqlConnection::lock_database (bool ignore_lock) } /* Protect everything with a single transaction to prevent races */ - result = dbi_conn_query (m_conn, "BEGIN"); + auto result = dbi_conn_query (m_conn, "BEGIN"); if (dbi_conn_error (m_conn, &errstr)) { /* Couldn't get a transaction (probably couldn't get a lock), so fail */ @@ -135,7 +127,7 @@ GncDbiSqlConnection::lock_database (bool ignore_lock) result = nullptr; /* Check for an existing entry; delete it if ignore_lock is true, otherwise fail */ char hostname[ GNC_HOST_NAME_MAX + 1 ]; - result = dbi_conn_queryf (m_conn, "SELECT * FROM %s", lock_table_name); + result = dbi_conn_queryf (m_conn, "SELECT * FROM %s", lock_table.c_str()); if (result && dbi_result_get_numrows (result)) { dbi_result_free (result); @@ -147,7 +139,7 @@ GncDbiSqlConnection::lock_database (bool ignore_lock) dbi_conn_query (m_conn, "ROLLBACK"); return false; } - result = dbi_conn_queryf (m_conn, "DELETE FROM %s", lock_table_name); + result = dbi_conn_queryf (m_conn, "DELETE FROM %s", lock_table.c_str()); if (!result) { qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); @@ -165,7 +157,7 @@ GncDbiSqlConnection::lock_database (bool ignore_lock) gethostname (hostname, GNC_HOST_NAME_MAX); result = dbi_conn_queryf (m_conn, "INSERT INTO %s VALUES ('%s', '%d')", - lock_table_name, hostname, (int)GETPID ()); + lock_table.c_str(), hostname, (int)GETPID ()); if (!result) { qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); @@ -198,23 +190,13 @@ GncDbiSqlConnection::unlock_database () if (m_conn == nullptr) return; g_return_if_fail (dbi_conn_error (m_conn, nullptr) == 0); - auto dbname = dbi_conn_get_option (m_conn, "dbname"); - /* Check if the lock table exists */ - g_return_if_fail (dbname != nullptr); - auto result = dbi_conn_get_table_list (m_conn, dbname, lock_table_name); - if (! (result && dbi_result_get_numrows (result))) + auto tables = m_provider->get_table_list (m_conn, lock_table); + if (tables.empty()) { - if (result) - { - dbi_result_free (result); - result = nullptr; - } PWARN ("No lock table in database, so not unlocking it."); return; } - dbi_result_free (result); - - result = dbi_conn_query (m_conn, "BEGIN"); + auto result = dbi_conn_query (m_conn, "BEGIN"); if (result) { /* Delete the entry if it's our hostname and PID */ @@ -225,7 +207,7 @@ GncDbiSqlConnection::unlock_database () memset (hostname, 0, sizeof (hostname)); gethostname (hostname, GNC_HOST_NAME_MAX); result = dbi_conn_queryf (m_conn, - "SELECT * FROM %s WHERE Hostname = '%s' AND PID = '%d'", lock_table_name, hostname, + "SELECT * FROM %s WHERE Hostname = '%s' AND PID = '%d'", lock_table.c_str(), hostname, (int)GETPID ()); if (result && dbi_result_get_numrows (result)) { @@ -234,7 +216,8 @@ GncDbiSqlConnection::unlock_database () dbi_result_free (result); result = nullptr; } - result = dbi_conn_queryf (m_conn, "DELETE FROM %s", lock_table_name); + result = dbi_conn_queryf (m_conn, "DELETE FROM %s", + lock_table.c_str()); if (!result) { PERR ("Failed to delete the lock entry"); @@ -349,17 +332,7 @@ bool GncDbiSqlConnection::does_table_exist (const std::string& table_name) const noexcept { - auto dbname = dbi_conn_get_option (m_conn, "dbname"); - auto tables = dbi_conn_get_table_list (m_conn, dbname, table_name.c_str()); - auto nTables = dbi_result_get_numrows (tables); - auto status = dbi_result_free (tables); - if (status < 0) - { - PERR ("Error in dbi_result_free() result\n"); - qof_backend_set_error (m_qbe, ERR_BACKEND_SERVER_ERR); - } - - return nTables == 1; + return ! m_provider->get_table_list(m_conn, table_name).empty(); } bool @@ -660,8 +633,6 @@ bool GncDbiSqlConnection::table_operation(const StrVec& table_names, TableOpType op) noexcept { - const char* dbname = dbi_conn_get_option (m_conn, "dbname"); - std::string lock_table{lock_table_name}; g_return_val_if_fail (!table_names.empty(), FALSE); bool retval{true}; for (auto table : table_names) @@ -679,7 +650,7 @@ GncDbiSqlConnection::table_operation(const StrVec& table_names, { case rollback: { - auto all_tables = m_provider->get_table_list(m_conn, dbname); + auto all_tables = m_provider->get_table_list(m_conn, ""); if (std::find(all_tables.begin(), all_tables.end(), table) != all_tables.end()) { From 0baff455a2b60d049f9dd2cf6bbf5e9a510a49c2 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 9 Aug 2016 10:05:33 -0700 Subject: [PATCH 57/63] Bug 769115 - db name isn't escaped well More like at all, but it's supposed to be quoted rather than escaped. dbi_conn_quote_string() doesn't work well for database names, so we do it directly. libdbi is also inconsistent about needing quotes: They're required by mysql in SQL commands, and libdbi requires them for internal commands that it turns into SQL (e.g. db_conn_get_table_list) but not others (e.g dbi_conn_set_option). --- src/backend/dbi/gnc-backend-dbi.cpp | 31 ++++++++++++++++++------- src/backend/dbi/gnc-dbiproviderimpl.hpp | 2 ++ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 17830c7db8..23a0fa9962 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -112,7 +112,7 @@ constexpr const char* MYSQL_TIMESPEC_STR_FORMAT = "%04d%02d%02d%02d%02d%02d"; constexpr const char* PGSQL_TIMESPEC_STR_FORMAT = "%04d%02d%02d %02d%02d%02d"; static void adjust_sql_options (dbi_conn connection); -static bool save_may_clobber_data (dbi_conn conn); +static bool save_may_clobber_data (dbi_conn conn, const std::string& dbname); static void init_sql_backend (GncDbiBackend* dbi_be); static bool conn_test_dbi_library (dbi_conn conn, QofBackend* qbe); @@ -175,6 +175,7 @@ struct UriStrings ~UriStrings() = default; std::string basename() const noexcept; const char* dbname() const noexcept; + std::string quote_dbname(DbType t) const noexcept; std::string m_protocol; std::string m_host; std::string m_dbname; @@ -201,6 +202,7 @@ UriStrings::UriStrings(const std::string& uri) g_free(username); g_free(password); g_free(dbname); + } std::string @@ -215,6 +217,17 @@ UriStrings::dbname() const noexcept return m_dbname.c_str(); } +std::string +UriStrings::quote_dbname(DbType t) const noexcept +{ + if (m_dbname.empty()) + return ""; + const char quote = (t == DbType::DBI_MYSQL ? '`' : '"'); + std::string retval(1, quote); + retval += m_dbname + quote; + return retval; +} + static void create_tables(const OBEEntry& entry, GncDbiBackend* be) { @@ -312,7 +325,6 @@ conn_setup (QofBackend* qbe, PairVec& options, } dbi_conn_error_handler (conn, error_handler, qbe); - if (!uri.m_dbname.empty() && !set_standard_connection_options(qbe, conn, uri)) { @@ -674,7 +686,8 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, LEAVE("Error"); return; } - if (create && !force && save_may_clobber_data (conn)) + if (create && !force && save_may_clobber_data (conn, + uri.quote_dbname(T))) { qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS); PWARN ("Databse already exists, Might clobber it."); @@ -698,7 +711,7 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, if (create) { - if (!create_database(T, qbe, conn, uri.dbname())) + if (!create_database(T, qbe, conn, uri.quote_dbname(T).c_str())) { dbi_conn_close(conn); LEAVE("Error"); @@ -720,7 +733,8 @@ gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, { if (T == DbType::DBI_PGSQL) dbi_conn_select_db (conn, "template1"); - dbi_conn_queryf (conn, "DROP DATABASE %s", uri.dbname()); + dbi_conn_queryf (conn, "DROP DATABASE %s", + uri.quote_dbname(T).c_str()); dbi_conn_close(conn); return; } @@ -883,14 +897,13 @@ gnc_dbi_load (QofBackend* qbe, QofBook* book, QofBackendLoadType loadType) } /* ================================================================= */ - +/* This is used too early to call GncDbiProvider::get_table_list(). */ static bool -save_may_clobber_data (dbi_conn conn) +save_may_clobber_data (dbi_conn conn, const std::string& dbname) { /* Data may be clobbered iff the number of tables != 0 */ - auto dbname = dbi_conn_get_option (conn, "dbname"); - auto result = dbi_conn_get_table_list (conn, dbname, nullptr); + auto result = dbi_conn_get_table_list (conn, dbname.c_str(), nullptr); bool retval = false; if (result) { diff --git a/src/backend/dbi/gnc-dbiproviderimpl.hpp b/src/backend/dbi/gnc-dbiproviderimpl.hpp index 9158de5789..e79003cc17 100644 --- a/src/backend/dbi/gnc-dbiproviderimpl.hpp +++ b/src/backend/dbi/gnc-dbiproviderimpl.hpp @@ -245,6 +245,8 @@ GncDbiProviderImpl::get_table_list (dbi_conn conn, const std::string& table) { std::string dbname (dbi_conn_get_option (conn, "dbname")); + dbname.insert((std::string::size_type)0, 1, '`'); + dbname += '`'; return conn_get_table_list (conn, dbname, table); } From 10ff71b29a430ccfc166129ceb20372534245cee Mon Sep 17 00:00:00 2001 From: John Ralls Date: Tue, 25 Oct 2016 14:15:43 -0700 Subject: [PATCH 58/63] Fix passing std::string to PWARN. --- src/backend/dbi/gnc-dbiproviderimpl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/dbi/gnc-dbiproviderimpl.hpp b/src/backend/dbi/gnc-dbiproviderimpl.hpp index e79003cc17..4c3f449f7f 100644 --- a/src/backend/dbi/gnc-dbiproviderimpl.hpp +++ b/src/backend/dbi/gnc-dbiproviderimpl.hpp @@ -305,7 +305,7 @@ GncDbiProviderImpl::get_index_list (dbi_conn conn) if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE) { PWARN ("Index Table Retrieval Error: %s on table %s\n", - errmsg, table_name); + errmsg, table_name.c_str()); continue; } From 0bc35eb3e28288858bb208c4067021f8343dbc6d Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 28 Oct 2016 11:38:29 -0700 Subject: [PATCH 59/63] Fix two C++11 initializer list errors. --- src/backend/sql/gnc-address-sql.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/sql/gnc-address-sql.cpp b/src/backend/sql/gnc-address-sql.cpp index cd6dd70220..0c280c0448 100644 --- a/src/backend/sql/gnc-address-sql.cpp +++ b/src/backend/sql/gnc-address-sql.cpp @@ -129,7 +129,7 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, const gpointer pObject, PairVec& vec) const noexcept { - auto addr{get_row_value_from_object(obj_name, pObject)}; + auto addr(get_row_value_from_object(obj_name, pObject)); if (addr == nullptr) return; for (auto const& subtable_row : col_table) @@ -139,7 +139,7 @@ GncSqlColumnTableEntryImpl::add_to_query(const GncSqlBackend* be, if (s == nullptr) continue; auto buf = std::string{m_col_name} + "_" + subtable_row->m_col_name; - vec.emplace_back(make_pair(buf, std::string{s})); + vec.emplace_back(make_pair(buf, std::string(s))); } } /* ========================== END OF FILE ===================== */ From afb57d0e7b86a19b58baddcddd00d727fc0041b7 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 28 Oct 2016 12:31:49 -0700 Subject: [PATCH 60/63] Initialize a variable to appease travis-ci. --- src/backend/dbi/gnc-backend-dbi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/dbi/gnc-backend-dbi.cpp b/src/backend/dbi/gnc-backend-dbi.cpp index 23a0fa9962..c8fffc9711 100644 --- a/src/backend/dbi/gnc-backend-dbi.cpp +++ b/src/backend/dbi/gnc-backend-dbi.cpp @@ -308,7 +308,7 @@ conn_setup (QofBackend* qbe, PairVec& options, const char* dbstr = (Type == DbType::DBI_SQLITE ? "sqlite3" : Type == DbType::DBI_MYSQL ? "mysql" : "pgsql"); #if HAVE_LIBDBI_R - dbi_conn conn; + dbi_conn conn = nullptr; if (dbi_instance) conn = dbi_conn_new_r (dbstr, dbi_instance); else From 70c803d6aab75531c992014dee958c67745d741f Mon Sep 17 00:00:00 2001 From: John Ralls Date: Fri, 28 Oct 2016 12:56:13 -0700 Subject: [PATCH 61/63] Fix unsigned-signed comparison mismatch. --- src/backend/dbi/gnc-backend-dbi.hpp | 2 +- src/backend/dbi/gnc-dbisqlconnection.hpp | 5 +++-- src/backend/sql/gnc-backend-sql.h | 2 +- src/backend/sql/test/utest-gnc-backend-sql.cpp | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/backend/dbi/gnc-backend-dbi.hpp b/src/backend/dbi/gnc-backend-dbi.hpp index cf1b1abae2..66c87320aa 100644 --- a/src/backend/dbi/gnc-backend-dbi.hpp +++ b/src/backend/dbi/gnc-backend-dbi.hpp @@ -89,7 +89,7 @@ public: GncSqlBackend(conn, book, format), m_exists{false} {} bool connected() const noexcept { return m_conn != nullptr; } /** FIXME: Just a pass-through to m_conn: */ - void set_error(int error, int repeat, bool retry) noexcept + void set_error(int error, unsigned int repeat, bool retry) noexcept { m_conn->set_error(error, repeat, retry); } diff --git a/src/backend/dbi/gnc-dbisqlconnection.hpp b/src/backend/dbi/gnc-dbisqlconnection.hpp index b97520fbc5..fd332948b2 100644 --- a/src/backend/dbi/gnc-dbisqlconnection.hpp +++ b/src/backend/dbi/gnc-dbisqlconnection.hpp @@ -58,7 +58,8 @@ public: return dbi_conn_error(m_conn, nullptr); } QofBackend* qbe () const noexcept { return m_qbe; } dbi_conn conn() const noexcept { return m_conn; } - inline void set_error(int error, int repeat, bool retry) noexcept override + inline void set_error(int error, unsigned int repeat, + bool retry) noexcept override { m_last_error = error; m_error_repeat = repeat; @@ -96,7 +97,7 @@ private: * the original call is allowed. error_repeat tracks the number of attempts * and can be used to prevent infinite loops. */ - int m_error_repeat; + unsigned int m_error_repeat; /** Signals the calling function that it should retry (the error handler * detected transient error and managed to resolve it, but it can't run the * original query) diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index cdf72fc9a8..c2c891bd18 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -313,7 +313,7 @@ public: * If not 0 will normally be meaningless outside of implementation code. */ virtual int dberror() const noexcept = 0; - virtual void set_error(int error, int repeat, bool retry) noexcept = 0; + virtual void set_error(int error, unsigned int repeat, bool retry) noexcept = 0; virtual bool verify() noexcept = 0; virtual bool retry_connection(const char* msg) noexcept = 0; diff --git a/src/backend/sql/test/utest-gnc-backend-sql.cpp b/src/backend/sql/test/utest-gnc-backend-sql.cpp index f2922c1812..f968a91e2f 100644 --- a/src/backend/sql/test/utest-gnc-backend-sql.cpp +++ b/src/backend/sql/test/utest-gnc-backend-sql.cpp @@ -105,7 +105,7 @@ public: virtual std::string quote_string (const std::string& str) const noexcept override { return std::string{str}; } int dberror() const noexcept override { return 0; } - void set_error(int error, int repeat, bool retry) noexcept override { return; } + void set_error(int error, unsigned int repeat, bool retry) noexcept override { return; } bool verify() noexcept override { return true; } bool retry_connection(const char* msg) noexcept override { return true; } private: From 00880cd8f505e80479fc97bc673db0e6050ed109 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 29 Oct 2016 11:42:55 -0700 Subject: [PATCH 62/63] Fix another initializer list error. --- src/backend/sql/gnc-backend-sql.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index c2c891bd18..9b3ddbe144 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -418,7 +418,7 @@ public: GncSqlObjectBackend (int version, const std::string& type, const std::string& table, const EntryVec& vec) : m_table_name{table}, m_version{version}, m_type_name{type}, - m_col_table{vec} {} + m_col_table(vec) {} /** * Load all objects of m_type in the database into memory. * @param be The GncSqlBackend containing the database connection. From b8024fa9eae3514cf1e7ba47463b2bb475dfbdc0 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Sat, 29 Oct 2016 12:40:57 -0700 Subject: [PATCH 63/63] Fix review comment errors. --- src/backend/dbi/gnc-dbisqlresult.cpp | 2 +- src/backend/sql/gnc-backend-sql.cpp | 8 ++++---- src/backend/sql/gnc-backend-sql.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/backend/dbi/gnc-dbisqlresult.cpp b/src/backend/dbi/gnc-dbisqlresult.cpp index 07e7fa3535..56e32bd9f9 100644 --- a/src/backend/dbi/gnc-dbisqlresult.cpp +++ b/src/backend/dbi/gnc-dbisqlresult.cpp @@ -156,7 +156,7 @@ GncDbiSqlResult::IteratorImpl::get_time64_at_col (const char* col) const auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col); if (type != DBI_TYPE_DATETIME) - throw (std::invalid_argument{"Requested double from non-double column."}); + throw (std::invalid_argument{"Requested time64 from non-time64 column."}); gnc_push_locale (LC_NUMERIC, "C"); #if HAVE_LIBDBI_TO_LONGLONG /* A less evil hack than the one equrie by libdbi-0.8, but diff --git a/src/backend/sql/gnc-backend-sql.cpp b/src/backend/sql/gnc-backend-sql.cpp index 1ba18bfb28..61cfb46161 100644 --- a/src/backend/sql/gnc-backend-sql.cpp +++ b/src/backend/sql/gnc-backend-sql.cpp @@ -158,10 +158,10 @@ gnc_sql_get_object_backend(const std::string& type) [type](const OBEEntry& entry){ return type == std::get<0>(entry); }); - auto obe = std::get<1>(*entry); - if (entry != backend_registry.end()) - return obe; - return nullptr; + if (entry == backend_registry.end()) + return nullptr; + + return std::get<1>(*entry); } void diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 9b3ddbe144..a81e114aa3 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -355,7 +355,7 @@ protected: * Row of SQL Query results. * * This is a "pointer" class of a pimpl pattern, the implementation being - * GncSqlResul::IteratorImpl. It's designed to present a std::forward_iterator + * GncSqlResult::IteratorImpl. It's designed to present a std::forward_iterator * like interface for use with range-for while allowing for wrapping a C API. * * Important Implementation Note: Operator++() as written requires that the