Interim merge of c++-backend to expose C++ interface.

This commit is contained in:
John Ralls 2016-10-29 13:16:29 -07:00
commit 472b585feb
77 changed files with 6383 additions and 9195 deletions

View File

@ -6,9 +6,15 @@ ADD_SUBDIRECTORY(test)
SET (backend_dbi_SOURCES
gnc-backend-dbi.cpp
gnc-dbisqlresult.cpp
gnc-dbisqlconnection.cpp
)
SET (backend_dbi_noinst_HEADERS
gnc-backend-dbi.h gnc-backend-dbi-priv.h
gnc-backend-dbi.h
gnc-backend-dbi.hpp
gnc-dbisqlresult.hpp
gnc-dbisqlconnection.hpp
gnc-dbiprovider.hpp
)
# Add dependency on config.h

View File

@ -21,11 +21,17 @@ AM_CPPFLAGS = \
${WARN_CFLAGS}
libgncmod_backend_dbi_la_SOURCES = \
gnc-backend-dbi.cpp
gnc-backend-dbi.cpp \
gnc-dbisqlconnection.cpp \
gnc-dbisqlresult.cpp
noinst_HEADERS = \
gnc-backend-dbi.h \
gnc-backend-dbi-priv.h
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 = \

View File

@ -1,121 +0,0 @@
/********************************************************************
* gnc-backend-dbi-priv.h: 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 *
* 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 *
\********************************************************************/
/* 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
extern "C"
{
#endif
#include <dbi/dbi.h>
#ifdef __cplusplus
}
#endif
#include "gnc-backend-sql.h"
/**
* Options to conn_table_operation
* @var drop Drop (remove without recourse) the table from the database
* @var empty Delete all of the records from the table
* @var backup Rename the table "name" to "name_back"
* @var rollback drop the name table if it exists and rename name_back to name
* @var drop_backup Drop the backup table
*/
typedef enum
{
drop = 0,
empty,
backup,
rollback,
drop_backup
} TableOpType;
/**
* Return values from conn_test_dbi_library
* @var GNC_DBI_PASS Did not find the large numbers bug
* @var GNC_DBI_FAIL_SETUP Could not completed the test
* @var GNC_DBI_FAIL_TEST Found the large numbers bug
*/
typedef enum
{
GNC_DBI_PASS = 0,
GNC_DBI_FAIL_SETUP,
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 struct
{
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;
struct GncDbiBackend_struct
{
GncSqlBackend sql_be;
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
};
typedef struct GncDbiBackend_struct GncDbiBackend;
typedef struct
{
GncSqlConnection base;
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)
} GncDbiSqlConnection;
/* external access required for tests */
std::string adjust_sql_options_string(const std::string&);
#endif //GNC_BACKEND_DBI_PRIV_H

File diff suppressed because it is too large Load Diff

View File

@ -28,10 +28,8 @@
#ifndef GNC_BACKEND_DBI_H_
#define GNC_BACKEND_DBI_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <gmodule.h>
/** 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_ */

View File

@ -0,0 +1,117 @@
/********************************************************************
* 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 *
* 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 *
\********************************************************************/
/* Private structures and variables for gnc-backend-dbi.c and its unit tests */
#ifndef GNC_BACKEND_DBI_HPP
#define GNC_BACKEND_DBI_HPP
extern "C"
{
#include <dbi/dbi.h>
#ifdef G_OS_WIN32
#include <winsock2.h>
#define GETPID() GetCurrentProcessId()
#else
#include <limits.h>
#include <unistd.h>
#define GETPID() getpid()
#endif
}
#include "gnc-backend-sql.h"
#define GNC_HOST_NAME_MAX 255
/**
* Options to conn_table_operation
* @var drop Drop (remove without recourse) the table from the database
* @var empty Delete all of the records from the table
* @var backup Rename the table "name" to "name_back"
* @var rollback drop the name table if it exists and rename name_back to name
* @var drop_backup Drop the backup table
*/
typedef enum
{
drop = 0,
empty,
backup,
rollback,
drop_backup
} TableOpType;
/**
* Return values from conn_test_dbi_library
* @var GNC_DBI_PASS Did not find the large numbers bug
* @var GNC_DBI_FAIL_SETUP Could not completed the test
* @var GNC_DBI_FAIL_TEST Found the large numbers bug
*/
typedef enum
{
GNC_DBI_PASS = 0,
GNC_DBI_FAIL_SETUP,
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.
*/
class GncDbiBackend : public GncSqlBackend
{
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, unsigned 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);
}
/*-----*/
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?
};
void gnc_dbi_safe_sync_all (QofBackend* qbe, QofBook* book);
/* external access required for tests */
std::string adjust_sql_options_string(const std::string&);
#endif //GNC_BACKEND_DBI_HPP

View File

@ -0,0 +1,54 @@
/********************************************************************
* gnc-dbiprovider.cpp: Encapsulate differences among Dbi backends. *
* *
* Copyright 2016 John Ralls <jralls@ceridwen.us> *
* *
* 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 <dbi/dbi.h>
}
#include <string>
#include <vector>
/**
* Provides the primary abstraction for different DBI backends.
*/
class GncSqlConnection;
struct GncSqlColumnInfo;
using ColVec=std::vector<GncSqlColumnInfo>;
class GncDbiProvider
{
public:
virtual ~GncDbiProvider() = default;
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;
virtual void drop_index(dbi_conn conn, const std::string& index) = 0;
};
using GncDbiProviderPtr = std::unique_ptr<GncDbiProvider>;
#endif //__GNC_DBIPROVIDER_HPP__

View File

@ -0,0 +1,371 @@
/************************************************************************
* gnc-dbiproviderimpl.hpp: Encapsulate differences among Dbi backends. *
* *
* Copyright 2016 John Ralls <jralls@ceridwen.us> *
* *
* 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 <guid.hpp>
extern "C"
{
#include <config.h>
}
#include "gnc-backend-dbi.hpp"
#include "gnc-dbiprovider.hpp"
template <DbType T>
class GncDbiProviderImpl : public GncDbiProvider
{
public:
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);
};
template <DbType T> GncDbiProviderPtr
make_dbi_provider()
{
return GncDbiProviderPtr(new GncDbiProviderImpl<T>);
}
template<> void
GncDbiProviderImpl<DbType::DBI_SQLITE>::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<> void
GncDbiProviderImpl<DbType::DBI_MYSQL>::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<DbType::DBI_PGSQL>::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,
const std::string& table)
{
StrVec retval;
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)};
retval.push_back(table_name);
}
dbi_result_free (tables);
return retval;
}
template<> StrVec
GncDbiProviderImpl<DbType::DBI_SQLITE>::get_table_list (dbi_conn conn,
const std::string& table)
{
/* Return the list, but remove the tables that sqlite3 adds for
* its own use. */
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;
}
template<> StrVec
GncDbiProviderImpl<DbType::DBI_MYSQL>::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);
}
template<> StrVec
GncDbiProviderImpl<DbType::DBI_PGSQL>::get_table_list (dbi_conn conn,
const std::string& table)
{
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" ||
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;
}
template<> StrVec
GncDbiProviderImpl<DbType::DBI_SQLITE>::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<DbType::DBI_MYSQL>::get_index_list (dbi_conn conn)
{
StrVec retval;
const char* errmsg;
auto tables = get_table_list(conn, "");
for (auto table_name : tables)
{
auto result = dbi_conn_queryf (conn,
"SHOW INDEXES IN %s WHERE Key_name != 'PRIMARY'",
table_name.c_str());
if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
{
PWARN ("Index Table Retrieval Error: %s on table %s\n",
errmsg, table_name.c_str());
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<DbType::DBI_PGSQL>::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 <DbType P> void
GncDbiProviderImpl<P>::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<DbType::DBI_MYSQL>::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 (<index> <table>): %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__

View File

@ -0,0 +1,709 @@
/********************************************************************
* gnc-dbisqlconnection.cpp: Encapsulate libdbi dbi_conn *
* *
* Copyright 2016 John Ralls <jralls@ceridwen.us> *
* *
* 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 <guid.hpp>
extern "C"
{
#include <config.h>
#include <platform.h>
#include <gnc-locale-utils.h>
}
#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;
const std::string lock_table = "gnclock";
/* --------------------------------------------------------- */
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());
}
}
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<DbType::DBI_SQLITE>() :
type == DbType::DBI_MYSQL ?
make_dbi_provider<DbType::DBI_MYSQL>() :
make_dbi_provider<DbType::DBI_PGSQL>())},
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)
{
const char *errstr;
auto tables = m_provider->get_table_list(m_conn, lock_table);
if (tables.empty())
{
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);
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 */
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 */
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.c_str());
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.c_str());
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.c_str(), 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 ()
{
GncDbiBackend* qe = reinterpret_cast<decltype(qe)>(m_qbe);
if (m_conn == nullptr) return;
g_return_if_fail (dbi_conn_error (m_conn, nullptr) == 0);
auto tables = m_provider->get_table_list (m_conn, lock_table);
if (tables.empty())
{
PWARN ("No lock table in database, so not unlocking it.");
return;
}
auto result = dbi_conn_query (m_conn, "BEGIN");
if (result)
{
/* Delete the entry if it's our hostname and PID */
char 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'", lock_table.c_str(), 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",
lock_table.c_str());
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;
}
}
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<GncSqlStatement>{new GncDbiSqlStatement (this, sql)};
}
bool
GncDbiSqlConnection::does_table_exist (const std::string& table_name)
const noexcept
{
return ! m_provider->get_table_list(m_conn, table_name).empty();
}
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
{
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;
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(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
{
char* quoted_str;
size_t size;
size = dbi_conn_quote_string_copy (m_conn, unquoted_str.c_str(),
&quoted_str);
if (quoted_str == nullptr)
return std::string{""};
std::string retval{quoted_str};
free(quoted_str);
return retval;
}
/** 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;
}
/**
* 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 table_namess: StrVec of tables to operate on.
* @param op: The operation to perform.
* @return Success (TRUE) or failure.
*/
bool
GncDbiSqlConnection::table_operation(const StrVec& table_names,
TableOpType op) noexcept
{
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, "");
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;
}

View File

@ -0,0 +1,111 @@
/********************************************************************
* gnc-dbisqlconnection.hpp: Encapsulate libdbi dbi_conn *
* *
* Copyright 2016 John Ralls <jralls@ceridwen.us> *
* *
* 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_
#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 (DbType type, QofBackend* qbe, dbi_conn conn,
bool ignore_lock);
~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; }
inline void set_error(int error, unsigned 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);
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;
std::unique_ptr<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.
*/
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)
*/
gboolean m_retry;
bool lock_database(bool ignore_lock);
void unlock_database();
};
#endif //_GNC_DBISQLCONNECTION_HPP_

View File

@ -0,0 +1,187 @@
/********************************************************************
* gnc-dbisqlresult.cpp: Encapsulate libdbi dbi_result *
* *
* Copyright 2016 John Ralls <jralls@ceridwen.us> *
* *
* 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 <guid.hpp>
extern "C"
{
#include <config.h>
#include <gnc-locale-utils.h>
#include <dbi/dbi.h>
/* For direct access to dbi data structs, sadly needed for datetime */
#include <dbi/dbi-dev.h>
}
#include <gnc-datetime.hpp>
#include <gnc-backend-sql.h>
#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 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
* 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;
}
/* --------------------------------------------------------- */

View File

@ -0,0 +1,77 @@
/********************************************************************
* gnc-dbisqlresult.hpp: Iterable wrapper for dbi_result. *
* *
* Copyright 2016 John Ralls <jralls@ceridwen.us *
* *
* 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 *
\********************************************************************/
/* Private structures and variables for gnc-backend-dbi.c and its unit tests */
#ifndef __GNC_DBISQLBACKEND_HPP__
#define __GNC_DBISQLBACKEND_HPP__
#include "gnc-backend-dbi.h"
class GncDbiSqlConnection;
/**
* 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() 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:
const GncDbiSqlConnection* m_conn;
dbi_result m_dbi_result;
IteratorImpl m_iter;
GncSqlRow m_row;
GncSqlRow m_sentinel;
};
#endif //__GNC_DBISQLRESULT_HPP__

View File

@ -19,6 +19,8 @@ SET(test_dbi_backend_SOURCES
test-dbi-business-stuff.cpp
test-dbi-stuff.cpp
../gnc-backend-dbi.cpp
../gnc-dbisqlconnection.cpp
../gnc-dbisqlresult.cpp
)
# This test does not work on Win32

View File

@ -61,7 +61,9 @@ test_backend_dbi_SOURCES = \
test-backend-dbi-basic.cpp \
test-dbi-stuff.cpp \
test-dbi-business-stuff.cpp \
../gnc-backend-dbi.cpp
../gnc-dbisqlconnection.cpp \
../gnc-backend-dbi.cpp \
../gnc-dbisqlresult.cpp
test_backend_dbi_CPPFLAGS = \
-DDBI_TEST_XML_FILENAME=\"${srcdir}/test-dbi.xml\" \

View File

@ -35,9 +35,7 @@ extern "C"
#include <glib/gstdio.h>
#include <qof.h>
#include <unittest-support.h>
#include <test-stuff.h>
/* For cleaning up the database */
/* For cleaning up the database */
#include <dbi/dbi.h>
#include <gnc-uri-utils.h>
/* For setup_business */
@ -53,9 +51,14 @@ extern "C"
#include <gnc-prefs.h>
}
/* For test_conn_index_functions */
#include "../gnc-backend-dbi.hpp"
extern "C"
{
#include <unittest-support.h>
#include <test-stuff.h>
}
#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
@ -232,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)
{
@ -258,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);
@ -310,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
@ -348,29 +345,24 @@ 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);
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<const char*> (iter->data));
g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn, &errmsg));
conn->provider()->drop_index (be->conn, index);
g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn(), &errmsg));
}
g_slist_free (index_list);
}
#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. */
@ -486,7 +478,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,
@ -513,10 +505,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;
@ -532,11 +523,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<GncSqlBackend*>(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);
@ -545,13 +535,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<GncSqlBackend*>(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);
@ -562,11 +550,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<GncSqlBackend*>(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);
@ -661,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);
@ -672,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",

View File

@ -39,7 +39,7 @@ extern "C"
}
#include <kvp_frame.hpp>
#include "../gnc-backend-dbi-priv.h"
#include "../gnc-backend-dbi.hpp"
G_GNUC_UNUSED static QofLogModule log_module = "test-dbi";
@ -210,31 +210,23 @@ 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);
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<const char*> (iter->data));
g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn, &errmsg));
conn->provider()->drop_index (be->conn, index);
g_assert (DBI_ERROR_NONE == dbi_conn_error (conn->conn(), &errmsg));
}
g_slist_free (index_list);
}
#endif
static void
compare_pricedbs (QofBook* book_1, QofBook* book_2)
{

View File

@ -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

View File

@ -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 \

View File

@ -62,30 +62,47 @@ 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" },
{ "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" },
{ NULL }
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid" ),
gnc_sql_make_table_entry<CT_STRING>(
"name", ACCOUNT_MAX_NAME_LEN, COL_NNUL, "name"),
gnc_sql_make_table_entry<CT_STRING>("account_type", ACCOUNT_MAX_TYPE_LEN,
COL_NNUL, ACCOUNT_TYPE_, true),
gnc_sql_make_table_entry<CT_COMMODITYREF>(
"commodity_guid", 0, 0, "commodity"),
gnc_sql_make_table_entry<CT_INT>(
"commodity_scu", 0, COL_NNUL, "commodity-scu"),
gnc_sql_make_table_entry<CT_BOOLEAN>(
"non_std_scu", 0, COL_NNUL, "non-std-scu"),
gnc_sql_make_table_entry<CT_GUID>("parent_guid", 0, 0,
(QofAccessFunc)get_parent,
(QofSetterFunc)set_parent),
gnc_sql_make_table_entry<CT_STRING>(
"code", ACCOUNT_MAX_CODE_LEN, 0, "code"),
gnc_sql_make_table_entry<CT_STRING>(
"description", ACCOUNT_MAX_DESCRIPTION_LEN, 0, "description"),
gnc_sql_make_table_entry<CT_BOOLEAN>("hidden", 0, 0, "hidden"),
gnc_sql_make_table_entry<CT_BOOLEAN>("placeholder", 0, 0, "placeholder"),
};
static GncSqlColumnTableEntry parent_col_table[] =
static EntryVec parent_col_table
({
gnc_sql_make_table_entry<CT_GUID>(
"parent_guid", 0, 0, nullptr, (QofSetterFunc)set_parent_guid),
});
class GncSqlAccountBackend : public GncSqlObjectBackend
{
{ "parent_guid", CT_GUID, 0, 0, NULL, NULL, NULL, set_parent_guid },
{ NULL }
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;
@ -154,24 +171,23 @@ 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);
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);
@ -180,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<decltype (s)> (
g_malloc (sizeof (account_parent_guid_struct)));
@ -194,11 +210,9 @@ 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;
GncSqlResult* result;
QofBook* pBook;
GList* l_accounts_needing_parents = NULL;
GSList* bal_slist;
@ -208,130 +222,102 @@ load_all_accounts (GncSqlBackend* be)
ENTER ("");
pBook = be->book;
pBook = be->book();
stmt = gnc_sql_create_select_statement (be, TABLE_NAME);
if (stmt == NULL)
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);
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
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)
{
LEAVE ("stmt == NULL");
return;
gboolean progress_made = TRUE;
Account* root;
Account* pParent;
GList* elem;
while (progress_made)
{
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)
{
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);
}
}
}
/* 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)
{
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);
}
}
result = gnc_sql_execute_select_statement (be, stmt);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
/* Load starting balances */
bal_slist = gnc_sql_get_account_balances_slist (be);
for (bal = bal_slist; bal != NULL; bal = bal->next)
{
GncSqlRow* row = gnc_sql_result_get_first_row (result);
gchar* sql;
acct_balances_t* balances = (acct_balances_t*)bal->data;
while (row != NULL)
{
load_single_account (be, row, &l_accounts_needing_parents);
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
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);
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;)
{
account_parent_guid_struct* s = (account_parent_guid_struct*)elem->data;
pParent = xaccAccountLookup (&s->guid, be->book);
if (pParent != NULL)
{
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);
}
}
}
/* 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)
{
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;
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 ("");
}
/* ================================================================= */
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;
@ -359,7 +345,7 @@ gnc_sql_save_account (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;
}
@ -400,72 +386,40 @@ 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<CT_ACCOUNTREF>::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 (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);
if (val != NULL && G_VALUE_HOLDS_STRING (val) &&
g_value_get_string (val) != NULL)
{
(void)string_to_guid (g_value_get_string (val), &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);
}
}
else
{
PWARN ("Account ref '%s' not found", g_value_get_string (val));
}
}
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_colname_to_list,
gnc_sql_add_gvalue_objectref_guid_to_slist
};
template<> void
GncSqlColumnTableEntryImpl<CT_ACCOUNTREF>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
add_objectref_guid_to_table(be, vec);
}
template<> void
GncSqlColumnTableEntryImpl<CT_ACCOUNTREF>::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)
{
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 */
};
(void)qof_object_register_backend (GNC_ID_ACCOUNT, GNC_SQL_BACKEND, &be_data);
gnc_sql_register_col_type_handler (CT_ACCOUNTREF, &account_guid_handler);
static GncSqlAccountBackend be_data{
GNC_SQL_BACKEND_VERSION, GNC_ID_ACCOUNT, TABLE_NAME, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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;
@ -50,205 +49,97 @@ 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[] =
{
{ "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" },
{ NULL }
};
static EntryVec col_table
({
std::make_shared<GncSqlColumnTableEntryImpl<CT_STRING>>(
"name", CT_STRING, ADDRESS_MAX_NAME_LEN, COL_NNUL, "name"),
gnc_sql_make_table_entry<CT_STRING>(
"addr1", ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr1"),
gnc_sql_make_table_entry<CT_STRING>(
"addr2", ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr2"),
gnc_sql_make_table_entry<CT_STRING>(
"addr3", ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr3"),
gnc_sql_make_table_entry<CT_STRING>(
"addr4", ADDRESS_MAX_ADDRESS_LINE_LEN, COL_NNUL, "addr4"),
gnc_sql_make_table_entry<CT_STRING>(
"phone", ADDRESS_MAX_PHONE_LEN, COL_NNUL, "phone"),
gnc_sql_make_table_entry<CT_STRING>(
"fax", ADDRESS_MAX_FAX_LEN, COL_NNUL, "fax" ),
gnc_sql_make_table_entry<CT_STRING>(
"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<CT_ADDRESS>::load (const GncSqlBackend* be,
GncSqlRow& row,
QofIdTypeConst obj_name,
gpointer pObject) const noexcept
{
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++)
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->col_name);
val = gnc_sql_row_get_value_at_col_name (row, buf);
g_free (buf);
if (val == NULL)
auto buf = std::string{m_col_name} + "_" + subtable_row->m_col_name;
try
{
s = NULL;
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->m_gobj_param_name);
}
else
catch (std::invalid_argument)
{
s = g_value_get_string (val);
}
if (subtable->gobj_param_name != NULL)
{
g_object_set (addr, subtable->gobj_param_name, s, NULL);
}
else
{
if (subtable->qof_param_name != NULL)
{
setter = qof_class_get_parameter_setter (GNC_ID_ADDRESS,
subtable->qof_param_name);
}
else
{
setter = subtable->setter;
}
(*setter) (addr, (const gpointer)s);
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<AddressSetterFunc>(get_setter(obj_name)),
m_gobj_param_name);
}
static void
add_address_col_info_to_list (const GncSqlBackend* be,
const GncSqlColumnTableEntry* table_row,
GList** pList)
template<> void
GncSqlColumnTableEntryImpl<CT_ADDRESS>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
GncSqlColumnInfo* info;
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 = 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);
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;
*pList = g_list_append (*pList, info);
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_address_colname_to_list (const GncSqlColumnTableEntry* table_row,
GList** pList)
/* char is unusual in that we get a pointer but don't deref it to pass
* it to operator<<().
*/
template<> void
GncSqlColumnTableEntryImpl<CT_ADDRESS>::add_to_query(const GncSqlBackend* be,
QofIdTypeConst obj_name,
const gpointer pObject,
PairVec& vec) const noexcept
{
gnc_sql_add_subtable_colnames_to_list (table_row, col_table, pList);
}
auto addr(get_row_value_from_object<char*>(obj_name, pObject));
if (addr == nullptr) return;
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);
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)
for (auto const& subtable_row : col_table)
{
g_object_get (pObject, table_row->gobj_param_name, &addr, NULL);
auto s = subtable_row->get_row_value_from_object<char*>(GNC_ID_ADDRESS,
addr);
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)));
}
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;
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<decltype (addr)> (g_value_get_object (&value));
for (subtable_row = col_table; subtable_row->col_name != NULL; subtable_row++)
{
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);
}
}
}
static GncSqlColumnTypeHandler address_handler
= { load_address,
add_address_col_info_to_list,
add_address_colname_to_list,
add_gvalue_address_to_slist
};
/* ================================================================= */
void
gnc_address_sql_initialize (void)
{
gnc_sql_register_col_type_handler (CT_ADDRESS, &address_handler);
}
/* ========================== END OF FILE ===================== */

View File

@ -1,36 +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 <plongstaff@rogers.com>
*
* 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
#define CT_ADDRESS "address"
void gnc_address_sql_initialize (void);
#endif /* GNC_ADDRESS_SQL_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -61,35 +61,49 @@ 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" },
{ "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 },
{ NULL }
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_STRING>("name", MAX_NAME_LEN, COL_NNUL, "name"),
gnc_sql_make_table_entry<CT_STRING>("description", MAX_DESCRIPTION_LEN,
COL_NNUL, GNC_BILLTERM_DESC,
true),
gnc_sql_make_table_entry<CT_INT>("refcount", 0, COL_NNUL,
(QofAccessFunc)gncBillTermGetRefcount,
(QofSetterFunc)gncBillTermSetRefcount),
gnc_sql_make_table_entry<CT_BOOLEAN>("invisible", 0, COL_NNUL,
(QofAccessFunc)gncBillTermGetInvisible,
(QofSetterFunc)set_invisible),
gnc_sql_make_table_entry<CT_GUID>("parent", 0, 0,
(QofAccessFunc)bt_get_parent,
(QofSetterFunc)bt_set_parent),
gnc_sql_make_table_entry<CT_STRING>("type", MAX_TYPE_LEN, COL_NNUL,
GNC_BILLTERM_TYPE, true),
gnc_sql_make_table_entry<CT_INT>("duedays", 0, 0, GNC_BILLTERM_DUEDAYS,
true),
gnc_sql_make_table_entry<CT_INT>("discountdays", 0, 0,
GNC_BILLTERM_DISCDAYS, true),
gnc_sql_make_table_entry<CT_NUMERIC>("discount", 0, 0,
GNC_BILLTERM_DISCOUNT, true),
gnc_sql_make_table_entry<CT_INT>("cutoff", 0, 0, GNC_BILLTERM_CUTOFF,
true),
};
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 }
gnc_sql_make_table_entry<CT_INT64>("parent", 0, 0, nullptr,
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
@ -174,20 +188,19 @@ 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);
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);
@ -219,118 +232,93 @@ load_single_billterm (GncSqlBackend* be, GncSqlRow* row,
return pBillTerm;
}
static void
load_all_billterms (GncSqlBackend* be)
void
GncSqlBillTermBackend::load_all (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);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
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;
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 != nullptr)
instances.push_back(QOF_INSTANCE(pBillTerm));
}
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
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
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;
}
}
}
}
/* ================================================================= */
typedef struct
{
GncSqlBackend* be;
gboolean 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 = gnc_sql_save_billterm (data->be, inst);
}
auto data = static_cast<write_objects_t*>(p2);
data->commit(inst);
}
static gboolean
write_billterms (GncSqlBackend* be)
bool
GncSqlBillTermBackend::write (GncSqlBackend* be)
{
write_billterms_t data;
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);
write_objects_t data {be, true, this};
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;
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)
{
/* 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->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",
TABLE_VERSION);
@ -338,81 +326,40 @@ 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
GncSqlColumnTableEntryImpl<CT_BILLTERMREF>::load (const GncSqlBackend* be,
GncSqlRow& row,
QofIdTypeConst obj_name,
gpointer pObject) const noexcept
{
load_from_guid_ref(row, obj_name, pObject,
[be](GncGUID* g){
return gncBillTermLookup(be->book(), g);
});
}
/* ================================================================= */
static void
load_billterm_guid (const GncSqlBackend* be, GncSqlRow* row,
QofSetterFunc setter, gpointer pObject,
const GncSqlColumnTableEntry* table_row)
template<> void
GncSqlColumnTableEntryImpl<CT_BILLTERMREF>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
const GValue* val;
GncGUID guid;
GncBillTerm* term = NULL;
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);
if (val != NULL && G_VALUE_HOLDS_STRING (val) &&
g_value_get_string (val) != NULL)
{
string_to_guid (g_value_get_string (val), &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);
}
}
else
{
PWARN ("Billterm ref '%s' not found", g_value_get_string (val));
}
}
add_objectref_guid_to_table(be, vec);
}
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
};
template<> void
GncSqlColumnTableEntryImpl<CT_BILLTERMREF>::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)
{
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 */
};
qof_object_register_backend (GNC_ID_BILLTERM, GNC_SQL_BACKEND, &be_data);
gnc_sql_register_col_type_handler (CT_BILLTERMREF, &billterm_guid_handler);
static GncSqlBillTermBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_BILLTERM, TABLE_NAME, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -35,9 +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);
#endif /* GNC_BILLTERM_SQL_H */

View File

@ -56,18 +56,25 @@ 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" },
{
"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
},
{ NULL }
gnc_sql_make_table_entry<CT_GUID>(
"guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_GUID>("root_account_guid", 0, COL_NNUL,
(QofAccessFunc)get_root_account_guid,
set_root_account_guid),
gnc_sql_make_table_entry<CT_GUID>("root_template_guid", 0, COL_NNUL,
(QofAccessFunc)get_root_template_guid,
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;
};
/* ================================================================= */
@ -137,16 +144,15 @@ 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);
pBook = be->book;
pBook = be->book();
if (pBook == NULL)
{
pBook = qof_book_new ();
@ -160,91 +166,42 @@ 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;
GncSqlResult* result;
g_return_if_fail (be != NULL);
stmt = gnc_sql_create_select_statement (be, BOOK_TABLE);
if (stmt != NULL)
std::stringstream sql;
sql << "SELECT * FROM " << BOOK_TABLE;
auto stmt = be->create_statement_from_sql(sql.str());
if (stmt != nullptr)
{
result = gnc_sql_execute_select_statement (be, stmt);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
auto result = be->execute_select_statement(stmt);
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->set_loading(false);
commit (be, QOF_INSTANCE (be->book()));
be->set_loading(true);
}
else
{
// Otherwise, load the 1st book.
load_single_book (be, *row);
}
}
}
/* ================================================================= */
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 */
};
(void)qof_object_register_backend (GNC_ID_BOOK, GNC_SQL_BACKEND, &be_data);
static GncSqlBookBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_BOOK, BOOK_TABLE, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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 */

View File

@ -55,13 +55,16 @@ 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 }
gnc_sql_make_table_entry<CT_GUID>(
"guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_STRING>(
"name", BUDGET_MAX_NAME_LEN, COL_NNUL, "name"),
gnc_sql_make_table_entry<CT_STRING>(
"description", BUDGET_MAX_DESCRIPTION_LEN, 0, "description"),
gnc_sql_make_table_entry<CT_INT>(
"num_periods", 0, COL_NNUL, "num_periods"),
};
static QofInstance* get_budget (gpointer pObj);
@ -73,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;
@ -80,26 +97,22 @@ 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 },
{
"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
},
{ NULL }
gnc_sql_make_table_entry<CT_INT>(
"id", 0, COL_NNUL | COL_PKEY | COL_AUTOINC),
gnc_sql_make_table_entry<CT_BUDGETREF>("budget_guid", 0, COL_NNUL,
(QofAccessFunc)get_budget,
(QofSetterFunc)set_budget),
gnc_sql_make_table_entry<CT_ACCOUNTREF>("account_guid", 0, COL_NNUL,
(QofAccessFunc)get_account,
(QofSetterFunc)set_account),
gnc_sql_make_table_entry<CT_INT>("period_num", 0, COL_NNUL,
(QofAccessFunc)get_period_num,
(QofSetterFunc)set_period_num),
gnc_sql_make_table_entry<CT_NUMERIC>("amount", 0, COL_NNUL,
(QofAccessFunc)get_amount,
(QofSetterFunc)set_amount),
};
/* ================================================================= */
@ -193,35 +206,23 @@ static void
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);
(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 = be->create_statement_from_sql(sql);
g_free (sql);
if (stmt != NULL)
if (stmt != nullptr)
{
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 };
auto result = be->execute_select_statement(stmt);
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);
}
}
@ -235,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;
}
/**
@ -274,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;
@ -296,23 +297,22 @@ 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)
{
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);
@ -329,70 +329,52 @@ load_single_budget (GncSqlBackend* be, GncSqlRow* row)
return pBudget;
}
static void
load_all_budgets (GncSqlBackend* be)
void
GncSqlBudgetBackend::load_all (GncSqlBackend* be)
{
GncSqlStatement* stmt;
GncSqlResult* result;
GList* list = NULL;
InstanceVec instances;
g_return_if_fail (be != NULL);
stmt = gnc_sql_create_select_statement (be, BUDGET_TABLE);
if (stmt != NULL)
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)
{
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);
GncBudget* b;
while (row != NULL)
{
b = load_single_budget (be, row);
if (b != NULL)
{
list = g_list_prepend (list, b);
}
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);
}
}
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);
}
/* ================================================================= */
static void
create_budget_tables (GncSqlBackend* be)
void
GncSqlBudgetBackend::create_tables (GncSqlBackend* be)
{
gint version;
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);
}
}
/* ================================================================= */
static gboolean
save_budget (GncSqlBackend* be, QofInstance* inst)
bool
GncSqlBudgetBackend::commit (GncSqlBackend* be, QofInstance* inst)
{
GncBudget* pBudget = GNC_BUDGET (inst);
const GncGUID* guid;
@ -409,7 +391,7 @@ save_budget (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;
}
@ -455,18 +437,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;
@ -474,79 +456,47 @@ write_budgets (GncSqlBackend* be)
data.be = be;
data.is_ok = TRUE;
qof_collection_foreach (qof_book_get_collection (be->book, GNC_ID_BUDGET),
(QofInstanceForeachCB)do_save_budget, &data);
data.obe = this;
qof_collection_foreach (qof_book_get_collection (be->book(), GNC_ID_BUDGET),
(QofInstanceForeachCB)do_save, &data);
return data.is_ok;
}
/* ================================================================= */
static void
load_budget_guid (const GncSqlBackend* be, GncSqlRow* row,
QofSetterFunc setter, gpointer pObject,
const GncSqlColumnTableEntry* table_row)
template<> void
GncSqlColumnTableEntryImpl<CT_BUDGETREF>::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 (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);
if (val != NULL && G_VALUE_HOLDS_STRING (val) &&
g_value_get_string (val) != NULL)
{
(void)string_to_guid (g_value_get_string (val), &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);
}
}
else
{
PWARN ("Budget ref '%s' not found", g_value_get_string (val));
}
}
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_colname_to_list,
gnc_sql_add_gvalue_objectref_guid_to_slist
};
template<> void
GncSqlColumnTableEntryImpl<CT_BUDGETREF>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
add_objectref_guid_to_table(be, vec);
}
template<> void
GncSqlColumnTableEntryImpl<CT_BUDGETREF>::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)
{
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 */
};
(void)qof_object_register_backend (GNC_ID_BUDGET, GNC_SQL_BACKEND, &be_data);
gnc_sql_register_col_type_handler (CT_BUDGETREF, &budget_guid_handler);
static GncSqlBudgetBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_BUDGET, BUDGET_TABLE, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -59,25 +59,39 @@ 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" },
{
"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" },
{ NULL }
gnc_sql_make_table_entry<CT_GUID>(
"guid", 0, COL_NNUL | COL_PKEY | COL_UNIQUE, "guid"),
gnc_sql_make_table_entry<CT_STRING>("namespace",
COMMODITY_MAX_NAMESPACE_LEN, COL_NNUL,
(QofAccessFunc)gnc_commodity_get_namespace,
(QofSetterFunc)gnc_commodity_set_namespace),
gnc_sql_make_table_entry<CT_STRING>(
"mnemonic", COMMODITY_MAX_MNEMONIC_LEN, COL_NNUL, "mnemonic"),
gnc_sql_make_table_entry<CT_STRING>(
"fullname", COMMODITY_MAX_FULLNAME_LEN, 0, "fullname"),
gnc_sql_make_table_entry<CT_STRING>(
"cusip", COMMODITY_MAX_CUSIP_LEN, 0, "cusip"),
gnc_sql_make_table_entry<CT_INT>("fraction", 0, COL_NNUL, "fraction"),
gnc_sql_make_table_entry<CT_BOOLEAN>(
"quote_flag", 0, COL_NNUL, "quote_flag"),
gnc_sql_make_table_entry<CT_STRING>("quote_source",
COMMODITY_MAX_QUOTESOURCE_LEN, 0,
(QofAccessFunc)get_quote_source_name,
set_quote_source_name),
gnc_sql_make_table_entry<CT_STRING>(
"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;
};
/* ================================================================= */
@ -113,9 +127,9 @@ 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;
QofBook* pBook = be->book();
gnc_commodity* pCommodity;
pCommodity = gnc_commodity_new (pBook, NULL, NULL, NULL, NULL, 100);
@ -126,63 +140,38 @@ load_single_commodity (GncSqlBackend* be, GncSqlRow* row)
return pCommodity;
}
static void
load_all_commodities (GncSqlBackend* be)
void
GncSqlCommodityBackend::load_all (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);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
pTable = gnc_commodity_table_get_table (be->book());
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)
{
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);
}
}
/* ================================================================= */
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,
@ -198,7 +187,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;
}
@ -226,8 +215,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);
@ -272,73 +261,40 @@ 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<CT_COMMODITYREF>::load (const GncSqlBackend* be,
GncSqlRow& row,
QofIdTypeConst obj_name,
gpointer pObject) const noexcept
{
const GValue* val;
GncGUID guid;
gnc_commodity* commodity = NULL;
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);
if (val != NULL && G_VALUE_HOLDS_STRING (val) &&
g_value_get_string (val) != NULL)
{
(void)string_to_guid (g_value_get_string (val), &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);
}
}
else
{
PWARN ("Commodity ref '%s' not found", g_value_get_string (val));
}
}
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_colname_to_list,
gnc_sql_add_gvalue_objectref_guid_to_slist
};
template<> void
GncSqlColumnTableEntryImpl<CT_COMMODITYREF>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
add_objectref_guid_to_table(be, vec);
}
template<> void
GncSqlColumnTableEntryImpl<CT_COMMODITYREF>::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)
{
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 */
};
(void)qof_object_register_backend (GNC_ID_COMMODITY, GNC_SQL_BACKEND,
&be_data);
gnc_sql_register_col_type_handler (CT_COMMODITYREF, &commodity_guid_handler);
GNC_SQL_BACKEND_VERSION, GNC_ID_COMMODITY, COMMODITIES_TABLE, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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"
@ -58,48 +57,63 @@ 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
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid" ),
gnc_sql_make_table_entry<CT_STRING>("name", MAX_NAME_LEN, COL_NNUL, "name"),
gnc_sql_make_table_entry<CT_STRING>("id", MAX_ID_LEN, COL_NNUL,
CUSTOMER_ID, true),
gnc_sql_make_table_entry<CT_STRING>("notes", MAX_NOTES_LEN, COL_NNUL,
CUSTOMER_NOTES, true),
gnc_sql_make_table_entry<CT_BOOLEAN>("active", 0, COL_NNUL,
QOF_PARAM_ACTIVE, true),
gnc_sql_make_table_entry<CT_NUMERIC>("discount", 0, COL_NNUL,
CUSTOMER_DISCOUNT, true),
gnc_sql_make_table_entry<CT_NUMERIC>("credit", 0, COL_NNUL,
CUSTOMER_CREDIT, true),
gnc_sql_make_table_entry<CT_COMMODITYREF>("currency", 0, COL_NNUL,
(QofAccessFunc)gncCustomerGetCurrency,
(QofSetterFunc)gncCustomerSetCurrency),
gnc_sql_make_table_entry<CT_BOOLEAN>("tax_override", 0, COL_NNUL,
CUSTOMER_TT_OVER, true),
gnc_sql_make_table_entry<CT_ADDRESS>("addr", 0, 0, CUSTOMER_ADDR,
true),
gnc_sql_make_table_entry<CT_ADDRESS>("shipaddr", 0, 0, CUSTOMER_SHIPADDR,
true),
gnc_sql_make_table_entry<CT_BILLTERMREF>("terms", 0, 0, CUSTOMER_TERMS,
true),
gnc_sql_make_table_entry<CT_INT>("tax_included", 0, 0,
(QofAccessFunc)gncCustomerGetTaxIncluded,
(QofSetterFunc)gncCustomerSetTaxIncluded),
gnc_sql_make_table_entry<CT_TAXTABLEREF>("taxtable", 0, 0,
(QofAccessFunc)gncCustomerGetTaxTable,
(QofSetterFunc)gncCustomerSetTaxTable),
});
class GncSqlCustomerBackend : public GncSqlObjectBackend
{
{ "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
},
{ NULL }
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)
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);
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));
@ -107,61 +121,46 @@ load_single_customer (GncSqlBackend* be, GncSqlRow* row)
return pCustomer;
}
static void
load_all_customers (GncSqlBackend* be)
void
GncSqlCustomerBackend::load_all (GncSqlBackend* be)
{
GncSqlStatement* stmt;
GncSqlResult* result;
g_return_if_fail (be != NULL);
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;
stmt = gnc_sql_create_select_statement (be, TABLE_NAME);
result = gnc_sql_execute_select_statement (be, stmt);
gnc_sql_statement_dispose (stmt);
if (result != 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)
{
list = g_list_append (list, pCustomer);
}
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);
}
GncCustomer* pCustomer = load_single_customer (be, row);
if (pCustomer != nullptr)
instances.push_back(QOF_INSTANCE(pCustomer));
}
if (!instances.empty())
gnc_sql_slots_load_for_instancevec (be, instances);
}
/* ================================================================= */
static void
create_customer_tables (GncSqlBackend* be)
void
GncSqlCustomerBackend::create_tables (GncSqlBackend* be)
{
gint version;
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)
{
/* 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->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",
TABLE_VERSION);
@ -169,24 +168,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)
{
@ -207,28 +188,29 @@ 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<write_objects_t*>(data_p);
g_return_if_fail (term_p != NULL);
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 = save_customer (data->be, term_p);
data->commit (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;
qof_object_foreach (GNC_ID_CUSTOMER, be->book, write_single_customer,
data.obe = this;
qof_object_foreach (GNC_ID_CUSTOMER, be->book(), write_single_customer,
(gpointer)&data);
return data.is_ok;
}
@ -237,17 +219,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 */
};
qof_object_register_backend (GNC_ID_CUSTOMER, GNC_SQL_BACKEND, &be_data);
static GncSqlCustomerBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_CUSTOMER, TABLE_NAME, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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
@ -58,36 +56,50 @@ static QofLogModule log_module = G_LOG_DOMAIN;
#define TABLE_NAME "employees"
#define TABLE_VERSION 2
static GncSqlColumnTableEntry col_table[] =
static EntryVec col_table
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_STRING>(
"username", MAX_USERNAME_LEN, COL_NNUL, "username"),
gnc_sql_make_table_entry<CT_STRING>("id", MAX_ID_LEN, COL_NNUL, "id"),
gnc_sql_make_table_entry<CT_STRING>(
"language", MAX_LANGUAGE_LEN, COL_NNUL, "language"),
gnc_sql_make_table_entry<CT_STRING>("acl", MAX_ACL_LEN, COL_NNUL, "acl"),
gnc_sql_make_table_entry<CT_BOOLEAN>("active", 0, COL_NNUL, "active"),
gnc_sql_make_table_entry<CT_COMMODITYREF>(
"currency", 0, COL_NNUL, "currency"),
gnc_sql_make_table_entry<CT_ACCOUNTREF>(
"ccard_guid", 0, 0, "credit-card-account"),
gnc_sql_make_table_entry<CT_NUMERIC>("workday", 0, COL_NNUL, "workday"),
gnc_sql_make_table_entry<CT_NUMERIC>("rate", 0, COL_NNUL, "rate"),
gnc_sql_make_table_entry<CT_ADDRESS>("addr", 0, 0, "address"),
});
class GncSqlEmployeeBackend : public GncSqlObjectBackend
{
{ "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" },
{ NULL }
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)
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);
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));
@ -95,60 +107,47 @@ load_single_employee (GncSqlBackend* be, GncSqlRow* row)
return pEmployee;
}
static void
load_all_employees (GncSqlBackend* be)
void
GncSqlEmployeeBackend::load_all (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);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
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;
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)
{
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);
}
GncEmployee* pEmployee = load_single_employee (be, row);
if (pEmployee != nullptr)
instances.push_back(QOF_INSTANCE(pEmployee));
}
if (!instances.empty())
gnc_sql_slots_load_for_instancevec (be, instances);
}
/* ================================================================= */
static void
create_employee_tables (GncSqlBackend* be)
void
GncSqlEmployeeBackend::create_tables (GncSqlBackend* be)
{
gint version;
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)
{
/* 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->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",
TABLE_VERSION);
@ -156,8 +155,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;
@ -176,7 +175,7 @@ save_employee (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;
}
@ -242,12 +241,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;
@ -255,7 +254,8 @@ write_employees (GncSqlBackend* be)
data.be = be;
data.is_ok = TRUE;
qof_object_foreach (GNC_ID_EMPLOYEE, be->book, write_single_employee, &data);
data.obe = this;
qof_object_foreach (GNC_ID_EMPLOYEE, be->book(), write_single_employee, &data);
return data.is_ok;
}
@ -264,17 +264,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 */
};
qof_object_register_backend (GNC_ID_EMPLOYEE, GNC_SQL_BACKEND, &be_data);
static GncSqlEmployeeBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_EMPLOYEE, TABLE_NAME, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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
@ -64,56 +63,76 @@ 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
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_TIMESPEC>("date", 0, COL_NNUL, ENTRY_DATE,
true),
gnc_sql_make_table_entry<CT_TIMESPEC>("date_entered", 0, 0,
ENTRY_DATE_ENTERED, true),
gnc_sql_make_table_entry<CT_STRING>(
"description", MAX_DESCRIPTION_LEN, 0, "description"),
gnc_sql_make_table_entry<CT_STRING>("action", MAX_ACTION_LEN, 0,
ENTRY_ACTION, true),
gnc_sql_make_table_entry<CT_STRING>("notes", MAX_NOTES_LEN, 0, ENTRY_NOTES,
true),
gnc_sql_make_table_entry<CT_NUMERIC>("quantity", 0, 0, ENTRY_QTY,
true),
gnc_sql_make_table_entry<CT_ACCOUNTREF>("i_acct", 0, 0, ENTRY_IACCT,
true),
gnc_sql_make_table_entry<CT_NUMERIC>("i_price", 0, 0, ENTRY_IPRICE,
true),
gnc_sql_make_table_entry<CT_NUMERIC>("i_discount", 0, 0,
(QofAccessFunc)gncEntryGetInvDiscount,
(QofSetterFunc)gncEntrySetInvDiscount),
gnc_sql_make_table_entry<CT_INVOICEREF>("invoice", 0, 0,
(QofAccessFunc)gncEntryGetInvoice,
(QofSetterFunc)entry_set_invoice),
gnc_sql_make_table_entry<CT_STRING>("i_disc_type", MAX_DISCTYPE_LEN, 0,
ENTRY_INV_DISC_TYPE, true),
gnc_sql_make_table_entry<CT_STRING>("i_disc_how", MAX_DISCHOW_LEN, 0,
ENTRY_INV_DISC_HOW, true),
gnc_sql_make_table_entry<CT_BOOLEAN>("i_taxable", 0, 0, ENTRY_INV_TAXABLE,
true),
gnc_sql_make_table_entry<CT_BOOLEAN>("i_taxincluded", 0, 0,
ENTRY_INV_TAX_INC, true),
gnc_sql_make_table_entry<CT_TAXTABLEREF>("i_taxtable", 0, 0,
(QofAccessFunc)gncEntryGetInvTaxTable,
(QofSetterFunc)gncEntrySetInvTaxTable),
gnc_sql_make_table_entry<CT_ACCOUNTREF>("b_acct", 0, 0, ENTRY_BACCT,
true),
gnc_sql_make_table_entry<CT_NUMERIC>("b_price", 0, 0, ENTRY_BPRICE,
true),
gnc_sql_make_table_entry<CT_INVOICEREF>("bill", 0, 0,
(QofAccessFunc)gncEntryGetBill,
(QofSetterFunc)entry_set_bill),
gnc_sql_make_table_entry<CT_BOOLEAN>("b_taxable", 0, 0, ENTRY_BILL_TAXABLE,
true),
gnc_sql_make_table_entry<CT_BOOLEAN>("b_taxincluded", 0, 0,
ENTRY_BILL_TAX_INC, true),
gnc_sql_make_table_entry<CT_TAXTABLEREF>("b_taxtable", 0, 0,
(QofAccessFunc)gncEntryGetBillTaxTable,
(QofSetterFunc)gncEntrySetBillTaxTable),
gnc_sql_make_table_entry<CT_INT>("b_paytype", 0, 0,
(QofAccessFunc)gncEntryGetBillPayment,
(QofSetterFunc)gncEntrySetBillPayment),
gnc_sql_make_table_entry<CT_BOOLEAN>("billable", 0, 0, ENTRY_BILLABLE,
true),
gnc_sql_make_table_entry<CT_OWNERREF>("billto", 0, 0, ENTRY_BILLTO, true),
gnc_sql_make_table_entry<CT_ORDERREF>("order_guid", 0, 0,
(QofAccessFunc)gncEntryGetOrder,
(QofSetterFunc)gncEntrySetOrder),
});
class GncSqlEntryBackend : public GncSqlObjectBackend
{
{ "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
},
{ NULL }
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
@ -151,19 +170,18 @@ 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);
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));
@ -171,54 +189,40 @@ load_single_entry (GncSqlBackend* be, GncSqlRow* row)
return pEntry;
}
static void
load_all_entries (GncSqlBackend* be)
void
GncSqlEntryBackend::load_all (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);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
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;
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)
{
list = g_list_append (list, pEntry);
}
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);
}
GncEntry* pEntry = load_single_entry (be, row);
if (pEntry != nullptr)
instances.push_back(QOF_INSTANCE(pEntry));
}
if (!instances.empty())
gnc_sql_slots_load_for_instancevec(be, instances);
}
/* ================================================================= */
static void
create_entry_tables (GncSqlBackend* be)
void
GncSqlEntryBackend::create_tables (GncSqlBackend* be)
{
gint version;
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)
{
@ -226,26 +230,14 @@ create_entry_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);
gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION);
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,
TABLE_VERSION);
}
}
/* ================================================================= */
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)
@ -262,20 +254,17 @@ 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);
qof_object_foreach (GNC_ID_ENTRY, be->book(), write_single_entry, &data);
return data.is_ok;
}
@ -284,17 +273,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 */
};
qof_object_register_backend (GNC_ID_ENTRY, GNC_SQL_BACKEND, &be_data);
static GncSqlEntryBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_ENTRY, TABLE_NAME, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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
@ -59,55 +58,69 @@ 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
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_STRING>("id", MAX_ID_LEN, COL_NNUL, INVOICE_ID,
true),
gnc_sql_make_table_entry<CT_TIMESPEC>("date_opened", 0, 0, INVOICE_OPENED,
true),
gnc_sql_make_table_entry<CT_TIMESPEC>("date_posted", 0, 0, INVOICE_POSTED,
true),
gnc_sql_make_table_entry<CT_STRING>("notes", MAX_NOTES_LEN, COL_NNUL,
"notes"),
gnc_sql_make_table_entry<CT_BOOLEAN>("active", 0, COL_NNUL,
QOF_PARAM_ACTIVE, true),
gnc_sql_make_table_entry<CT_COMMODITYREF>("currency", 0, COL_NNUL,
(QofAccessFunc)gncInvoiceGetCurrency,
(QofSetterFunc)gncInvoiceSetCurrency),
gnc_sql_make_table_entry<CT_OWNERREF>("owner", 0, 0,
(QofAccessFunc)gncInvoiceGetOwner,
(QofSetterFunc)gncInvoiceSetOwner),
gnc_sql_make_table_entry<CT_BILLTERMREF>("terms", 0, 0, INVOICE_TERMS,
true),
gnc_sql_make_table_entry<CT_STRING>("billing_id", MAX_BILLING_ID_LEN, 0,
INVOICE_BILLINGID, true),
gnc_sql_make_table_entry<CT_TXREF>("post_txn", 0, 0, INVOICE_POST_TXN,
true),
gnc_sql_make_table_entry<CT_LOTREF>("post_lot", 0, 0,
(QofAccessFunc)gncInvoiceGetPostedLot,
(QofSetterFunc)gncInvoiceSetPostedLot),
gnc_sql_make_table_entry<CT_ACCOUNTREF>("post_acc", 0, 0, INVOICE_ACC,
true),
gnc_sql_make_table_entry<CT_OWNERREF>("billto", 0, 0,
(QofAccessFunc)gncInvoiceGetBillTo,
(QofSetterFunc)gncInvoiceSetBillTo),
gnc_sql_make_table_entry<CT_NUMERIC>("charge_amt", 0, 0,
(QofAccessFunc)gncInvoiceGetToChargeAmount,
(QofSetterFunc)gncInvoiceSetToChargeAmount),
});
class GncSqlInvoiceBackend : public GncSqlObjectBackend
{
{ "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
},
{ NULL }
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)
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);
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));
@ -115,54 +128,40 @@ load_single_invoice (GncSqlBackend* be, GncSqlRow* row)
return pInvoice;
}
static void
load_all_invoices (GncSqlBackend* be)
void
GncSqlInvoiceBackend::load_all (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);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
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;
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)
{
list = g_list_append (list, pInvoice);
}
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);
}
GncInvoice* pInvoice = load_single_invoice (be, row);
if (pInvoice != nullptr)
instances.push_back(QOF_INSTANCE(pInvoice));
}
if (!instances.empty())
gnc_sql_slots_load_for_instancevec (be, instances);
}
/* ================================================================= */
static void
create_invoice_tables (GncSqlBackend* be)
void
GncSqlInvoiceBackend::create_tables (GncSqlBackend* be)
{
gint version;
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)
{
@ -170,8 +169,8 @@ create_invoice_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);
gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION);
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,
TABLE_VERSION);
@ -179,8 +178,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;
@ -199,7 +198,7 @@ save_invoice (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;
}
@ -257,7 +256,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<write_objects_t*>(data_p);
g_return_if_fail (term_p != NULL);
g_return_if_fail (GNC_IS_INVOICE (term_p));
@ -265,88 +264,56 @@ 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);
qof_object_foreach (GNC_ID_INVOICE, be->book(), write_single_invoice, &data);
return data.is_ok;
}
/* ================================================================= */
static void
load_invoice_guid (const GncSqlBackend* be, GncSqlRow* row,
QofSetterFunc setter, gpointer pObject,
const GncSqlColumnTableEntry* table_row)
template<> void
GncSqlColumnTableEntryImpl<CT_INVOICEREF>::load (const GncSqlBackend* be,
GncSqlRow& row,
QofIdTypeConst obj_name,
gpointer pObject) const noexcept
{
const GValue* val;
GncGUID guid;
GncInvoice* invoice = NULL;
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);
if (val != NULL && G_VALUE_HOLDS_STRING (val) &&
g_value_get_string (val) != NULL)
{
string_to_guid (g_value_get_string (val), &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);
}
}
else
{
PWARN ("Invoice ref '%s' not found", g_value_get_string (val));
}
}
load_from_guid_ref(row, obj_name, pObject,
[be](GncGUID* g){
return gncInvoiceLookup (be->book(), g);
});
}
template<> void
GncSqlColumnTableEntryImpl<CT_INVOICEREF>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
add_objectref_guid_to_table(be, vec);
}
template<> void
GncSqlColumnTableEntryImpl<CT_INVOICEREF>::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_colname_to_list,
gnc_sql_add_gvalue_objectref_guid_to_slist
};
/* ================================================================= */
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 */
};
qof_object_register_backend (GNC_ID_INVOICE, GNC_SQL_BACKEND, &be_data);
gnc_sql_register_col_type_handler (CT_INVOICEREF, &invoice_guid_handler);
static GncSqlInvoiceBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_INVOICE, TABLE_NAME, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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 */

View File

@ -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
@ -54,37 +53,46 @@ 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
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_STRING>("id", MAX_ID_LEN, COL_NNUL,
JOB_ID, true),
gnc_sql_make_table_entry<CT_STRING>("name", MAX_NAME_LEN, COL_NNUL, "name"),
gnc_sql_make_table_entry<CT_STRING>("reference", MAX_REFERENCE_LEN,
COL_NNUL, JOB_REFERENCE, true),
gnc_sql_make_table_entry<CT_BOOLEAN>("active", 0, COL_NNUL,
(QofAccessFunc)gncJobGetActive,
(QofSetterFunc)gncJobSetActive),
gnc_sql_make_table_entry<CT_OWNERREF>("owner", 0, 0,
(QofAccessFunc)gncJobGetOwner,
(QofSetterFunc)gncJobSetOwner),
});
class GncSqlJobBackend : public GncSqlObjectBackend
{
{ "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
},
{ NULL }
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)
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);
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));
@ -92,67 +100,26 @@ load_single_job (GncSqlBackend* be, GncSqlRow* row)
return pJob;
}
static void
load_all_jobs (GncSqlBackend* be)
void
GncSqlJobBackend::load_all (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);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
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;
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)
{
list = g_list_append (list, pJob);
}
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);
}
GncJob* pJob = load_single_job (be, row);
if (pJob != nullptr)
instances.push_back(QOF_INSTANCE(pJob));
}
}
/* ================================================================= */
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);
if (!instances.empty())
gnc_sql_slots_load_for_instancevec (be, instances);
}
/* ================================================================= */
@ -176,7 +143,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<write_objects_t*>(data_p);
g_return_if_fail (term_p != NULL);
g_return_if_fail (GNC_IS_JOB (term_p));
@ -184,20 +151,17 @@ 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);
qof_object_foreach (GNC_ID_JOB, be->book(), write_single_job, &data);
return data.is_ok;
}
@ -206,17 +170,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 */
};
qof_object_register_backend (GNC_ID_JOB, GNC_SQL_BACKEND, &be_data);
static GncSqlJobBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_JOB, TABLE_NAME, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -54,15 +54,24 @@ 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
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_ACCOUNTREF>("account_guid", 0, 0,
(QofAccessFunc)get_lot_account,
set_lot_account),
gnc_sql_make_table_entry<CT_BOOLEAN>("is_closed", 0, COL_NNUL, "is-closed")
});
class GncSqlLotsBackend : public GncSqlObjectBackend
{
{ "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 }
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;
};
/* ================================================================= */
@ -98,14 +107,13 @@ 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);
lot = gnc_lot_new (be->book());
gnc_lot_begin_edit (lot);
gnc_sql_load_object (be, row, GNC_ID_LOT, lot, col_table);
@ -114,51 +122,42 @@ load_single_lot (GncSqlBackend* be, GncSqlRow* row)
return lot;
}
static void
load_all_lots (GncSqlBackend* be)
void
GncSqlLotsBackend::load_all (GncSqlBackend* be)
{
GncSqlStatement* stmt;
GncSqlResult* result;
g_return_if_fail (be != NULL);
stmt = gnc_sql_create_select_statement (be, TABLE_NAME);
if (stmt != NULL)
std::stringstream sql;
sql << "SELECT * FROM " << TABLE_NAME;
auto stmt = be->create_statement_from_sql(sql.str());
if (stmt != nullptr)
{
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;
auto result = be->execute_select_statement(stmt);
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);
}
}
/* ================================================================= */
static void
create_lots_tables (GncSqlBackend* be)
void
GncSqlLotsBackend::create_tables (GncSqlBackend* be)
{
gint version;
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)
{
@ -168,117 +167,70 @@ create_lots_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);
(void)gnc_sql_set_table_version (be, TABLE_NAME, TABLE_VERSION);
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);
}
}
/* ================================================================= */
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<write_objects_t*>(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),
qof_collection_foreach (qof_book_get_collection (be->book(), GNC_ID_LOT),
(QofInstanceForeachCB)do_save_lot, &data);
return data.is_ok;
}
/* ================================================================= */
static void
load_lot_guid (const GncSqlBackend* be, GncSqlRow* row,
QofSetterFunc setter, gpointer pObject,
const GncSqlColumnTableEntry* table_row)
template<> void
GncSqlColumnTableEntryImpl<CT_LOTREF>::load (const GncSqlBackend* be,
GncSqlRow& row,
QofIdTypeConst obj_name,
gpointer pObject) const noexcept
{
const GValue* val;
GncGUID guid;
GNCLot* lot;
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);
if (val != NULL && G_VALUE_HOLDS_STRING (val) &&
g_value_get_string (val) != NULL)
{
(void)string_to_guid (g_value_get_string (val), &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);
}
}
else
{
PWARN ("Lot ref '%s' not found", g_value_get_string (val));
}
}
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_colname_to_list,
gnc_sql_add_gvalue_objectref_guid_to_slist
};
template<> void
GncSqlColumnTableEntryImpl<CT_LOTREF>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
add_objectref_guid_to_table(be, vec);
}
template<> void
GncSqlColumnTableEntryImpl<CT_LOTREF>::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)
{
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 */
};
(void)qof_object_register_backend (GNC_ID_LOT, GNC_SQL_BACKEND, &be_data);
gnc_sql_register_col_type_handler (CT_LOTREF, &lot_guid_handler);
static GncSqlLotsBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_LOT, TABLE_NAME, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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
@ -54,33 +53,46 @@ 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
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_STRING>("id", MAX_ID_LEN, COL_NNUL, "id"),
gnc_sql_make_table_entry<CT_STRING>("notes", MAX_NOTES_LEN, COL_NNUL,
"notes"),
gnc_sql_make_table_entry<CT_STRING>(
"reference", MAX_REFERENCE_LEN, COL_NNUL, "reference"),
gnc_sql_make_table_entry<CT_BOOLEAN>("active", 0, COL_NNUL, "order"),
gnc_sql_make_table_entry<CT_TIMESPEC>("date_opened", 0, COL_NNUL,
"date-opened"),
gnc_sql_make_table_entry<CT_TIMESPEC>("date_closed", 0, COL_NNUL,
"date-closed"),
gnc_sql_make_table_entry<CT_OWNERREF>("owner", 0, COL_NNUL,
ORDER_OWNER, true),
});
class GncSqlOrderBackend : public GncSqlObjectBackend
{
{ "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 },
{ NULL },
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)
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);
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));
@ -88,67 +100,26 @@ load_single_order (GncSqlBackend* be, GncSqlRow* row)
return pOrder;
}
static void
load_all_orders (GncSqlBackend* be)
void
GncSqlOrderBackend::load_all (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);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
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;
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)
{
list = g_list_append (list, pOrder);
}
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);
}
GncOrder* pOrder = load_single_order (be, row);
if (pOrder != nullptr)
instances.push_back(QOF_INSTANCE(pOrder));
}
}
/* ================================================================= */
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);
if (!instances.empty())
gnc_sql_slots_load_for_instancevec (be, instances);
}
/* ================================================================= */
@ -172,7 +143,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<write_objects_t*>(data_p);
g_return_if_fail (term_p != NULL);
g_return_if_fail (GNC_IS_ORDER (term_p));
@ -180,88 +151,56 @@ 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);
qof_object_foreach (GNC_ID_ORDER, be->book(), write_single_order, &data);
return data.is_ok;
}
/* ================================================================= */
static void
load_order_guid (const GncSqlBackend* be, GncSqlRow* row,
QofSetterFunc setter, gpointer pObject,
const GncSqlColumnTableEntry* table_row)
template<> void
GncSqlColumnTableEntryImpl<CT_ORDERREF>::load (const GncSqlBackend* be,
GncSqlRow& row,
QofIdTypeConst obj_name,
gpointer pObject) const noexcept
{
const GValue* val;
GncGUID guid;
GncOrder* order = NULL;
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);
if (val != NULL && G_VALUE_HOLDS_STRING (val) &&
g_value_get_string (val) != NULL)
{
string_to_guid (g_value_get_string (val), &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);
}
}
else
{
PWARN ("Order ref '%s' not found", g_value_get_string (val));
}
}
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_colname_to_list,
gnc_sql_add_gvalue_objectref_guid_to_slist
};
template<> void
GncSqlColumnTableEntryImpl<CT_ORDERREF>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
add_objectref_guid_to_table(be, vec);
}
template<> void
GncSqlColumnTableEntryImpl<CT_ORDERREF>::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)
{
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};
qof_object_register_backend (GNC_ID_ORDER, GNC_SQL_BACKEND, &be_data);
gnc_sql_register_col_type_handler (CT_ORDERREF, &order_guid_handler);
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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 */

View File

@ -41,46 +41,40 @@ 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<CT_OWNERREF>::load (const GncSqlBackend* be,
GncSqlRow& row,
QofIdTypeConst obj_name,
gpointer pObject) const noexcept
{
const GValue* val;
gchar* buf;
GncOwnerType type;
GncGUID guid;
QofBook* book;
GncOwner owner;
GncGUID* pGuid = NULL;
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);
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 = std::string{m_col_name} + "_type";
try
{
string_to_guid (g_value_get_string (val), &guid);
type = static_cast<decltype(type)>(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;
}
catch (std::invalid_argument)
{
return;
}
switch (type)
{
@ -155,97 +149,48 @@ 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, get_setter(obj_name), m_gobj_param_name);
}
static void
add_owner_col_info_to_list (const GncSqlBackend* be,
const GncSqlColumnTableEntry* table_row,
GList** pList)
template<> void
GncSqlColumnTableEntryImpl<CT_OWNERREF>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
GncSqlColumnInfo* info;
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);
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;
*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;
*pList = g_list_append (*pList, info);
auto buf = g_strdup_printf ("%s_type", m_col_name);
GncSqlColumnInfo info(buf, BCT_INT, 0, false, false,
m_flags & COL_PKEY, m_flags & COL_NNUL);
vec.emplace_back(std::move(info));
/* 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_colname_to_list (const GncSqlColumnTableEntry* table_row, GList** pList)
template<> void
GncSqlColumnTableEntryImpl<CT_OWNERREF>::add_to_query(const GncSqlBackend* be,
QofIdTypeConst obj_name,
const gpointer pObject,
PairVec& vec) const noexcept
{
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);
g_return_if_fail (table_row != NULL);
getter = (OwnerGetterFunc)gnc_sql_get_getter (obj_name, table_row);
owner = (*getter) (pObject);
auto getter = (OwnerGetterFunc)get_getter (obj_name);
auto owner = (*getter) (pObject);
if (owner != NULL)
QofInstance* inst = nullptr;
GncOwnerType type;
auto type_hdr = std::string{m_col_name} + "_type";
auto guid_hdr = std::string{m_col_name} + "_guid";
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:
@ -267,43 +212,25 @@ 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;
}
}
std::ostringstream buf;
static GncSqlColumnTypeHandler owner_handler
= { load_owner,
add_owner_col_info_to_list,
add_colname_to_list,
add_gvalue_owner_to_slist
};
/* ================================================================= */
void
gnc_owner_sql_initialize (void)
{
gnc_sql_register_col_type_handler (CT_OWNERREF, &owner_handler);
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()));
}
/* ========================== END OF FILE ===================== */

View File

@ -1,36 +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 <plongstaff@rogers.com>
*
* 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
#define CT_OWNERREF "owner"
void gnc_owner_sql_initialize (void);
#endif /* GNC_OWNER_SQL_H */

View File

@ -53,29 +53,43 @@ 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
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_COMMODITYREF>("commodity_guid", 0, COL_NNUL,
"commodity"),
gnc_sql_make_table_entry<CT_COMMODITYREF>("currency_guid", 0, COL_NNUL,
"currency"),
gnc_sql_make_table_entry<CT_TIMESPEC>("date", 0, COL_NNUL, "date"),
gnc_sql_make_table_entry<CT_STRING>("source", PRICE_MAX_SOURCE_LEN, 0,
"source"),
gnc_sql_make_table_entry<CT_STRING>("type", PRICE_MAX_TYPE_LEN, 0, "type"),
gnc_sql_make_table_entry<CT_NUMERIC>("value", 0, COL_NNUL, "value")
});
class GncSqlPriceBackend : public GncSqlObjectBackend
{
{ "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 }
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*
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);
pPrice = gnc_price_create (be->book());
gnc_price_begin_edit (pPrice);
gnc_sql_load_object (be, row, GNC_ID_PRICE, pPrice, col_table);
@ -84,69 +98,65 @@ load_single_price (GncSqlBackend* be, GncSqlRow* row)
return pPrice;
}
static void
load_all_prices (GncSqlBackend* be)
void
GncSqlPriceBackend::load_all (GncSqlBackend* be)
{
GncSqlStatement* stmt;
GncSqlResult* result;
QofBook* pBook;
GNCPriceDB* pPriceDB;
g_return_if_fail (be != NULL);
pBook = be->book;
pBook = be->book();
pPriceDB = gnc_pricedb_get_db (pBook);
stmt = gnc_sql_create_select_statement (be, TABLE_NAME);
if (stmt != NULL)
std::stringstream sql;
sql << "SELECT * FROM " << TABLE_NAME;
auto stmt = be->create_statement_from_sql(sql.str());
if (stmt != nullptr)
{
result = gnc_sql_execute_select_statement (be, stmt);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
auto result = be->execute_select_statement(stmt);
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);
}
}
/* ================================================================= */
static void
create_prices_tables (GncSqlBackend* be)
void
GncSqlPriceBackend::create_tables (GncSqlBackend* be)
{
gint version;
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)
{
/* 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->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);
}
@ -154,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;
@ -171,7 +181,7 @@ save_price (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;
}
@ -196,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<write_objects_t*>(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);
}
@ -231,18 +236,9 @@ 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 */
};
(void)qof_object_register_backend (GNC_ID_PRICE, GNC_SQL_BACKEND, &be_data);
static GncSqlPriceBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_PRICE, TABLE_NAME, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -69,50 +69,59 @@ 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[] =
{
{ "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
},
{ NULL }
};
static const EntryVec col_table
({
gnc_sql_make_table_entry<CT_INT>(
"id", 0, COL_PKEY | COL_NNUL | COL_AUTOINC),
gnc_sql_make_table_entry<CT_GUID>("obj_guid", 0, COL_NNUL,
(QofAccessFunc)get_obj_guid, (QofSetterFunc)set_obj_guid),
gnc_sql_make_table_entry<CT_INT>(
"recurrence_mult", 0, COL_NNUL,
(QofAccessFunc)get_recurrence_mult, (QofSetterFunc)set_recurrence_mult),
gnc_sql_make_table_entry<CT_STRING>(
"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<CT_GDATE>(
"recurrence_period_start", 0, COL_NNUL,
(QofAccessFunc)get_recurrence_period_start,
set_recurrence_period_start),
gnc_sql_make_table_entry<CT_STRING>(
"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 GncSqlColumnTableEntry guid_col_table[] =
{
{
"obj_guid", CT_GUID, 0, 0, NULL, NULL,
(QofAccessFunc)get_obj_guid, (QofSetterFunc)set_obj_guid
},
{ NULL }
};
static const EntryVec guid_col_table
({
gnc_sql_make_table_entry<CT_GUID>("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 GncSqlColumnTableEntry weekend_adjust_col_table[] =
static const EntryVec weekend_adjust_col_table
({
gnc_sql_make_table_entry<CT_STRING>(
"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
{
{
"recurrence_weekend_adjust", CT_STRING, BUDGET_MAX_RECURRENCE_WEEKEND_ADJUST_LEN, 0,
},
{ NULL }
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; }
};
/* ================================================================= */
@ -287,12 +296,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;
@ -301,13 +309,11 @@ 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);
@ -315,43 +321,33 @@ 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 = be->create_statement_from_sql (buf);
g_free (buf);
result = gnc_sql_execute_select_statement (be, stmt);
gnc_sql_statement_dispose (stmt);
auto result = be->execute_select_statement(stmt);
return result;
}
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;
}
@ -359,26 +355,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;
@ -389,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");
@ -400,32 +388,32 @@ 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].col_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);
}
static void
create_recurrence_tables (GncSqlBackend* be)
void
GncSqlRecurrenceBackend::create_tables (GncSqlBackend* be)
{
gint version;
gboolean ok;
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)
{
@ -436,7 +424,7 @@ create_recurrence_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);
}
@ -446,19 +434,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 */
};
(void)qof_object_register_backend (TABLE_NAME, GNC_SQL_BACKEND, &be_data);
static GncSqlRecurrenceBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_ACCOUNT, TABLE_NAME, col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -55,28 +55,45 @@ 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
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_STRING>("name", SX_MAX_NAME_LEN, 0, "name"),
gnc_sql_make_table_entry<CT_BOOLEAN>("enabled", 0, COL_NNUL, "enabled"),
gnc_sql_make_table_entry<CT_GDATE>("start_date", 0, 0, "start-date"),
gnc_sql_make_table_entry<CT_GDATE>("end_date", 0, 0, "end-date"),
gnc_sql_make_table_entry<CT_GDATE>(
"last_occur", 0, 0, "last-occurance-date"),
gnc_sql_make_table_entry<CT_INT>(
"num_occur", 0, COL_NNUL, "num-occurance"),
gnc_sql_make_table_entry<CT_INT>("rem_occur", 0, COL_NNUL, "rem-occurance"),
gnc_sql_make_table_entry<CT_BOOLEAN>(
"auto_create", 0, COL_NNUL, "auto-create"),
gnc_sql_make_table_entry<CT_BOOLEAN>(
"auto_notify", 0, COL_NNUL, "auto-create-notify"),
gnc_sql_make_table_entry<CT_INT>(
"adv_creation", 0, COL_NNUL, "advance-creation-days"),
gnc_sql_make_table_entry<CT_INT>(
"adv_notify", 0, COL_NNUL, "advance-reminder-days"),
gnc_sql_make_table_entry<CT_INT>(
"instance_count", 0, COL_NNUL, "instance-count"),
gnc_sql_make_table_entry<CT_ACCOUNTREF>(
"template_act_guid", 0, COL_NNUL, "template-account"),
});
class GncSqlSchedXactionBackend : public GncSqlObjectBackend
{
{ "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" },
{ NULL }
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)
load_single_sx (GncSqlBackend* be, GncSqlRow& row)
{
const GncGUID* guid;
SchedXaction* pSx;
@ -84,11 +101,10 @@ 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);
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);
@ -102,66 +118,40 @@ 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;
GncSqlResult* result;
g_return_if_fail (be != NULL);
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;
result = gnc_sql_execute_select_statement (be, stmt);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
auto result = be->execute_select_statement(stmt);
SchedXactions* sxes;
InstanceVec instances;
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 != nullptr)
{
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_sql_result_dispose (result);
if (list != NULL)
{
gnc_sql_slots_load_for_list (be, list);
g_list_free (list);
gnc_sxes_add_sx (sxes, sx);
instances.push_back(QOF_INSTANCE(sx));
}
}
if (!instances.empty())
gnc_sql_slots_load_for_instancevec (be, instances);
}
/* ================================================================= */
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;
@ -180,7 +170,7 @@ gnc_sql_save_schedxaction (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;
}
@ -220,20 +210,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 */
};
(void)qof_object_register_backend (GNC_ID_SCHEDXACTION, GNC_SQL_BACKEND,
&be_data);
static GncSqlSchedXactionBackend be_data {
GNC_SQL_BACKEND_VERSION, GNC_ID_SCHEDXACTION, SCHEDXACTION_TABLE,
col_table};
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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);
@ -110,65 +110,69 @@ 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 },
{
"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
},
{ NULL }
gnc_sql_make_table_entry<CT_INT>(
"id", 0, COL_PKEY | COL_NNUL | COL_AUTOINC),
gnc_sql_make_table_entry<CT_GUID>("obj_guid", 0, COL_NNUL,
(QofAccessFunc)get_obj_guid,
(QofSetterFunc)set_obj_guid),
gnc_sql_make_table_entry<CT_STRING>("name", SLOT_MAX_PATHNAME_LEN, COL_NNUL,
(QofAccessFunc)get_path, set_path),
gnc_sql_make_table_entry<CT_INT>("slot_type", 0, COL_NNUL,
(QofAccessFunc)get_slot_type,
set_slot_type),
gnc_sql_make_table_entry<CT_INT64>("int64_val", 0, 0,
(QofAccessFunc)get_int64_val,
(QofSetterFunc)set_int64_val),
gnc_sql_make_table_entry<CT_STRING>("string_val", SLOT_MAX_PATHNAME_LEN, 0,
(QofAccessFunc)get_string_val,
set_string_val),
gnc_sql_make_table_entry<CT_DOUBLE>("double_val", 0, 0,
(QofAccessFunc)get_double_val,
set_double_val),
gnc_sql_make_table_entry<CT_TIMESPEC>("timespec_val", 0, 0,
(QofAccessFunc)get_timespec_val,
(QofSetterFunc)set_timespec_val),
gnc_sql_make_table_entry<CT_GUID>("guid_val", 0, 0,
(QofAccessFunc)get_guid_val,
set_guid_val),
gnc_sql_make_table_entry<CT_NUMERIC>("numeric_val", 0, 0,
(QofAccessFunc)get_numeric_val,
(QofSetterFunc)set_numeric_val),
gnc_sql_make_table_entry<CT_GDATE>("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 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 }
gnc_sql_make_table_entry<CT_GUID>("obj_guid", 0, 0,
(QofAccessFunc)get_obj_guid,
_retrieve_guid_),
};
static const GncSqlColumnTableEntry gdate_col_table[] =
static const EntryVec gdate_col_table
{
{ "gdate_val", CT_GDATE, 0, 0, },
{ NULL }
gnc_sql_make_table_entry<CT_GDATE>("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; }
};
/* ================================================================= */
@ -439,7 +443,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;
@ -447,7 +451,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);
}
@ -556,7 +560,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;
@ -564,7 +568,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*
@ -710,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);
}
@ -727,9 +731,7 @@ 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) };
g_return_val_if_fail (be != NULL, FALSE);
@ -739,30 +741,26 @@ 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 = be->create_statement_from_sql(buf);
g_free (buf);
if (stmt != NULL)
if (stmt != nullptr)
{
result = gnc_sql_execute_select_statement (be, stmt);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
auto result = be->execute_select_statement(stmt);
for (auto row : *result)
{
GncSqlRow* row = gnc_sql_result_get_first_row (result);
while (row != NULL)
try
{
GncSqlColumnTableEntry table_row = col_table[guid_val_col];
const GncSqlColumnTableEntryPtr 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)
continue;
(void)string_to_guid (g_value_get_string (val), &child_guid);
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);
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
catch (std::invalid_argument)
{
continue;
}
}
}
@ -776,13 +774,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);
@ -827,10 +824,7 @@ gnc_sql_slots_load (GncSqlBackend* be, QofInstance* inst)
static void
slots_load_info (slot_info_t* pInfo)
{
gchar* buf;
GncSqlResult* result;
gchar guid_buf[GUID_ENCODING_LENGTH + 1];
GncSqlStatement* stmt;
g_return_if_fail (pInfo != NULL);
g_return_if_fail (pInfo->be != NULL);
@ -839,35 +833,24 @@ 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);
stmt = gnc_sql_create_statement_from_sql (pInfo->be, buf);
g_free (buf);
if (stmt != NULL)
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)
{
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);
}
auto result = pInfo->be->execute_select_statement (stmt);
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);
@ -875,7 +858,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 };
@ -883,7 +866,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);
@ -903,68 +885,45 @@ 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;
GncSqlStatement* stmt;
GString* sql;
GncSqlResult* result;
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].col_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
stmt = gnc_sql_create_statement_from_sql (be, sql->str);
if (stmt == NULL)
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);
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);
}
auto result = be->execute_select_statement (stmt);
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 };
@ -972,12 +931,11 @@ 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);
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;
@ -1006,8 +964,6 @@ void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* be,
BookLookupFn lookup_fn)
{
gchar* sql;
GncSqlStatement* stmt;
GncSqlResult* result;
g_return_if_fail (be != NULL);
@ -1015,49 +971,39 @@ 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
stmt = gnc_sql_create_statement_from_sql (be, sql);
if (stmt == NULL)
auto stmt = be->create_statement_from_sql(sql);
if (stmt == nullptr)
{
PERR ("stmt == NULL, SQL = '%s'\n", sql);
g_free (sql);
return;
}
g_free (sql);
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);
}
auto result = be->execute_select_statement(stmt);
for (auto row : *result)
load_slot_for_book_object (be, row, lookup_fn);
}
/* ================================================================= */
static void
create_slots_tables (GncSqlBackend* be)
void
GncSqlSlotsBackend::create_tables (GncSqlBackend* be)
{
gint version;
gboolean ok;
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");
@ -1071,9 +1017,9 @@ create_slots_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);
be->upgrade_table(TABLE_NAME, col_table);
ok = be->create_index ("slots_guid_index", TABLE_NAME,
obj_guid_col_table);
if (!ok)
{
PERR ("Unable to create index\n");
@ -1081,13 +1027,13 @@ create_slots_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");
}
}
(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);
}
@ -1097,19 +1043,9 @@ create_slots_tables (GncSqlBackend* be)
void
gnc_sql_init_slots_handler (void)
{
static GncSqlObjectBackend be_data =
{
GNC_SQL_BACKEND_VERSION,
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 */
};
(void)qof_object_register_backend (TABLE_NAME, GNC_SQL_BACKEND, &be_data);
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));
}
/* ========================== END OF FILE ===================== */

View File

@ -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);

View File

@ -65,58 +65,64 @@ 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[] =
{
{ "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,
static EntryVec tt_col_table
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid" ),
gnc_sql_make_table_entry<CT_STRING>("name", MAX_NAME_LEN, COL_NNUL, "name" ),
gnc_sql_make_table_entry<CT_INT64>("refcount", 0, COL_NNUL, "ref-count" ),
gnc_sql_make_table_entry<CT_BOOLEAN>("invisible", 0, COL_NNUL, "invisible" ),
/* gnc_sql_make_table_entry<CT_TAXTABLEREF>("child", 0, 0,
get_child, (QofSetterFunc)gncTaxTableSetChild ), */
gnc_sql_make_table_entry<CT_GUID>("parent", 0, 0,
(QofAccessFunc)bt_get_parent, tt_set_parent
},
{ NULL }
};
),
});
static GncSqlColumnTableEntry tt_parent_col_table[] =
{
{ "parent", CT_GUID, 0, 0, NULL, NULL, NULL, tt_set_parent_guid },
{ NULL }
};
static EntryVec tt_parent_col_table
({
gnc_sql_make_table_entry<CT_GUID>("parent", 0, 0, nullptr,
tt_set_parent_guid ),
});
#define TTENTRIES_TABLE_NAME "taxtable_entries"
#define TTENTRIES_TABLE_VERSION 3
static GncSqlColumnTableEntry 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
},
{ NULL }
};
static EntryVec ttentries_col_table
({
gnc_sql_make_table_entry<CT_INT>(
"id", 0, COL_PKEY | COL_NNUL | COL_AUTOINC),
gnc_sql_make_table_entry<CT_TAXTABLEREF>("taxtable", 0, COL_NNUL,
(QofAccessFunc)gncTaxTableEntryGetTable,
set_obj_guid),
gnc_sql_make_table_entry<CT_ACCOUNTREF>("account", 0, COL_NNUL,
(QofAccessFunc)gncTaxTableEntryGetAccount,
(QofSetterFunc)gncTaxTableEntrySetAccount),
gnc_sql_make_table_entry<CT_NUMERIC>("amount", 0, COL_NNUL,
(QofAccessFunc)gncTaxTableEntryGetAmount,
(QofSetterFunc)gncTaxTableEntrySetAmount),
gnc_sql_make_table_entry<CT_INT>("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 GncSqlColumnTableEntry guid_col_table[] =
static EntryVec guid_col_table
({
gnc_sql_make_table_entry<CT_GUID>("taxtable", 0, 0,
get_obj_guid, set_obj_guid),
});
class GncSqlTaxTableBackend : public GncSqlObjectBackend
{
{ "taxtable", CT_GUID, 0, 0, NULL, NULL, get_obj_guid, set_obj_guid },
{ NULL }
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
@ -204,12 +210,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);
@ -219,11 +224,9 @@ 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;
GncSqlStatement* stmt;
g_return_if_fail (be != NULL);
g_return_if_fail (tt != NULL);
@ -234,39 +237,27 @@ 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 = be->create_statement_from_sql (buf);
g_free (buf);
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);
}
auto result = be->execute_select_statement(stmt);
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);
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));
@ -297,89 +288,78 @@ 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;
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);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
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;
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;
}
}
}
}
/* ================================================================= */
static void
create_taxtable_tables (GncSqlBackend* be)
void
GncSqlTaxTableBackend::create_tables (GncSqlBackend* be)
{
gint version;
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)
{
/* 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->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);
}
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)
{
/* 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->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);
}
@ -425,8 +405,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;
@ -445,7 +425,7 @@ save_taxtable (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;
}
@ -485,92 +465,60 @@ 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<write_objects_t*>(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);
qof_object_foreach (GNC_ID_TAXTABLE, be->book(), save_next_taxtable, &data);
return data.is_ok;
}
/* ================================================================= */
static void
load_taxtable_guid (const GncSqlBackend* be, GncSqlRow* row,
QofSetterFunc setter, gpointer pObject,
const GncSqlColumnTableEntry* table_row)
template<> void
GncSqlColumnTableEntryImpl<CT_TAXTABLEREF>::load (const GncSqlBackend* be,
GncSqlRow& row,
QofIdTypeConst obj_name,
gpointer pObject) const noexcept
{
const GValue* val;
GncGUID guid;
GncTaxTable* taxtable = NULL;
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);
if (val != NULL && G_VALUE_HOLDS_STRING (val) &&
g_value_get_string (val) != NULL)
{
string_to_guid (g_value_get_string (val), &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);
}
}
else
{
PWARN ("Taxtable ref '%s' not found", g_value_get_string (val));
}
}
load_from_guid_ref(row, obj_name, pObject,
[be](GncGUID* g){
return gncTaxTableLookup(be->book(), g);
});
}
template<> void
GncSqlColumnTableEntryImpl<CT_TAXTABLEREF>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
add_objectref_guid_to_table(be, vec);
}
template<> void
GncSqlColumnTableEntryImpl<CT_TAXTABLEREF>::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_colname_to_list,
gnc_sql_add_gvalue_objectref_guid_to_slist
};
/* ================================================================= */
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 */
};
qof_object_register_backend (GNC_ID_TAXTABLE, GNC_SQL_BACKEND, &be_data);
gnc_sql_register_col_type_handler (CT_TAXTABLEREF, &taxtable_guid_handler);
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 ===================== */

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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"
@ -61,36 +60,49 @@ 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
({
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_STRING>("name", MAX_NAME_LEN, COL_NNUL, "name"),
gnc_sql_make_table_entry<CT_STRING>("id", MAX_ID_LEN, COL_NNUL, "id"),
gnc_sql_make_table_entry<CT_STRING>("notes", MAX_NOTES_LEN, COL_NNUL,
"notes"),
gnc_sql_make_table_entry<CT_COMMODITYREF>("currency", 0, COL_NNUL,
"currency"),
gnc_sql_make_table_entry<CT_BOOLEAN>("active", 0, COL_NNUL, "active"),
gnc_sql_make_table_entry<CT_BOOLEAN>("tax_override", 0, COL_NNUL,
"tax-table-override"),
gnc_sql_make_table_entry<CT_ADDRESS>("addr", 0, 0, "address"),
gnc_sql_make_table_entry<CT_BILLTERMREF>("terms", 0, 0, "terms"),
gnc_sql_make_table_entry<CT_STRING>("tax_inc", MAX_TAX_INC_LEN, 0,
"tax-included-string"),
gnc_sql_make_table_entry<CT_TAXTABLEREF>("tax_table", 0, 0, "tax-table"),
});
class GncSqlVendorBackend : public GncSqlObjectBackend
{
{ "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" },
{ NULL }
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)
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);
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));
@ -98,60 +110,31 @@ load_single_vendor (GncSqlBackend* be, GncSqlRow* row)
return pVendor;
}
static void
load_all_vendors (GncSqlBackend* be)
void
GncSqlVendorBackend::load_all (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);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
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;
for (auto row : *result)
{
GncSqlRow* row;
GList* list = NULL;
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);
}
GncVendor* pVendor = load_single_vendor (be, row);
if (pVendor != nullptr)
instances.push_back(QOF_INSTANCE(pVendor));
}
if (!instances.empty())
gnc_sql_slots_load_for_instancevec (be, instances);
}
/* ================================================================= */
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;
@ -170,7 +153,7 @@ save_vendor (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;
}
@ -227,28 +210,25 @@ 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<write_objects_t*>(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);
qof_object_foreach (GNC_ID_VENDOR, be->book(), write_single_vendor, &data);
return data.is_ok;
}
@ -257,17 +237,9 @@ 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};
qof_object_register_backend (GNC_ID_VENDOR, GNC_SQL_BACKEND, &be_data);
gnc_sql_register_backend(&be_data);
}
/* ========================== END OF FILE ===================== */

View File

@ -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)
{

View File

@ -32,6 +32,85 @@ 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<GncMockSqlStatement>(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}; }
int dberror() const noexcept override { return 0; }
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:
GncMockSqlResult m_result;
};
/* gnc_sql_init
void
@ -48,14 +127,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
@ -185,19 +256,12 @@ 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 =
@ -220,55 +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;
conn.beginTransaction = fake_connection_function;
conn.rollbackTransaction = fake_connection_function;
conn.commitTransaction = fake_connection_function;
auto book = qof_book_new();
GncSqlBackend be (&conn, book);
inst = static_cast<decltype (inst)> (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
@ -362,13 +422,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
@ -386,67 +439,23 @@ 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)
{
}*/
// 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 GncSqlColumnTableEntry* subtable,
GList** pList)// C: 1 */
/* static void
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,
const GncSqlColumnTableEntry* table_row)// 2
load_string (const GncSqlBackend* be, GncSqlRow& row,
const GncSqlColumnTableEntry& table_row)// 2
*/
/* static void
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
load_int (const GncSqlBackend* be, GncSqlRow& row,// 4
*/
/* static void
test_load_int (Fixture *fixture, gconstpointer pData)
@ -454,7 +463,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)
@ -470,7 +479,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)
@ -478,7 +487,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)
@ -494,7 +503,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)
@ -502,7 +511,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)
@ -518,7 +527,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)
@ -526,7 +535,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)
@ -542,7 +551,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)
@ -550,7 +559,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)
@ -565,12 +574,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
@ -582,44 +591,35 @@ 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, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, ERR_BACKEND_NO_ERR, nullptr, 0, nullptr, nullptr
},
nullptr, nullptr, FALSE, FALSE, FALSE, 0, 0, nullptr,
"%4d-%02d-%02d %02d:%02d:%02d"
};
const char* date[numtests] = {"1995-03-11 19:17:26",
GncSqlBackend be {nullptr, nullptr, "%4d-%02d-%02d %02d:%02d:%02d"};
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());
}
}
/* 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)
@ -627,23 +627,23 @@ 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)
{
}*/
/* 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
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)
@ -651,23 +651,23 @@ 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)
{
}*/
/* 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
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)
@ -675,30 +675,22 @@ 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)
{
}*/
/* add_numeric_colname_to_list
/* add_value_numeric_to_vec
static void
add_numeric_colname_to_list (const GncSqlColumnTableEntry* table_row, GList** pList)// 2
add_value_numeric_to_vec (const GncSqlBackend* be, QofIdTypeConst obj_name,// 2
*/
/* static void
test_add_numeric_colname_to_list (Fixture *fixture, gconstpointer pData)
{
}*/
/* add_gvalue_numeric_to_slist
static void
add_gvalue_numeric_to_slist (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
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)
{
@ -722,23 +714,14 @@ 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)
{
}*/
// 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 */
gnc_sql_load_object (const GncSqlBackend* be, GncSqlRow& row,// C: 29 in 19 */
/* static void
test_gnc_sql_load_object (Fixture *fixture, gconstpointer pData)
{
@ -790,13 +773,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 */
@ -811,14 +787,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 */
@ -826,14 +794,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
@ -858,13 +818,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
@ -873,13 +826,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
@ -896,13 +842,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 */
@ -938,14 +877,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)
@ -953,7 +884,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);
@ -981,45 +911,42 @@ 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);
// 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);
// 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_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 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);
@ -1036,23 +963,16 @@ 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);
// 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);
// 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);
}

View File

@ -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);
}

View File

@ -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 <qofbackend-p.h>
#include "gnc-xml-helper.h"
#include "io-gncxml-v2.h"
#include "io-gncxml.h"
#include "gnc-address-xml-v2.h"
@ -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;

View File

@ -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*

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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<GncXmlDataType_t> 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<decltype (data)> (data_p);
struct file_backend* be_data = static_cast<decltype (be_data)> (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<decltype (data)> (data_p);
struct file_backend* be_data = static_cast<decltype (be_data)> (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<decltype (data)> (data_p);
struct file_backend* be_data = static_cast<decltype (be_data)> (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<decltype (data)> (data_p);
struct file_backend* be_data = static_cast<decltype (be_data)> (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<decltype (data)> (data_p);
struct file_backend* be_data = static_cast<decltype (be_data)> (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<decltype (data)> (data_p);
struct file_backend* be_data = static_cast<decltype (be_data)> (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, "</%s>\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<decltype (data)> (data_p);
FILE* out = static_cast<decltype (out)> (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;

View File

@ -37,8 +37,11 @@ extern "C"
#include <glib.h>
#include "gnc-engine.h"
#ifdef __cplusplus
}
#include "gnc-backend-xml.h"
#include "sixtp.h"
#include <vector>
/**
@ -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__ */

View File

@ -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);

View File

@ -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
{

View File

@ -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

View File

@ -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

View File

@ -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<GHashTable*>(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<GHashTable*>(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<char*>(key);
struct foreach_data *cb_data = static_cast<struct foreach_data*>(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<GHashTable*>(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 =================== */

View File

@ -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

View File

@ -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<QofBook*>(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<QofBook*>(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);

View File

@ -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

View File

@ -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 );
}

View File

@ -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);

View File

@ -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;
}