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,20 +659,20 @@ 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))
for (auto name : drivers)
{
if (name == "sqlite3")
create_dbi_test_suite ("sqlite3", "sqlite3");
if (strlen (TEST_MYSQL_URL) > 0 &&
g_list_find_custom (drivers, "mysql", (GCompareFunc)g_strcmp0))
if (strlen (TEST_MYSQL_URL) > 0 && name == "mysql")
create_dbi_test_suite ("mysql", TEST_MYSQL_URL);
if (strlen (TEST_PGSQL_URL) > 0 &&
g_list_find_custom (drivers, "pgsql", (GCompareFunc)g_strcmp0))
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",
test_adjust_sql_options_string );

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,31 +222,19 @@ load_all_accounts (GncSqlBackend* be)
ENTER ("");
pBook = be->book;
pBook = be->book();
stmt = gnc_sql_create_select_statement (be, TABLE_NAME);
if (stmt == NULL)
{
LEAVE ("stmt == NULL");
return;
}
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;
while (row != 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);
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
sql = g_strdup_printf ("SELECT DISTINCT guid FROM %s", TABLE_NAME);
gnc_sql_slots_load_for_sql_subquery (be, sql, (BookLookupFn)xaccAccountLookup);
g_free (sql);
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
@ -252,7 +254,7 @@ load_all_accounts (GncSqlBackend* be)
for (elem = l_accounts_needing_parents; elem != NULL;)
{
account_parent_guid_struct* s = (account_parent_guid_struct*)elem->data;
pParent = xaccAccountLookup (&s->guid, be->book);
pParent = xaccAccountLookup (&s->guid, be->book());
if (pParent != NULL)
{
GList* next_elem;
@ -309,29 +311,13 @@ load_all_accounts (GncSqlBackend* be)
{
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)
{
gnc_sql_add_subtable_colnames_to_list (table_row, col_table, pList);
}
static void
get_gvalue_address (const GncSqlBackend* be, QofIdTypeConst obj_name,
/* 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,
const GncSqlColumnTableEntry* table_row, GValue* value)
PairVec& vec) const noexcept
{
AddressGetterFunc getter;
GncAddress* addr;
auto addr(get_row_value_from_object<char*>(obj_name, pObject));
if (addr == nullptr) return;
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,41 +232,29 @@ 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)
{
GncSqlRow* row;
GList* list = 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;
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
for (auto row : *result)
{
GncBillTerm* pBillTerm = load_single_billterm (be, row,
&l_billterms_needing_parents);
if (pBillTerm != NULL)
{
list = g_list_append (list, pBillTerm);
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_next_row (result);
}
gnc_sql_result_dispose (result);
if (list != NULL)
{
gnc_sql_slots_load_for_list (be, list);
g_list_free (list);
}
if (!instances.empty())
gnc_sql_slots_load_for_instancevec (be, instances);
/* While there are items on the list of billterms needing parents,
try to see if the parent has now been loaded. Theory says that if
@ -279,58 +280,45 @@ load_all_billterms (GncSqlBackend* be)
}
}
}
}
}
/* ================================================================= */
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)
{
GncSqlRow* row = gnc_sql_result_get_first_row (result);
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 == NULL)
if (row == result->end())
{
be->loading = FALSE;
(void)gnc_sql_save_book (be, QOF_INSTANCE (be->book));
be->loading = TRUE;
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);
}
gnc_sql_result_dispose (result);
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'",
auto 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 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);
auto result = be->execute_select_statement(stmt);
budget_amount_info_t info = { budget, NULL, 0 };
while (row != NULL)
{
for (auto row : *result)
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);
}
}
}
@ -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;
auto b = load_single_budget (be, row);
if (b != nullptr)
instances.push_back(QOF_INSTANCE(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);
}
}
}
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,
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
},
{ "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 }
(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,27 +140,20 @@ 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)
{
gnc_commodity* pCommodity;
GncSqlRow* row = gnc_sql_result_get_first_row (result);
gchar* sql;
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);
while (row != NULL)
for (auto row : *result)
{
pCommodity = load_single_commodity (be, row);
auto pCommodity = load_single_commodity (be, row);
if (pCommodity != NULL)
{
@ -158,31 +165,13 @@ load_all_commodities (GncSqlBackend* be)
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);
}
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)
{
GList* list = NULL;
GncSqlRow* row;
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
for (auto row : *result)
{
GncCustomer* pCustomer = load_single_customer (be, row);
if (pCustomer != NULL)
{
list = g_list_append (list, pCustomer);
if (pCustomer != nullptr)
instances.push_back(QOF_INSTANCE(pCustomer));
}
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
if (list != NULL)
{
gnc_sql_slots_load_for_list (be, list);
g_list_free (list);
}
}
if (!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)
{
GncSqlRow* row;
GList* list = 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);
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
InstanceVec instances;
for (auto row : *result)
{
GncEmployee* pEmployee = load_single_employee (be, row);
if (pEmployee != NULL)
{
list = g_list_append (list, pEmployee);
if (pEmployee != nullptr)
instances.push_back(QOF_INSTANCE(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);
}
}
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)
{
GncSqlRow* row;
GList* list = 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;
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
for (auto row : *result)
{
GncEntry* pEntry = load_single_entry (be, row);
if (pEntry != NULL)
{
list = g_list_append (list, pEntry);
if (pEntry != nullptr)
instances.push_back(QOF_INSTANCE(pEntry));
}
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
if (list != NULL)
{
gnc_sql_slots_load_for_list (be, list);
g_list_free (list);
}
}
if (!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)
{
GncSqlRow* row;
GList* list = 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;
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
for (auto row : *result)
{
GncInvoice* pInvoice = load_single_invoice (be, row);
if (pInvoice != NULL)
{
list = g_list_append (list, pInvoice);
if (pInvoice != nullptr)
instances.push_back(QOF_INSTANCE(pInvoice));
}
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
if (list != NULL)
{
gnc_sql_slots_load_for_list (be, list);
g_list_free (list);
}
}
if (!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)
{
GncSqlRow* row;
GList* list = 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;
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
for (auto row : *result)
{
GncJob* pJob = load_single_job (be, row);
if (pJob != NULL)
{
list = g_list_append (list, pJob);
if (pJob != nullptr)
instances.push_back(QOF_INSTANCE(pJob));
}
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);
}
}
}
/* ================================================================= */
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)
{
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;
while (row != NULL)
std::stringstream sql;
sql << "SELECT * FROM " << TABLE_NAME;
auto stmt = be->create_statement_from_sql(sql.str());
if (stmt != nullptr)
{
auto result = be->execute_select_statement(stmt);
if (result->begin () == nullptr)
return;
for (auto row : *result)
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);
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)
{
GncSqlRow* row;
GList* list = 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;
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
for (auto row : *result)
{
GncOrder* pOrder = load_single_order (be, row);
if (pOrder != NULL)
{
list = g_list_append (list, pOrder);
if (pOrder != nullptr)
instances.push_back(QOF_INSTANCE(pOrder));
}
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);
}
}
}
/* ================================================================= */
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)
}
if (inst == nullptr)
{
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);
/* 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;
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
{
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);
}
buf << "NULL";
vec.emplace_back(std::make_pair(guid_hdr, buf.str()));
}
static GncSqlColumnTypeHandler owner_handler
= { load_owner,
add_owner_col_info_to_list,
add_colname_to_list,
add_gvalue_owner_to_slist
};
/* ================================================================= */
void
gnc_owner_sql_initialize (void)
{
gnc_sql_register_col_type_handler (CT_OWNERREF, &owner_handler);
}
/* ========================== 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,31 +98,30 @@ 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)
{
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());
if (stmt != nullptr)
{
auto result = be->execute_select_statement(stmt);
if (result->begin() == result->end())
return;
GNCPrice* pPrice;
GncSqlRow* row = gnc_sql_result_get_first_row (result);
gchar* sql;
gnc_pricedb_set_bulk_update (pPriceDB, TRUE);
while (row != NULL)
for (auto row : *result)
{
pPrice = load_single_price (be, row);
@ -117,36 +130,33 @@ load_all_prices (GncSqlBackend* be)
(void)gnc_pricedb_add_price (pPriceDB, pPrice);
gnc_price_unref (pPrice);
}
row = gnc_sql_result_get_next_row (result);
}
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);
}
}
}
/* ================================================================= */
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");
g_warning ("No recurrences found");
return r;
}
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);
}
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)
{
GncSqlRow* row = gnc_sql_result_get_first_row (result);
while (row != NULL)
auto result = gnc_sql_set_recurrences_from_db (be, guid);
for (auto row : *result)
{
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);
}
return list;
@ -389,7 +377,7 @@ 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,
gboolean ok = be->add_columns_to_table(TABLE_NAME,
weekend_adjust_col_table);
if (!ok)
{
@ -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)
{
GncSqlRow* row;
auto result = be->execute_select_statement(stmt);
SchedXactions* sxes;
GList* list = NULL;
sxes = gnc_book_get_schedxactions (be->book);
InstanceVec instances;
sxes = gnc_book_get_schedxactions (be->book());
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
for (auto row : *result)
{
SchedXaction* sx;
sx = load_single_sx (be, row);
if (sx != NULL)
if (sx != nullptr)
{
gnc_sxes_add_sx (sxes, sx);
list = g_list_prepend (list, sx);
instances.push_back(QOF_INSTANCE(sx));
}
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
if (list != NULL)
{
gnc_sql_slots_load_for_list (be, list);
g_list_free (list);
}
}
if (!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)
{
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)
std::stringstream buf;
buf << "SELECT * FROM " << TABLE_NAME <<
" WHERE obj_guid='" << guid_buf << "'";
auto stmt = pInfo->be->create_statement_from_sql (buf.str());
if (stmt != nullptr)
{
auto result = pInfo->be->execute_select_statement (stmt);
for (auto row : *result)
load_slot (pInfo, row);
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
}
}
}
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)
{
auto result = be->execute_select_statement (stmt);
for (auto row : *result)
load_slot_for_list_item (be, row, coll);
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
}
}
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,48 +971,38 @@ 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)
{
auto result = be->execute_select_statement(stmt);
for (auto row : *result)
load_slot_for_book_object (be, row, lookup_fn);
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
}
}
/* ================================================================= */
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,
ok = be->create_index ("slots_guid_index", TABLE_NAME,
obj_guid_col_table);
if (!ok)
{
@ -1071,8 +1017,8 @@ 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,
be->upgrade_table(TABLE_NAME, col_table);
ok = be->create_index ("slots_guid_index", TABLE_NAME,
obj_guid_col_table);
if (!ok)
{
@ -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)
{
auto result = be->execute_select_statement(stmt);
for (auto row : *result)
load_single_ttentry (be, row, tt);
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
}
}
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,30 +288,20 @@ 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)
{
GncSqlRow* row;
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;
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
{
for (auto row : *result)
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
@ -344,42 +325,41 @@ load_all_taxtables (GncSqlBackend* be)
}
}
}
}
}
/* ================================================================= */
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 */

View File

@ -66,25 +66,28 @@ static QofLogModule log_module = G_LOG_DOMAIN;
#define SPLIT_TABLE "splits"
#define SPLIT_TABLE_VERSION 4
typedef struct
struct split_info_t : public write_objects_t
{
GncSqlBackend* be;
split_info_t () = default;
split_info_t (GncSqlBackend* be, bool o,
GncSqlObjectBackendPtr e, const GncGUID* g):
write_objects_t(be, o, e), guid{g} {}
const GncGUID* guid;
gboolean is_ok;
} split_info_t;
};
#define TX_MAX_NUM_LEN 2048
#define TX_MAX_DESCRIPTION_LEN 2048
static const GncSqlColumnTableEntry tx_col_table[] =
static const EntryVec tx_col_table
{
{ "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" },
{ "currency_guid", CT_COMMODITYREF, 0, COL_NNUL, "currency" },
{ "num", CT_STRING, TX_MAX_NUM_LEN, COL_NNUL, "num" },
{ "post_date", CT_TIMESPEC, 0, 0, "post-date" },
{ "enter_date", CT_TIMESPEC, 0, 0, "enter-date" },
{ "description", CT_STRING, TX_MAX_DESCRIPTION_LEN, 0, "description" },
{ NULL }
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_COMMODITYREF>("currency_guid", 0, COL_NNUL,
"currency"),
gnc_sql_make_table_entry<CT_STRING>("num", TX_MAX_NUM_LEN, COL_NNUL, "num"),
gnc_sql_make_table_entry<CT_TIMESPEC>("post_date", 0, 0, "post-date"),
gnc_sql_make_table_entry<CT_TIMESPEC>("enter_date", 0, 0, "enter-date"),
gnc_sql_make_table_entry<CT_STRING>("description", TX_MAX_DESCRIPTION_LEN,
0, "description"),
};
static gpointer get_split_reconcile_state (gpointer pObject);
@ -94,45 +97,74 @@ static void set_split_lot (gpointer pObject, gpointer pLot);
#define SPLIT_MAX_MEMO_LEN 2048
#define SPLIT_MAX_ACTION_LEN 2048
static const GncSqlColumnTableEntry split_col_table[] =
static const EntryVec split_col_table
{
{ "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" },
{ "tx_guid", CT_TXREF, 0, COL_NNUL, "transaction" },
{ "account_guid", CT_ACCOUNTREF, 0, COL_NNUL, "account" },
{ "memo", CT_STRING, SPLIT_MAX_MEMO_LEN, COL_NNUL, "memo" },
{ "action", CT_STRING, SPLIT_MAX_ACTION_LEN, COL_NNUL, "action" },
{
"reconcile_state", CT_STRING, 1, COL_NNUL, NULL, NULL,
(QofAccessFunc)get_split_reconcile_state, set_split_reconcile_state
},
{ "reconcile_date", CT_TIMESPEC, 0, 0, "reconcile-date" },
{ "value", CT_NUMERIC, 0, COL_NNUL, "value" },
{ "quantity", CT_NUMERIC, 0, COL_NNUL, "amount" },
{
"lot_guid", CT_LOTREF, 0, 0, NULL, NULL,
(QofAccessFunc)xaccSplitGetLot, set_split_lot
},
{ NULL }
gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
gnc_sql_make_table_entry<CT_TXREF>("tx_guid", 0, COL_NNUL, "transaction"),
gnc_sql_make_table_entry<CT_ACCOUNTREF>("account_guid", 0, COL_NNUL,
"account"),
gnc_sql_make_table_entry<CT_STRING>("memo", SPLIT_MAX_MEMO_LEN, COL_NNUL,
"memo"),
gnc_sql_make_table_entry<CT_STRING>("action", SPLIT_MAX_ACTION_LEN,
COL_NNUL, "action"),
gnc_sql_make_table_entry<CT_STRING>("reconcile_state", 1, COL_NNUL,
(QofAccessFunc)get_split_reconcile_state,
set_split_reconcile_state),
gnc_sql_make_table_entry<CT_TIMESPEC>("reconcile_date", 0, 0,
"reconcile-date"),
gnc_sql_make_table_entry<CT_NUMERIC>("value", 0, COL_NNUL, "value"),
gnc_sql_make_table_entry<CT_NUMERIC>("quantity", 0, COL_NNUL, "amount"),
gnc_sql_make_table_entry<CT_LOTREF>("lot_guid", 0, 0,
(QofAccessFunc)xaccSplitGetLot,
set_split_lot),
};
static const GncSqlColumnTableEntry post_date_col_table[] =
static const EntryVec post_date_col_table
{
{ "post_date", CT_TIMESPEC, 0, 0, "post-date" },
{ NULL }
gnc_sql_make_table_entry<CT_TIMESPEC>("post_date", 0, 0, "post-date"),
};
static const GncSqlColumnTableEntry account_guid_col_table[] =
static const EntryVec account_guid_col_table
{
{ "account_guid", CT_ACCOUNTREF, 0, COL_NNUL, "account" },
{ NULL }
gnc_sql_make_table_entry<CT_ACCOUNTREF>("account_guid", 0, COL_NNUL,
"account"),
};
static const GncSqlColumnTableEntry tx_guid_col_table[] =
static const EntryVec tx_guid_col_table
{
{ "tx_guid", CT_GUID, 0, 0, "guid" },
{ NULL }
gnc_sql_make_table_entry<CT_GUID>("tx_guid", 0, 0, "guid"),
};
class GncSqlTransBackend : public GncSqlObjectBackend
{
public:
GncSqlTransBackend(int version, const std::string& type,
const std::string& table, const EntryVec& vec) :
GncSqlObjectBackend(version, type, table, vec) {}
void load_all(GncSqlBackend*) override;
void create_tables(GncSqlBackend*) override;
bool commit (GncSqlBackend* be, QofInstance* inst) override;
};
class GncSqlSplitBackend : public GncSqlObjectBackend
{
public:
GncSqlSplitBackend(int version, const std::string& type,
const std::string& table, const EntryVec& vec) :
GncSqlObjectBackend(version, type, table, vec) {}
void load_all(GncSqlBackend*) override { return; } // loaded by transaction.
void create_tables(GncSqlBackend*) override;
bool commit (GncSqlBackend* be, QofInstance* inst) override;
};
static GncSqlSplitBackend be_data_split {
GNC_SQL_BACKEND_VERSION, GNC_ID_SPLIT, SPLIT_TABLE, split_col_table};
/* These functions exist but have not been tested.
#if LOAD_TRANSACTIONS_AS_NEEDED
compile_split_query,
run_split_query,
free_split_query,
*/
/* ================================================================= */
static gpointer
@ -179,7 +211,7 @@ set_split_lot (gpointer pObject, gpointer pLot)
}
static Split*
load_single_split (GncSqlBackend* be, GncSqlRow* row)
load_single_split (GncSqlBackend* be, GncSqlRow& row)
{
const GncGUID* guid;
GncGUID split_guid;
@ -187,7 +219,6 @@ load_single_split (GncSqlBackend* be, GncSqlRow* row)
gboolean bad_guid = FALSE;
g_return_val_if_fail (be != NULL, NULL);
g_return_val_if_fail (row != NULL, NULL);
guid = gnc_sql_load_guid (be, row);
if (guid == NULL) return NULL;
@ -200,12 +231,12 @@ load_single_split (GncSqlBackend* be, GncSqlRow* row)
else
{
split_guid = *guid;
pSplit = xaccSplitLookup (&split_guid, be->book);
pSplit = xaccSplitLookup (&split_guid, be->book());
}
if (pSplit == NULL)
{
pSplit = xaccMallocSplit (be->book);
pSplit = xaccMallocSplit (be->book());
}
/* If the split is dirty, don't overwrite it */
@ -215,95 +246,75 @@ load_single_split (GncSqlBackend* be, GncSqlRow* row)
}
/*# -ifempty */
if (pSplit != xaccSplitLookup (&split_guid, be->book))
if (pSplit != xaccSplitLookup (&split_guid, be->book()))
{
gchar guidstr[GUID_ENCODING_LENGTH + 1];
guid_to_string_buff (qof_instance_get_guid (pSplit), guidstr);
PERR ("A malformed split with id %s was found in the dataset.", guidstr);
qof_backend_set_error (&be->be, ERR_BACKEND_DATA_CORRUPT);
qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_DATA_CORRUPT);
pSplit = NULL;
}
return pSplit;
}
static void
load_splits_for_tx_list (GncSqlBackend* be, GList* list)
load_splits_for_tx_list (GncSqlBackend* be, InstanceVec& transactions)
{
GString* sql;
GncSqlResult* result;
g_return_if_fail (be != NULL);
if (list == NULL) return;
std::stringstream sql;
sql = g_string_sized_new (40 + (GUID_ENCODING_LENGTH + 3) * g_list_length (
list));
g_string_append_printf (sql, "SELECT * FROM %s WHERE %s IN (", SPLIT_TABLE,
tx_guid_col_table[0].col_name);
(void)gnc_sql_append_guid_list_to_sql (sql, list, G_MAXUINT);
(void)g_string_append (sql, ")");
sql << "SELECT * FROM " << SPLIT_TABLE << " WHERE " <<
tx_guid_col_table[0]->name() << " IN (";
gnc_sql_append_guids_to_sql (sql, transactions);
sql << ")";
// Execute the query and load the splits
result = gnc_sql_execute_select_sql (be, sql->str);
if (result != NULL)
{
GList* split_list = NULL;
GncSqlRow* row;
auto stmt = be->create_statement_from_sql(sql.str());
auto result = be->execute_select_statement (stmt);
InstanceVec instances;
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
for (auto row : *result)
{
Split* s;
s = load_single_split (be, row);
if (s != NULL)
{
split_list = g_list_prepend (split_list, s);
}
row = gnc_sql_result_get_next_row (result);
Split* s = load_single_split (be, row);
if (s != nullptr)
instances.push_back(QOF_INSTANCE(s));
}
if (split_list != NULL)
{
gnc_sql_slots_load_for_list (be, split_list);
g_list_free (split_list);
}
gnc_sql_result_dispose (result);
}
(void)g_string_free (sql, TRUE);
if (!instances.empty())
gnc_sql_slots_load_for_instancevec (be, instances);
}
static Transaction*
load_single_tx (GncSqlBackend* be, GncSqlRow* row)
load_single_tx (GncSqlBackend* be, GncSqlRow& row)
{
const GncGUID* guid;
GncGUID tx_guid;
Transaction* pTx;
g_return_val_if_fail (be != NULL, NULL);
g_return_val_if_fail (row != NULL, NULL);
guid = gnc_sql_load_guid (be, row);
if (guid == NULL) return NULL;
tx_guid = *guid;
// Don't overwrite the transaction if it's already been loaded (and possibly modified).
pTx = xaccTransLookup (&tx_guid, be->book);
pTx = xaccTransLookup (&tx_guid, be->book());
if (pTx != NULL)
{
return NULL;
}
pTx = xaccMallocTransaction (be->book);
pTx = xaccMallocTransaction (be->book());
xaccTransBeginEdit (pTx);
gnc_sql_load_object (be, row, GNC_ID_TRANS, pTx, tx_col_table);
if (pTx != xaccTransLookup (&tx_guid, be->book))
if (pTx != xaccTransLookup (&tx_guid, be->book()))
{
gchar guidstr[GUID_ENCODING_LENGTH + 1];
guid_to_string_buff (qof_instance_get_guid (pTx), guidstr);
PERR ("A malformed transaction with id %s was found in the dataset.", guidstr);
qof_backend_set_error (&be->be, ERR_BACKEND_DATA_CORRUPT);
qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_DATA_CORRUPT);
pTx = NULL;
}
@ -335,24 +346,21 @@ typedef struct
* @param stmt SQL statement
*/
static void
query_transactions (GncSqlBackend* be, GncSqlStatement* stmt)
query_transactions (GncSqlBackend* be, const GncSqlStatementPtr& stmt)
{
GncSqlResult* result;
g_return_if_fail (be != NULL);
g_return_if_fail (stmt != NULL);
result = gnc_sql_execute_select_statement (be, stmt);
if (result != NULL)
{
GList* tx_list = NULL;
auto result = be->execute_select_statement(stmt);
if (result->begin() == result->end())
return;
GList* node;
GncSqlRow* row;
Transaction* tx;
#if LOAD_TRANSACTIONS_AS_NEEDED
GSList* bal_list = NULL;
GSList* nextbal;
Account* root = gnc_book_get_root_account (be->book);
Account* root = gnc_book_get_root_account (be->book());
qof_event_suspend ();
xaccAccountBeginEdit (root);
@ -365,33 +373,27 @@ query_transactions (GncSqlBackend* be, GncSqlStatement* stmt)
#endif
// Load the transactions
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
InstanceVec instances;
for (auto row : *result)
{
tx = load_single_tx (be, row);
if (tx != NULL)
if (tx != nullptr)
{
tx_list = g_list_prepend (tx_list, tx);
xaccTransScrubPostedDate (tx);
instances.push_back(QOF_INSTANCE(tx));
}
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
// Load all splits and slots for the transactions
if (tx_list != NULL)
if (!instances.empty())
{
gnc_sql_slots_load_for_list (be, tx_list);
load_splits_for_tx_list (be, tx_list);
gnc_sql_slots_load_for_instancevec (be, instances);
load_splits_for_tx_list (be, instances);
}
// Commit all of the transactions
for (node = tx_list; node != NULL; node = node->next)
{
Transaction* pTx = GNC_TRANSACTION (node->data);
xaccTransCommitEdit (pTx);
}
g_list_free (tx_list);
for (auto instance : instances)
xaccTransCommitEdit(GNC_TRANSACTION(instance));
#if LOAD_TRANSACTIONS_AS_NEEDED
// Update the account balances based on the loaded splits. If the end
@ -456,7 +458,6 @@ query_transactions (GncSqlBackend* be, GncSqlStatement* stmt)
xaccAccountCommitEdit (root);
qof_event_resume ();
#endif
}
}
/* ================================================================= */
@ -465,78 +466,74 @@ query_transactions (GncSqlBackend* be, GncSqlStatement* stmt)
*
* @param be SQL backend
*/
static void
create_transaction_tables (GncSqlBackend* be)
void
GncSqlTransBackend::create_tables (GncSqlBackend* be)
{
gint version;
gboolean ok;
g_return_if_fail (be != NULL);
version = gnc_sql_get_table_version (be, TRANSACTION_TABLE);
version = be->get_table_version( m_table_name.c_str());
if (version == 0)
{
(void)gnc_sql_create_table (be, TRANSACTION_TABLE, TX_TABLE_VERSION,
(void)be->create_table(TRANSACTION_TABLE, TX_TABLE_VERSION,
tx_col_table);
ok = gnc_sql_create_index (be, "tx_post_date_index", TRANSACTION_TABLE,
ok = be->create_index ("tx_post_date_index", TRANSACTION_TABLE,
post_date_col_table);
if (!ok)
{
PERR ("Unable to create index\n");
}
}
else if (version < TX_TABLE_VERSION)
else if (version < m_version)
{
/* Upgrade:
1->2: 64 bit int handling
2->3: allow dates to be NULL
*/
gnc_sql_upgrade_table (be, TRANSACTION_TABLE, tx_col_table);
(void)gnc_sql_set_table_version (be, TRANSACTION_TABLE, TX_TABLE_VERSION);
PINFO ("Transactions table upgraded from version %d to version %d\n", version,
TX_TABLE_VERSION);
be->upgrade_table(m_table_name.c_str(), tx_col_table);
be->set_table_version (m_table_name.c_str(), m_version);
PINFO ("Transactions table upgraded from version %d to version %d\n",
version, m_version);
}
}
void
GncSqlSplitBackend::create_tables (GncSqlBackend* be)
{
g_return_if_fail (be != nullptr);
version = gnc_sql_get_table_version (be, SPLIT_TABLE);
auto version = be->get_table_version( m_table_name.c_str());
if (version == 0)
{
(void)gnc_sql_create_table (be, SPLIT_TABLE, SPLIT_TABLE_VERSION,
split_col_table);
ok = gnc_sql_create_index (be, "splits_tx_guid_index", SPLIT_TABLE,
tx_guid_col_table);
if (!ok)
{
(void)be->create_table(m_table_name.c_str(),
m_version, m_col_table);
if (!be->create_index("splits_tx_guid_index",
m_table_name.c_str(), tx_guid_col_table))
PERR ("Unable to create index\n");
}
ok = gnc_sql_create_index (be, "splits_account_guid_index", SPLIT_TABLE,
account_guid_col_table);
if (!ok)
{
if (!be->create_index("splits_account_guid_index",
m_table_name.c_str(),
account_guid_col_table))
PERR ("Unable to create index\n");
}
}
else if (version < SPLIT_TABLE_VERSION)
{
/* Upgrade:
1->2: 64 bit int handling
3->4: Split reconcile date can be NULL */
gnc_sql_upgrade_table (be, SPLIT_TABLE, split_col_table);
ok = gnc_sql_create_index (be, "splits_tx_guid_index", SPLIT_TABLE,
tx_guid_col_table);
if (!ok)
{
be->upgrade_table(m_table_name.c_str(), split_col_table);
if (!be->create_index("splits_tx_guid_index",
m_table_name.c_str(),
tx_guid_col_table))
PERR ("Unable to create index\n");
}
ok = gnc_sql_create_index (be, "splits_account_guid_index", SPLIT_TABLE,
account_guid_col_table);
if (!ok)
{
if (!be->create_index("splits_account_guid_index",
m_table_name.c_str(),
account_guid_col_table))
PERR ("Unable to create index\n");
}
(void)gnc_sql_set_table_version (be, SPLIT_TABLE, SPLIT_TABLE_VERSION);
be->set_table_version (m_table_name.c_str(), m_version);
PINFO ("Splits table upgraded from version %d to version %d\n", version,
SPLIT_TABLE_VERSION);
m_version);
}
}
/* ================================================================= */
@ -599,8 +596,8 @@ delete_splits (GncSqlBackend* be, Transaction* pTx)
* @param inst Split
* @return TRUE if successful, FALSE if error
*/
static gboolean
commit_split (GncSqlBackend* be, QofInstance* inst)
bool
GncSqlSplitBackend::commit (GncSqlBackend* be, QofInstance* inst)
{
E_DB_OPERATION op;
gboolean is_infant;
@ -615,7 +612,7 @@ commit_split (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;
}
@ -641,59 +638,24 @@ commit_split (GncSqlBackend* be, QofInstance* inst)
return is_ok;
}
static void
save_split_cb (gpointer data, gpointer user_data)
bool
GncSqlTransBackend::commit (GncSqlBackend* be, QofInstance* inst)
{
split_info_t* split_info = (split_info_t*)user_data;
Split* pSplit = GNC_SPLIT (data);
g_return_if_fail (data != NULL);
g_return_if_fail (GNC_IS_SPLIT (data));
g_return_if_fail (user_data != NULL);
if (split_info->is_ok)
{
split_info->is_ok = commit_split (split_info->be, QOF_INSTANCE (pSplit));
}
}
static gboolean
save_splits (GncSqlBackend* be, const GncGUID* tx_guid, SplitList* pSplitList)
{
split_info_t split_info;
g_return_val_if_fail (be != NULL, FALSE);
g_return_val_if_fail (tx_guid != NULL, FALSE);
g_return_val_if_fail (pSplitList != NULL, FALSE);
split_info.be = be;
split_info.guid = tx_guid;
split_info.is_ok = TRUE;
g_list_foreach (pSplitList, save_split_cb, &split_info);
return split_info.is_ok;
}
static gboolean
save_transaction (GncSqlBackend* be, Transaction* pTx, gboolean do_save_splits)
{
const GncGUID* guid;
E_DB_OPERATION op;
gboolean is_infant;
QofInstance* inst;
gboolean is_ok = TRUE;
const char* err = NULL;
g_return_val_if_fail (be != NULL, FALSE);
g_return_val_if_fail (pTx != NULL, FALSE);
g_return_val_if_fail (inst != NULL, FALSE);
inst = QOF_INSTANCE (pTx);
is_infant = qof_instance_get_infant (inst);
auto pTx = GNC_TRANS(inst);
auto is_infant = qof_instance_get_infant (inst);
if (qof_instance_get_destroying (inst))
{
op = OP_DB_DELETE;
}
else if (be->is_pristine_db || is_infant)
else if (be->pristine() || is_infant)
{
op = OP_DB_INSERT;
}
@ -710,7 +672,7 @@ save_transaction (GncSqlBackend* be, Transaction* pTx, gboolean do_save_splits)
if (! is_ok)
{
err = "Commodity save failed: Probably an invalid or missing currency";
qof_backend_set_error (&be->be, ERR_BACKEND_DATA_CORRUPT);
qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_DATA_CORRUPT);
}
}
@ -726,8 +688,8 @@ save_transaction (GncSqlBackend* be, Transaction* pTx, gboolean do_save_splits)
if (is_ok)
{
// Commit slots and splits
guid = qof_instance_get_guid (inst);
// Commit slots
auto guid = qof_instance_get_guid (inst);
if (!qof_instance_get_destroying (inst))
{
is_ok = gnc_sql_slots_save (be, guid, is_infant, inst);
@ -735,14 +697,6 @@ save_transaction (GncSqlBackend* be, Transaction* pTx, gboolean do_save_splits)
{
err = "Slots save failed. Check trace log for SQL errors";
}
if (is_ok && do_save_splits)
{
is_ok = save_splits (be, guid, xaccTransGetSplitList (pTx));
if (! is_ok)
{
err = "Split save failed. Check trace log for SQL errors";
}
}
}
else
{
@ -785,26 +739,6 @@ save_transaction (GncSqlBackend* be, Transaction* pTx, gboolean do_save_splits)
return is_ok;
}
gboolean
gnc_sql_save_transaction (GncSqlBackend* be, QofInstance* inst)
{
g_return_val_if_fail (be != NULL, FALSE);
g_return_val_if_fail (inst != NULL, FALSE);
g_return_val_if_fail (GNC_IS_TRANS (inst), FALSE);
return save_transaction (be, GNC_TRANS (inst), /* do_save_splits */TRUE);
}
static gboolean
commit_transaction (GncSqlBackend* be, QofInstance* inst)
{
g_return_val_if_fail (be != NULL, FALSE);
g_return_val_if_fail (inst != NULL, FALSE);
g_return_val_if_fail (GNC_IS_TRANS (inst), FALSE);
return save_transaction (be, GNC_TRANS (inst), /* do_save_splits */FALSE);
}
/* ================================================================= */
/**
* Loads all transactions for an account.
@ -818,7 +752,6 @@ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* be,
const GncGUID* guid;
gchar guid_buf[GUID_ENCODING_LENGTH + 1];
gchar* query_sql;
GncSqlStatement* stmt;
g_return_if_fail (be != NULL);
g_return_if_fail (account != NULL);
@ -828,12 +761,11 @@ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* be,
query_sql = g_strdup_printf (
"SELECT DISTINCT t.* FROM %s AS t, %s AS s WHERE s.tx_guid=t.guid AND s.account_guid ='%s'",
TRANSACTION_TABLE, SPLIT_TABLE, guid_buf);
stmt = gnc_sql_create_statement_from_sql (be, query_sql);
auto stmt = be->create_statement_from_sql(query_sql);
g_free (query_sql);
if (stmt != NULL)
if (stmt != nullptr)
{
query_transactions (be, stmt);
gnc_sql_statement_dispose (stmt);
}
}
@ -843,20 +775,17 @@ void gnc_sql_transaction_load_tx_for_account (GncSqlBackend* be,
*
* @param be SQL backend
*/
void gnc_sql_transaction_load_all_tx (GncSqlBackend* be)
void
GncSqlTransBackend::load_all (GncSqlBackend* be)
{
gchar* query_sql;
GncSqlStatement* stmt;
g_return_if_fail (be != NULL);
query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE);
stmt = gnc_sql_create_statement_from_sql (be, query_sql);
auto query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE);
auto stmt = be->create_statement_from_sql(query_sql);
g_free (query_sql);
if (stmt != NULL)
if (stmt != nullptr)
{
query_transactions (be, stmt);
gnc_sql_statement_dispose (stmt);
}
}
@ -1040,10 +969,9 @@ convert_query_term_to_sql (const GncSqlBackend* be, const gchar* fieldName,
else if (g_strcmp0 (pPredData->type_name, QOF_TYPE_DATE) == 0)
{
query_date_t date_data = (query_date_t)pPredData;
gchar* datebuf;
datebuf = gnc_sql_convert_timespec_to_string (be, date_data->date);
g_string_append_printf (sql, "'%s'", datebuf);
auto datebuf = be->time64_to_string (date_data->date.tv_sec);
g_string_append_printf (sql, "'%s'", datebuf.c_str());
}
else if (strcmp (pPredData->type_name, QOF_TYPE_INT32) == 0)
@ -1085,7 +1013,7 @@ convert_query_term_to_sql (const GncSqlBackend* be, const gchar* fieldName,
typedef struct
{
GncSqlStatement* stmt;
GncSqlStatementPtr stmt;
gboolean has_been_run;
} split_query_info_t;
@ -1237,7 +1165,7 @@ done_compiling_query:
{
query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE);
}
query_info->stmt = gnc_sql_create_statement_from_sql (be, query_sql);
query_info->stmt = be->create_statement_from_sql(query_sql);
g_string_free (sql, TRUE);
g_free (query_sql);
@ -1246,7 +1174,7 @@ done_compiling_query:
else
{
query_sql = g_strdup_printf ("SELECT * FROM %s", TRANSACTION_TABLE);
query_info->stmt = gnc_sql_create_statement_from_sql (be, query_sql);
query_info->stmt = be->create_statement_from_sql(query_sql);
g_free (query_sql);
}
@ -1265,8 +1193,7 @@ run_split_query (GncSqlBackend* be, gpointer pQuery)
{
query_transactions (be, query_info->stmt);
query_info->has_been_run = TRUE;
gnc_sql_statement_dispose (query_info->stmt);
query_info->stmt = NULL;
query_info->stmt = nullptr;
}
}
@ -1297,7 +1224,7 @@ set_acct_bal_account_from_guid (gpointer pObject, gpointer pValue)
g_return_if_fail (pObject != NULL);
g_return_if_fail (pValue != NULL);
bal->acct = xaccAccountLookup (guid, bal->be->book);
bal->acct = xaccAccountLookup (guid, bal->be->book());
}
static void
@ -1322,21 +1249,22 @@ set_acct_bal_balance (gpointer pObject, gnc_numeric value)
bal->balance = value;
}
static const GncSqlColumnTableEntry acct_balances_col_table[] =
static const EntryVec acct_balances_col_table
{
{ "account_guid", CT_GUID, 0, 0, NULL, NULL, NULL, (QofSetterFunc)set_acct_bal_account_from_guid },
{ "reconcile_state", CT_STRING, 1, 0, NULL, NULL, NULL, (QofSetterFunc)set_acct_bal_reconcile_state },
{ "quantity", CT_NUMERIC, 0, 0, NULL, NULL, NULL, (QofSetterFunc)set_acct_bal_balance },
{ NULL }
gnc_sql_make_table_entry<CT_GUID>("account_guid", 0, 0, nullptr,
(QofSetterFunc)set_acct_bal_account_from_guid),
gnc_sql_make_table_entry<CT_STRING>("reconcile_state", 1, 0, nullptr,
(QofSetterFunc)set_acct_bal_reconcile_state),
gnc_sql_make_table_entry<CT_NUMERIC>("quantity", 0, 0, nullptr,
(QofSetterFunc)set_acct_bal_balance),
};
G_GNUC_UNUSED static single_acct_balance_t*
load_single_acct_balances (const GncSqlBackend* be, GncSqlRow* row)
load_single_acct_balances (const GncSqlBackend* be, GncSqlRow& row)
{
single_acct_balance_t* bal = NULL;
g_return_val_if_fail (be != NULL, NULL);
g_return_val_if_fail (row != NULL, NULL);
bal = static_cast<decltype (bal)> (g_malloc (sizeof (single_acct_balance_t)));
g_assert (bal != NULL);
@ -1351,8 +1279,6 @@ GSList*
gnc_sql_get_account_balances_slist (GncSqlBackend* be)
{
#if LOAD_TRANSACTIONS_AS_NEEDED
GncSqlResult* result;
GncSqlStatement* stmt;
gchar* buf;
GSList* bal_slist = NULL;
@ -1360,18 +1286,13 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be)
buf = g_strdup_printf ("SELECT account_guid, reconcile_state, sum(quantity_num) as quantity_num, quantity_denom FROM %s GROUP BY account_guid, reconcile_state, quantity_denom ORDER BY account_guid, reconcile_state",
SPLIT_TABLE);
stmt = gnc_sql_create_statement_from_sql (be, buf);
g_assert (stmt != NULL);
auto stmt = be->create_statement_from_sql(buf);
g_assert (stmt != nullptr);
g_free (buf);
result = gnc_sql_execute_select_statement (be, stmt);
gnc_sql_statement_dispose (stmt);
if (result != NULL)
{
GncSqlRow* row;
auto result = be->execute_select_statement(stmt);
acct_balances_t* bal = NULL;
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
for (auto row : *result)
{
single_acct_balance_t* single_bal;
@ -1418,7 +1339,6 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be)
}
g_free (single_bal);
}
row = gnc_sql_result_get_next_row (result);
}
// Add the final balance
@ -1431,8 +1351,6 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be)
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
bal_slist = g_slist_append (bal_slist, bal);
}
gnc_sql_result_dispose (result);
}
return bal_slist;
#else
@ -1441,110 +1359,64 @@ gnc_sql_get_account_balances_slist (GncSqlBackend* be)
}
/* ----------------------------------------------------------------- */
static void
load_tx_guid (const GncSqlBackend* be, GncSqlRow* row,
QofSetterFunc setter, gpointer pObject,
const GncSqlColumnTableEntry* table_row)
template<> void
GncSqlColumnTableEntryImpl<CT_TXREF>::load (const GncSqlBackend* be,
GncSqlRow& row,
QofIdTypeConst obj_name,
gpointer pObject) const noexcept
{
const GValue* val;
GncGUID guid;
Transaction* tx;
const gchar* guid_str;
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);
g_assert (val != NULL);
guid_str = g_value_get_string (val);
if (guid_str != NULL)
try
{
(void)string_to_guid (guid_str, &guid);
tx = xaccTransLookup (&guid, be->book);
auto val = row.get_string_at_col (m_col_name);
GncGUID guid;
(void)string_to_guid (val.c_str(), &guid);
auto tx = xaccTransLookup (&guid, be->book());
// If the transaction is not found, try loading it
if (tx == NULL)
if (tx == nullptr)
{
gchar* buf;
GncSqlStatement* stmt;
buf = g_strdup_printf ("SELECT * FROM %s WHERE guid='%s'",
TRANSACTION_TABLE, guid_str);
stmt = gnc_sql_create_statement_from_sql ((GncSqlBackend*)be, buf);
g_free (buf);
auto buf = std::string{"SELECT * FROM "} + TRANSACTION_TABLE +
" WHERE guid='" + val + "'";
auto stmt = be->create_statement_from_sql (buf);
query_transactions ((GncSqlBackend*)be, stmt);
tx = xaccTransLookup (&guid, be->book);
tx = xaccTransLookup (&guid, be->book());
}
if (tx != NULL)
{
if (table_row->gobj_param_name != NULL)
{
qof_instance_increase_editlevel (pObject);
g_object_set (pObject, table_row->gobj_param_name, tx, NULL);
qof_instance_decrease_editlevel (pObject);
}
else
{
g_return_if_fail (setter != NULL);
(*setter) (pObject, (const gpointer)tx);
}
}
if (tx != nullptr)
set_parameter (pObject, tx, get_setter(obj_name), m_gobj_param_name);
}
catch (std::invalid_argument) {}
}
template<> void
GncSqlColumnTableEntryImpl<CT_TXREF>::add_to_table(const GncSqlBackend* be,
ColVec& vec) const noexcept
{
add_objectref_guid_to_table(be, vec);
}
template<> void
GncSqlColumnTableEntryImpl<CT_TXREF>::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 tx_guid_handler
= { load_tx_guid,
gnc_sql_add_objectref_guid_col_info_to_list,
gnc_sql_add_colname_to_list,
gnc_sql_add_gvalue_objectref_guid_to_slist
};
/* ================================================================= */
void
gnc_sql_init_transaction_handler (void)
{
static GncSqlObjectBackend be_data_tx =
{
GNC_SQL_BACKEND_VERSION,
GNC_ID_TRANS,
commit_transaction, /* commit */
#if LOAD_TRANSACTIONS_AS_NEEDED
NULL, /* initial load */
#else
gnc_sql_transaction_load_all_tx,
#endif
create_transaction_tables, /* create tables */
NULL, /* compile_query */
NULL, /* run_query */
NULL, /* free_query */
NULL /* write */
};
static GncSqlObjectBackend be_data_split =
{
GNC_SQL_BACKEND_VERSION,
GNC_ID_SPLIT,
commit_split, /* commit */
NULL, /* initial_load */
NULL, /* create tables */
#if LOAD_TRANSACTIONS_AS_NEEDED
compile_split_query,
run_split_query,
free_split_query,
#else
NULL, /* compile_query */
NULL, /* run_query */
NULL, /* free_query */
#endif
NULL /* write */
};
(void)qof_object_register_backend (GNC_ID_TRANS, GNC_SQL_BACKEND, &be_data_tx);
(void)qof_object_register_backend (GNC_ID_SPLIT, GNC_SQL_BACKEND,
&be_data_split);
gnc_sql_register_col_type_handler (CT_TXREF, &tx_guid_handler);
static GncSqlTransBackend be_data_tx {
GNC_SQL_BACKEND_VERSION, GNC_ID_TRANS, TRANSACTION_TABLE, tx_col_table};
gnc_sql_register_backend(&be_data_tx);
gnc_sql_register_backend(&be_data_split);
}
/* ========================== END OF FILE ===================== */

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)
{
GncSqlRow* row;
GList* list = 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;
row = gnc_sql_result_get_first_row (result);
while (row != NULL)
for (auto row : *result)
{
GncVendor* pVendor = load_single_vendor (be, row);
if (pVendor != NULL)
{
list = g_list_append (list, pVendor);
if (pVendor != nullptr)
instances.push_back(QOF_INSTANCE(pVendor));
}
row = gnc_sql_result_get_next_row (result);
}
gnc_sql_result_dispose (result);
if (list != NULL)
{
gnc_sql_slots_load_for_list (be, list);
g_list_free (list);
}
}
if (!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 (
if (data.create_parser)
if (!sixtp_add_some_sub_parsers(
be_data->parser, TRUE,
data->type_name, (data->create_parser) (),
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;
}