mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-12-01 21:19:16 -06:00
740 lines
24 KiB
C++
740 lines
24 KiB
C++
/********************************************************************
|
|
* gnc-sql-column-table-entry.cpp: Implement GncSqlColumnTableEntry *
|
|
* *
|
|
* 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 *
|
|
\********************************************************************/
|
|
|
|
extern "C"
|
|
{
|
|
#include <config.h>
|
|
#include <qof.h>
|
|
}
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <gnc-datetime.hpp>
|
|
#include "gnc-sql-backend.hpp"
|
|
#include "gnc-sql-object-backend.hpp"
|
|
#include "gnc-sql-column-table-entry.hpp"
|
|
#include "gnc-sql-result.hpp"
|
|
|
|
static QofLogModule log_module = G_LOG_DOMAIN;
|
|
|
|
/* ================================================================= */
|
|
static gpointer
|
|
get_autoinc_id (void* object, const QofParam* param)
|
|
{
|
|
// Just need a 0 to force a new autoinc value
|
|
return (gpointer)0;
|
|
}
|
|
|
|
static void
|
|
set_autoinc_id (void* object, void* item)
|
|
{
|
|
// Nowhere to put the ID
|
|
}
|
|
|
|
QofAccessFunc
|
|
GncSqlColumnTableEntry::get_getter (QofIdTypeConst obj_name) const noexcept
|
|
{
|
|
QofAccessFunc getter;
|
|
|
|
g_return_val_if_fail (obj_name != NULL, NULL);
|
|
|
|
if (m_flags & COL_AUTOINC)
|
|
{
|
|
getter = get_autoinc_id;
|
|
}
|
|
else if (m_qof_param_name != NULL)
|
|
{
|
|
getter = qof_class_get_parameter_getter (obj_name, m_qof_param_name);
|
|
}
|
|
else
|
|
{
|
|
getter = m_getter;
|
|
}
|
|
|
|
return getter;
|
|
}
|
|
|
|
QofSetterFunc
|
|
GncSqlColumnTableEntry::get_setter(QofIdTypeConst obj_name) const noexcept
|
|
{
|
|
QofSetterFunc setter = nullptr;
|
|
if (m_flags & COL_AUTOINC)
|
|
{
|
|
setter = set_autoinc_id;
|
|
}
|
|
else if (m_qof_param_name != nullptr)
|
|
{
|
|
g_assert (obj_name != NULL);
|
|
setter = qof_class_get_parameter_setter (obj_name, m_qof_param_name);
|
|
}
|
|
else
|
|
{
|
|
setter = m_setter;
|
|
}
|
|
return setter;
|
|
}
|
|
|
|
void
|
|
GncSqlColumnTableEntry::add_objectref_guid_to_query (QofIdTypeConst obj_name,
|
|
const void* pObject,
|
|
PairVec& vec) const noexcept
|
|
{
|
|
auto inst = get_row_value_from_object<QofInstance*>(obj_name, pObject);
|
|
if (inst == nullptr) return;
|
|
auto guid = qof_instance_get_guid (inst);
|
|
if (guid != nullptr)
|
|
vec.emplace_back (std::make_pair (std::string{m_col_name},
|
|
std::string{guid_to_string(guid)}));
|
|
}
|
|
|
|
void
|
|
GncSqlColumnTableEntry::add_objectref_guid_to_table (ColVec& vec) const noexcept
|
|
{
|
|
GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
|
|
vec.emplace_back(std::move(info));
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_STRING>::load (const GncSqlBackend* sql_be,
|
|
GncSqlRow& row,
|
|
QofIdTypeConst obj_name,
|
|
gpointer pObject) const noexcept
|
|
{
|
|
g_return_if_fail (pObject != NULL);
|
|
g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
|
|
|
|
try
|
|
{
|
|
auto s = row.get_string_at_col (m_col_name);
|
|
set_parameter(pObject, s.c_str(), get_setter(obj_name), m_gobj_param_name);
|
|
}
|
|
catch (std::invalid_argument) {}
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_STRING>::add_to_table(ColVec& vec) const noexcept
|
|
{
|
|
GncSqlColumnInfo info{*this, BCT_STRING, m_size, TRUE};
|
|
vec.emplace_back(std::move(info));
|
|
}
|
|
|
|
/* char is unusual in that we get a pointer but don't deref it to pass
|
|
* it to operator<<().
|
|
*/
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_STRING>::add_to_query(QofIdTypeConst obj_name,
|
|
const gpointer pObject,
|
|
PairVec& vec) const noexcept
|
|
{
|
|
auto s = get_row_value_from_object<char*>(obj_name, pObject);
|
|
|
|
if (s != nullptr)
|
|
{
|
|
std::ostringstream stream;
|
|
stream << s;
|
|
vec.emplace_back (std::make_pair (std::string{m_col_name}, stream.str()));
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
typedef gint (*IntAccessFunc) (const gpointer);
|
|
typedef void (*IntSetterFunc) (const gpointer, gint);
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_INT>::load (const GncSqlBackend* sql_be,
|
|
GncSqlRow& row,
|
|
QofIdTypeConst obj_name,
|
|
gpointer pObject) const noexcept
|
|
{
|
|
|
|
g_return_if_fail (pObject != NULL);
|
|
g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
|
|
|
|
auto val = row.get_int_at_col(m_col_name);
|
|
set_parameter(pObject, val,
|
|
reinterpret_cast<IntSetterFunc>(get_setter(obj_name)), m_gobj_param_name);
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_INT>::add_to_table(ColVec& vec) const noexcept
|
|
{
|
|
GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
|
|
vec.emplace_back(std::move(info));
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_INT>::add_to_query(QofIdTypeConst obj_name,
|
|
const gpointer pObject,
|
|
PairVec& vec) const noexcept
|
|
{
|
|
add_value_to_vec<int>(obj_name, pObject, vec);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
typedef gboolean (*BooleanAccessFunc) (const gpointer);
|
|
typedef void (*BooleanSetterFunc) (const gpointer, gboolean);
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_BOOLEAN>::load (const GncSqlBackend* sql_be,
|
|
GncSqlRow& row,
|
|
QofIdTypeConst obj_name,
|
|
gpointer pObject)
|
|
const noexcept
|
|
{
|
|
g_return_if_fail (pObject != NULL);
|
|
g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
|
|
|
|
auto val = row.get_int_at_col (m_col_name);
|
|
set_parameter(pObject, val,
|
|
reinterpret_cast<BooleanSetterFunc>(get_setter(obj_name)),
|
|
m_gobj_param_name);
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_BOOLEAN>::add_to_table(ColVec& vec) const noexcept
|
|
{
|
|
GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
|
|
vec.emplace_back(std::move(info));
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_BOOLEAN>::add_to_query(QofIdTypeConst obj_name,
|
|
const gpointer pObject,
|
|
PairVec& vec) const noexcept
|
|
{
|
|
add_value_to_vec<int>(obj_name, pObject, vec);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
typedef gint64 (*Int64AccessFunc) (const gpointer);
|
|
typedef void (*Int64SetterFunc) (const gpointer, gint64);
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_INT64>::load (const GncSqlBackend* sql_be,
|
|
GncSqlRow& row,
|
|
QofIdTypeConst obj_name,
|
|
gpointer pObject)
|
|
const noexcept
|
|
{
|
|
g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
|
|
|
|
auto val = row.get_int_at_col (m_col_name);
|
|
set_parameter(pObject, val,
|
|
reinterpret_cast<Int64SetterFunc>(get_setter(obj_name)),
|
|
m_gobj_param_name);
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_INT64>::add_to_table(ColVec& vec) const noexcept
|
|
{
|
|
|
|
GncSqlColumnInfo info{*this, BCT_INT64, 0, FALSE};
|
|
vec.emplace_back(std::move(info));
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_INT64>::add_to_query(QofIdTypeConst obj_name,
|
|
const gpointer pObject,
|
|
PairVec& vec) const noexcept
|
|
{
|
|
add_value_to_vec<int64_t>(obj_name, pObject, vec);
|
|
}
|
|
/* ----------------------------------------------------------------- */
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_DOUBLE>::load (const GncSqlBackend* sql_be,
|
|
GncSqlRow& row,
|
|
QofIdTypeConst obj_name,
|
|
gpointer pObject)
|
|
const noexcept
|
|
{
|
|
g_return_if_fail (pObject != NULL);
|
|
g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
|
|
double val;
|
|
try
|
|
{
|
|
val = static_cast<double>(row.get_int_at_col(m_col_name));
|
|
}
|
|
catch (std::invalid_argument)
|
|
{
|
|
try
|
|
{
|
|
val = static_cast<double>(row.get_float_at_col(m_col_name));
|
|
}
|
|
catch (std::invalid_argument)
|
|
{
|
|
try
|
|
{
|
|
val = row.get_double_at_col(m_col_name);
|
|
}
|
|
catch (std::invalid_argument)
|
|
{
|
|
val = 0.0;
|
|
}
|
|
}
|
|
}
|
|
set_parameter(pObject, val, get_setter(obj_name), m_gobj_param_name);
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_table(ColVec& vec) const noexcept
|
|
{
|
|
GncSqlColumnInfo info{*this, BCT_DOUBLE, 0, FALSE};
|
|
vec.emplace_back(std::move(info));
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_query(QofIdTypeConst obj_name,
|
|
const gpointer pObject,
|
|
PairVec& vec) const noexcept
|
|
{
|
|
add_value_to_vec<double*>(obj_name, pObject, vec);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_GUID>::load (const GncSqlBackend* sql_be,
|
|
GncSqlRow& row,
|
|
QofIdTypeConst obj_name,
|
|
gpointer pObject)
|
|
const noexcept
|
|
{
|
|
|
|
GncGUID guid;
|
|
const GncGUID* pGuid;
|
|
|
|
g_return_if_fail (pObject != NULL);
|
|
g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
|
|
|
|
std::string str;
|
|
try
|
|
{
|
|
str = row.get_string_at_col(m_col_name);
|
|
}
|
|
catch (std::invalid_argument)
|
|
{
|
|
return;
|
|
}
|
|
if (string_to_guid (str.c_str(), &guid))
|
|
set_parameter(pObject, &guid, get_setter(obj_name), m_gobj_param_name);
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_GUID>::add_to_table(ColVec& vec) const noexcept
|
|
{
|
|
GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
|
|
vec.emplace_back(std::move(info));
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_GUID>::add_to_query(QofIdTypeConst obj_name,
|
|
const gpointer pObject,
|
|
PairVec& vec) const noexcept
|
|
{
|
|
auto s = get_row_value_from_object<GncGUID*>(obj_name, pObject);
|
|
|
|
if (s != nullptr)
|
|
{
|
|
|
|
vec.emplace_back (std::make_pair (std::string{m_col_name},
|
|
std::string{guid_to_string(s)}));
|
|
return;
|
|
}
|
|
}
|
|
/* ----------------------------------------------------------------- */
|
|
typedef Timespec (*TimespecAccessFunc) (const gpointer);
|
|
typedef void (*TimespecSetterFunc) (const gpointer, Timespec*);
|
|
|
|
#define TIMESPEC_COL_SIZE (4+3+3+3+3+3)
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_TIMESPEC>::load (const GncSqlBackend* sql_be,
|
|
GncSqlRow& row,
|
|
QofIdTypeConst obj_name,
|
|
gpointer pObject) const noexcept
|
|
{
|
|
|
|
Timespec ts = {0, 0};
|
|
gboolean isOK = FALSE;
|
|
|
|
|
|
g_return_if_fail (pObject != NULL);
|
|
g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
|
|
|
|
try
|
|
{
|
|
auto val = row.get_time64_at_col(m_col_name);
|
|
timespecFromTime64 (&ts, val);
|
|
}
|
|
catch (std::invalid_argument)
|
|
{
|
|
try
|
|
{
|
|
constexpr size_t datelen = 14;
|
|
auto val = row.get_string_at_col(m_col_name);
|
|
if (val.length() == datelen)
|
|
{
|
|
using std::stoi;
|
|
#ifdef HAVE_STRUCT_TM_GMTOFF
|
|
const struct tm tm
|
|
{stoi(val.substr(12, 2)), stoi(val.substr(10, 2)),
|
|
stoi(val.substr(8, 2)), stoi(val.substr(6, 2)),
|
|
stoi(val.substr(4, 2)) - 1, stoi(val.substr(0, 4)) - 1900,
|
|
0, 0, 0, 0, nullptr};
|
|
#else
|
|
const struct tm tm
|
|
{stoi(val.substr(12, 2)), stoi(val.substr(10, 2)),
|
|
stoi(val.substr(8, 2)), stoi(val.substr(6, 2)),
|
|
stoi(val.substr(4, 2)) - 1, stoi(val.substr(0, 4)) -1900,
|
|
0, 0, 0};
|
|
#endif
|
|
|
|
GncDateTime time(tm);
|
|
ts.tv_sec = static_cast<time64>(time);
|
|
}
|
|
else
|
|
{
|
|
GncDateTime time(val);
|
|
ts.tv_sec = static_cast<time64>(time);
|
|
}
|
|
}
|
|
catch (std::invalid_argument)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
set_parameter(pObject, &ts,
|
|
reinterpret_cast<TimespecSetterFunc>(get_setter(obj_name)),
|
|
m_gobj_param_name);
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_TIMESPEC>::add_to_table(ColVec& vec) const noexcept
|
|
{
|
|
GncSqlColumnInfo info{*this, BCT_DATETIME, TIMESPEC_COL_SIZE, FALSE};
|
|
vec.emplace_back(std::move(info));
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_TIMESPEC>::add_to_query(QofIdTypeConst obj_name,
|
|
const gpointer pObject,
|
|
PairVec& vec) const noexcept
|
|
{
|
|
TimespecAccessFunc ts_getter;
|
|
Timespec ts;
|
|
/* Can't use get_row_value_from_object because g_object_get returns a
|
|
* Timespec* and the getter returns a Timespec. Will be fixed by the
|
|
* replacement of timespecs with time64s.
|
|
*/
|
|
g_return_if_fail (obj_name != NULL);
|
|
g_return_if_fail (pObject != NULL);
|
|
|
|
if (m_gobj_param_name != NULL)
|
|
{
|
|
Timespec* pts;
|
|
g_object_get (pObject, m_gobj_param_name, &pts, NULL);
|
|
ts = *pts;
|
|
}
|
|
else
|
|
{
|
|
ts_getter = (TimespecAccessFunc)get_getter (obj_name);
|
|
g_return_if_fail (ts_getter != NULL);
|
|
ts = (*ts_getter) (pObject);
|
|
}
|
|
|
|
GncDateTime time(ts.tv_sec);
|
|
vec.emplace_back (std::make_pair (std::string{m_col_name},
|
|
time.format_zulu ("%Y-%m-%d %H:%M:%S")));
|
|
}
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
#define DATE_COL_SIZE 8
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_GDATE>::load (const GncSqlBackend* sql_be,
|
|
GncSqlRow& row,
|
|
QofIdTypeConst obj_name,
|
|
gpointer pObject) const noexcept
|
|
{
|
|
g_return_if_fail (pObject != NULL);
|
|
g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
|
|
if (row.is_col_null(m_col_name))
|
|
return;
|
|
GDate date;
|
|
g_date_clear (&date, 1);
|
|
try
|
|
{
|
|
/* timespec_to_gdate applies the tz, and gdates are saved
|
|
* as ymd, so we don't want that.
|
|
*/
|
|
auto time = row.get_time64_at_col(m_col_name);
|
|
auto tm = gnc_gmtime(&time);
|
|
g_date_set_dmy(&date, tm->tm_mday,
|
|
static_cast<GDateMonth>(tm->tm_mon + 1),
|
|
tm->tm_year + 1900);
|
|
free(tm);
|
|
}
|
|
catch (std::invalid_argument)
|
|
{
|
|
try
|
|
{
|
|
std::string str = row.get_string_at_col(m_col_name);
|
|
if (str.empty()) return;
|
|
auto year = static_cast<GDateYear>(stoi (str.substr (0,4)));
|
|
auto month = static_cast<GDateMonth>(stoi (str.substr (4,2)));
|
|
auto day = static_cast<GDateDay>(stoi (str.substr (6,2)));
|
|
|
|
if (year != 0 || month != 0 || day != (GDateDay)0)
|
|
g_date_set_dmy(&date, day, month, year);
|
|
|
|
}
|
|
catch (std::invalid_argument)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
set_parameter(pObject, &date, get_setter(obj_name), m_gobj_param_name);
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_table(ColVec& vec) const noexcept
|
|
{
|
|
GncSqlColumnInfo info{*this, BCT_DATE, DATE_COL_SIZE, FALSE};
|
|
vec.emplace_back(std::move(info));
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_query(QofIdTypeConst obj_name,
|
|
const gpointer pObject,
|
|
PairVec& vec) const noexcept
|
|
{
|
|
GDate *date = get_row_value_from_object<GDate*>(obj_name, pObject);
|
|
|
|
if (date && g_date_valid (date))
|
|
{
|
|
std::ostringstream buf;
|
|
buf << std::setfill ('0') << std::setw (4) << g_date_get_year (date) <<
|
|
std::setw (2) << g_date_get_month (date) <<
|
|
std::setw (2) << static_cast<int>(g_date_get_day (date));
|
|
vec.emplace_back (std::make_pair (std::string{m_col_name}, buf.str()));
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
typedef gnc_numeric (*NumericGetterFunc) (const gpointer);
|
|
typedef void (*NumericSetterFunc) (gpointer, gnc_numeric*);
|
|
|
|
static const EntryVec numeric_col_table =
|
|
{
|
|
gnc_sql_make_table_entry<CT_INT64>("num", 0, COL_NNUL, "guid"),
|
|
gnc_sql_make_table_entry<CT_INT64>("denom", 0, COL_NNUL, "guid")
|
|
};
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_NUMERIC>::load (const GncSqlBackend* sql_be,
|
|
GncSqlRow& row,
|
|
QofIdTypeConst obj_name,
|
|
gpointer pObject) const noexcept
|
|
{
|
|
|
|
|
|
g_return_if_fail (pObject != NULL);
|
|
g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
|
|
gnc_numeric n;
|
|
try
|
|
{
|
|
auto buf = g_strdup_printf ("%s_num", m_col_name);
|
|
auto num = row.get_int_at_col (buf);
|
|
g_free (buf);
|
|
buf = g_strdup_printf ("%s_denom", m_col_name);
|
|
auto denom = row.get_int_at_col (buf);
|
|
n = gnc_numeric_create (num, denom);
|
|
g_free (buf);
|
|
}
|
|
catch (std::invalid_argument)
|
|
{
|
|
return;
|
|
}
|
|
set_parameter(pObject, &n,
|
|
reinterpret_cast<NumericSetterFunc>(get_setter(obj_name)),
|
|
m_gobj_param_name);
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_table(ColVec& vec) const noexcept
|
|
{
|
|
|
|
for (auto const& subtable_row : numeric_col_table)
|
|
{
|
|
gchar* buf = g_strdup_printf("%s_%s", m_col_name,
|
|
subtable_row->m_col_name);
|
|
GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false,
|
|
m_flags & COL_PKEY, m_flags & COL_NNUL);
|
|
g_free (buf);
|
|
vec.emplace_back(std::move(info));
|
|
}
|
|
}
|
|
|
|
template<> void
|
|
GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_query(QofIdTypeConst obj_name,
|
|
const gpointer pObject,
|
|
PairVec& vec) const noexcept
|
|
{
|
|
/* We can't use get_row_value_from_object for the same reason as Timespec. */
|
|
NumericGetterFunc getter;
|
|
gnc_numeric n;
|
|
|
|
g_return_if_fail (obj_name != NULL);
|
|
g_return_if_fail (pObject != NULL);
|
|
|
|
if (m_gobj_param_name != nullptr)
|
|
{
|
|
gnc_numeric* s;
|
|
g_object_get (pObject, m_gobj_param_name, &s, NULL);
|
|
n = *s;
|
|
}
|
|
else
|
|
{
|
|
getter = reinterpret_cast<NumericGetterFunc>(get_getter (obj_name));
|
|
if (getter != NULL)
|
|
{
|
|
n = (*getter) (pObject);
|
|
}
|
|
else
|
|
{
|
|
n = gnc_numeric_zero ();
|
|
}
|
|
}
|
|
|
|
std::ostringstream buf;
|
|
std::string num_col{m_col_name};
|
|
std::string denom_col{m_col_name};
|
|
num_col += "_num";
|
|
denom_col += "_denom";
|
|
buf << gnc_numeric_num (n);
|
|
vec.emplace_back (std::make_pair (num_col, buf.str ()));
|
|
buf.str ("");
|
|
buf << gnc_numeric_denom (n);
|
|
vec.emplace_back (denom_col, buf.str ());
|
|
}
|
|
|
|
static void
|
|
_retrieve_guid_ (gpointer pObject, gpointer pValue)
|
|
{
|
|
GncGUID* pGuid = (GncGUID*)pObject;
|
|
GncGUID* guid = (GncGUID*)pValue;
|
|
|
|
g_return_if_fail (pObject != NULL);
|
|
g_return_if_fail (pValue != NULL);
|
|
|
|
memcpy (pGuid, guid, sizeof (GncGUID));
|
|
}
|
|
|
|
// Table to retrieve just the guid
|
|
static EntryVec guid_table
|
|
{
|
|
gnc_sql_make_table_entry<CT_GUID>("guid", 0, 0, nullptr, _retrieve_guid_)
|
|
};
|
|
|
|
const GncGUID*
|
|
gnc_sql_load_guid (const GncSqlBackend* sql_be, GncSqlRow& row)
|
|
{
|
|
static GncGUID guid;
|
|
|
|
g_return_val_if_fail (sql_be != NULL, NULL);
|
|
|
|
gnc_sql_load_object (sql_be, row, NULL, &guid, guid_table);
|
|
|
|
return &guid;
|
|
}
|
|
|
|
void
|
|
gnc_sql_load_object (const GncSqlBackend* sql_be, GncSqlRow& row,
|
|
QofIdTypeConst obj_name, gpointer pObject,
|
|
const EntryVec& table)
|
|
{
|
|
QofSetterFunc setter;
|
|
|
|
g_return_if_fail (sql_be != NULL);
|
|
g_return_if_fail (pObject != NULL);
|
|
|
|
for (auto const& table_row : table)
|
|
{
|
|
table_row->load (sql_be, row, obj_name, pObject);
|
|
}
|
|
}
|
|
|
|
uint_t
|
|
gnc_sql_append_guids_to_sql (std::stringstream& sql,
|
|
const InstanceVec& instances)
|
|
{
|
|
char guid_buf[GUID_ENCODING_LENGTH + 1];
|
|
|
|
for (auto inst : instances)
|
|
{
|
|
(void)guid_to_string_buff (qof_instance_get_guid (inst), guid_buf);
|
|
|
|
if (inst != *(instances.begin()))
|
|
{
|
|
sql << ",";
|
|
}
|
|
sql << "'" << guid_buf << "'";
|
|
}
|
|
|
|
return instances.size();
|
|
}
|
|
|
|
/* This is necessary for 64-bit builds because g++ complains
|
|
* that reinterpret_casting a void* (64 bits) to an int (32 bits)
|
|
* loses precision, so we have to explicitly dispose of the precision.
|
|
* FIXME: We shouldn't be storing ints in ptrs in the first place.
|
|
*/
|
|
#ifdef __LP64__
|
|
template <> int
|
|
GncSqlColumnTableEntry::get_row_value_from_object<int>(QofIdTypeConst obj_name,
|
|
const void* pObject,
|
|
std::false_type) const
|
|
{
|
|
g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, 0);
|
|
int result = 0;
|
|
if (m_gobj_param_name != nullptr)
|
|
g_object_get(const_cast<void*>(pObject), m_gobj_param_name, &result,
|
|
nullptr);
|
|
else
|
|
{
|
|
QofAccessFunc getter = get_getter(obj_name);
|
|
if (getter != nullptr)
|
|
{
|
|
auto value = ((getter)(const_cast<void*>(pObject), nullptr));
|
|
result = reinterpret_cast<uint64_t>(value) &
|
|
UINT64_C(0x00000000FFFFFFFF);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|