Make float database operations more consistent.

We don't use floats in GnuCash, we use doubles (and those as little as
possible), but dbd-sqlite3 is broken in that it stores only floats.
Simply casting floats to doubles introduces bogus additional digits
that can cause round-trip tests to fail. Instead convert floats to
doubles by multiplying by 10E6, rounding, then dividing by 10E6.
This commit is contained in:
John Ralls 2018-06-02 16:16:41 -07:00
parent 3e052e8dac
commit 9db60ca63c
5 changed files with 9 additions and 7 deletions

View File

@ -30,6 +30,7 @@ extern "C"
/* For direct access to dbi data structs, sadly needed for datetime */ /* For direct access to dbi data structs, sadly needed for datetime */
#include <dbi/dbi-dev.h> #include <dbi/dbi-dev.h>
} }
#include <cmath>
#include <gnc-datetime.hpp> #include <gnc-datetime.hpp>
#include "gnc-dbisqlresult.hpp" #include "gnc-dbisqlresult.hpp"
#include "gnc-dbisqlconnection.hpp" #include "gnc-dbisqlconnection.hpp"
@ -109,7 +110,7 @@ GncDbiSqlResult::IteratorImpl::get_int_at_col(const char* col) const
return dbi_result_get_longlong (m_inst->m_dbi_result, col); return dbi_result_get_longlong (m_inst->m_dbi_result, col);
} }
float double
GncDbiSqlResult::IteratorImpl::get_float_at_col(const char* col) const GncDbiSqlResult::IteratorImpl::get_float_at_col(const char* col) const
{ {
auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col); auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
@ -118,8 +119,9 @@ GncDbiSqlResult::IteratorImpl::get_float_at_col(const char* col) const
(attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE4) (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE4)
throw (std::invalid_argument{"Requested float from non-float column."}); throw (std::invalid_argument{"Requested float from non-float column."});
auto locale = gnc_push_locale (LC_NUMERIC, "C"); auto locale = gnc_push_locale (LC_NUMERIC, "C");
auto retval = dbi_result_get_float(m_inst->m_dbi_result, col); auto interim = dbi_result_get_float(m_inst->m_dbi_result, col);
gnc_pop_locale (LC_NUMERIC, locale); gnc_pop_locale (LC_NUMERIC, locale);
double retval = static_cast<double>(round(interim * 1000000.0)) / 1000000.0;
return retval; return retval;
} }

View File

@ -54,7 +54,7 @@ protected:
virtual GncSqlRow& operator++(int) { return ++(*this); }; virtual GncSqlRow& operator++(int) { return ++(*this); };
virtual GncSqlResult* operator*() { return m_inst; } virtual GncSqlResult* operator*() { return m_inst; }
virtual int64_t get_int_at_col (const char* col) const; virtual int64_t get_int_at_col (const char* col) const;
virtual float get_float_at_col (const char* col) const; virtual double get_float_at_col (const char* col) const;
virtual double get_double_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 std::string get_string_at_col (const char* col)const;
virtual time64 get_time64_at_col (const char* col) const; virtual time64 get_time64_at_col (const char* col) const;

View File

@ -283,7 +283,7 @@ GncSqlColumnTableEntryImpl<CT_DOUBLE>::load (const GncSqlBackend* sql_be,
{ {
try try
{ {
val = static_cast<double>(row.get_float_at_col(m_col_name)); val = row.get_float_at_col(m_col_name);
} }
catch (std::invalid_argument&) catch (std::invalid_argument&)
{ {

View File

@ -52,7 +52,7 @@ protected:
virtual GncSqlRow& operator++() = 0; virtual GncSqlRow& operator++() = 0;
virtual GncSqlResult* operator*() = 0; virtual GncSqlResult* operator*() = 0;
virtual int64_t get_int_at_col (const char* col) const = 0; virtual int64_t get_int_at_col (const char* col) const = 0;
virtual float get_float_at_col (const char* col) const = 0; virtual double get_float_at_col (const char* col) const = 0;
virtual double get_double_at_col (const char* col) const = 0; virtual double get_double_at_col (const char* col) const = 0;
virtual std::string get_string_at_col (const char* col) const = 0; virtual std::string get_string_at_col (const char* col) const = 0;
virtual time64 get_time64_at_col (const char* col) const = 0; virtual time64 get_time64_at_col (const char* col) const = 0;
@ -88,7 +88,7 @@ public:
friend bool operator!=(const GncSqlRow&, const GncSqlRow&); friend bool operator!=(const GncSqlRow&, const GncSqlRow&);
int64_t get_int_at_col (const char* col) const { int64_t get_int_at_col (const char* col) const {
return m_iter->get_int_at_col (col); } return m_iter->get_int_at_col (col); }
float get_float_at_col (const char* col) const { double get_float_at_col (const char* col) const {
return m_iter->get_float_at_col (col); } return m_iter->get_float_at_col (col); }
double get_double_at_col (const char* col) const { double get_double_at_col (const char* col) const {
return m_iter->get_double_at_col (col); } return m_iter->get_double_at_col (col); }

View File

@ -66,7 +66,7 @@ protected:
virtual GncSqlResult* operator*() { return m_inst; } virtual GncSqlResult* operator*() { return m_inst; }
virtual int64_t get_int_at_col (const char* col) const virtual int64_t get_int_at_col (const char* col) const
{ return 1LL; } { return 1LL; }
virtual float get_float_at_col (const char* col) const virtual double get_float_at_col (const char* col) const
{ return 1.0; } { return 1.0; }
virtual double get_double_at_col (const char* col) const virtual double get_double_at_col (const char* col) const
{ return 1.0; } { return 1.0; }