Commit c3cd3093 authored by Vadim Zeitlin's avatar Vadim Zeitlin

Make text-to-double conversion exact in PostgreSQL backend.

By setting extra_float_digits to its maximal value (instead of the default 0)
we can ensure that the conversion from text (which we use when saving the
values in the database) to double (used internally) and back (when we retrieve
the values) is lossless and so that we read back exactly the same values as we
had written.

In principle, the best solution would be to use binary format with
PQexecParams() instead: this would avoid the conversion to/from text entirely
and so be undoubtedly correct and probably more efficient. However it also
would be more difficult, especially for NUMERIC types as we would need to
convert them to/from the protocol wire format ourselves, so for now just make
it work correctly in the simplest possible way.
parent ff9146ab
...@@ -29,6 +29,17 @@ ...@@ -29,6 +29,17 @@
using namespace soci; using namespace soci;
using namespace soci::details; using namespace soci::details;
namespace // unnamed
{
// helper function for hardcoded queries
void hard_exec(PGconn * conn, char const * query, char const * errMsg)
{
postgresql_result(PQexec(conn, query)).check_for_errors(errMsg);
}
} // namespace unnamed
postgresql_session_backend::postgresql_session_backend( postgresql_session_backend::postgresql_session_backend(
connection_parameters const& parameters) connection_parameters const& parameters)
: statementCount_(0) : statementCount_(0)
...@@ -47,6 +58,16 @@ postgresql_session_backend::postgresql_session_backend( ...@@ -47,6 +58,16 @@ postgresql_session_backend::postgresql_session_backend(
throw soci_error(msg); throw soci_error(msg);
} }
// Increase the number of digits used for floating point values to ensure
// that the conversions to/from text round trip correctly, which is not the
// case with the default value of 0. Use the maximal supported value, which
// was 2 until 9.x and is 3 since it.
int const version = PQserverVersion(conn);
hard_exec(conn,
version >= 90000 ? "SET extra_float_digits = 3"
: "SET extra_float_digits = 2",
"Cannot set extra_float_digits parameter");
conn_ = conn; conn_ = conn;
} }
...@@ -55,17 +76,6 @@ postgresql_session_backend::~postgresql_session_backend() ...@@ -55,17 +76,6 @@ postgresql_session_backend::~postgresql_session_backend()
clean_up(); clean_up();
} }
namespace // unnamed
{
// helper function for hardcoded queries
void hard_exec(PGconn * conn, char const * query, char const * errMsg)
{
postgresql_result(PQexec(conn, query)).check_for_errors(errMsg);
}
} // namespace unnamed
void postgresql_session_backend::begin() void postgresql_session_backend::begin()
{ {
hard_exec(conn_, "BEGIN", "Cannot begin transaction."); hard_exec(conn_, "BEGIN", "Cannot begin transaction.");
......
...@@ -800,6 +800,11 @@ public: ...@@ -800,6 +800,11 @@ public:
{ {
return "timestamptz(\'" + datdt_string + "\')"; return "timestamptz(\'" + datdt_string + "\')";
} }
virtual bool has_fp_bug() const
{
return false;
}
}; };
int main(int argc, char** argv) int main(int argc, char** argv)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment