mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Interim merge of c++-backend to expose C++ interface.
This commit is contained in:
commit
472b585feb
@ -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
|
||||
|
@ -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 = \
|
||||
|
@ -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
@ -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_ */
|
||||
|
117
src/backend/dbi/gnc-backend-dbi.hpp
Normal file
117
src/backend/dbi/gnc-backend-dbi.hpp
Normal 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
|
54
src/backend/dbi/gnc-dbiprovider.hpp
Normal file
54
src/backend/dbi/gnc-dbiprovider.hpp
Normal 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__
|
371
src/backend/dbi/gnc-dbiproviderimpl.hpp
Normal file
371
src/backend/dbi/gnc-dbiproviderimpl.hpp
Normal 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__
|
709
src/backend/dbi/gnc-dbisqlconnection.cpp
Normal file
709
src/backend/dbi/gnc-dbisqlconnection.cpp
Normal 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(),
|
||||
"ed_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;
|
||||
}
|
111
src/backend/dbi/gnc-dbisqlconnection.hpp
Normal file
111
src/backend/dbi/gnc-dbisqlconnection.hpp
Normal 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_
|
187
src/backend/dbi/gnc-dbisqlresult.cpp
Normal file
187
src/backend/dbi/gnc-dbisqlresult.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
|
77
src/backend/dbi/gnc-dbisqlresult.hpp
Normal file
77
src/backend/dbi/gnc-dbisqlresult.hpp
Normal 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__
|
@ -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
|
||||
|
@ -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\" \
|
||||
|
@ -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 );
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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
@ -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 ===================== */
|
||||
|
@ -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 */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 */
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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);
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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 */
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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;
|
||||
|
@ -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 ===================== */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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*
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 =================== */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user