summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut2022-09-26 14:02:09 +0000
committerPeter Eisentraut2022-09-26 14:02:09 +0000
commitacd624644bc4f957824abcd00f6af27861b03a29 (patch)
tree6017e9171f838541bba7e27bb2808a5bbf58de2e
parentc07785d458c1ca69ad7cd3ebb8f4a1d953c3779b (diff)
Don't lose precision for float fields of Nodes.
Historically we've been more worried about making the output of float fields look pretty than whether they'd be read back exactly. That won't work if we're to compare the read-back nodes for equality, so switch to using the Ryu code for float output. Author: Tom Lane <[email protected]> Discussion: https://www.postgresql.org/message-id/flat/[email protected]
-rw-r--r--src/backend/nodes/gen_node_support.pl12
-rw-r--r--src/backend/nodes/outfuncs.c23
2 files changed, 25 insertions, 10 deletions
diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl
index b707a09f56..81b8c184a9 100644
--- a/src/backend/nodes/gen_node_support.pl
+++ b/src/backend/nodes/gen_node_support.pl
@@ -983,29 +983,29 @@ _read${n}(void)
}
elsif ($t eq 'double')
{
- print $off "\tWRITE_FLOAT_FIELD($f, \"%.6f\");\n";
+ print $off "\tWRITE_FLOAT_FIELD($f);\n";
print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
}
elsif ($t eq 'Cardinality')
{
- print $off "\tWRITE_FLOAT_FIELD($f, \"%.0f\");\n";
+ print $off "\tWRITE_FLOAT_FIELD($f);\n";
print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
}
elsif ($t eq 'Cost')
{
- print $off "\tWRITE_FLOAT_FIELD($f, \"%.2f\");\n";
+ print $off "\tWRITE_FLOAT_FIELD($f);\n";
print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
}
elsif ($t eq 'QualCost')
{
- print $off "\tWRITE_FLOAT_FIELD($f.startup, \"%.2f\");\n";
- print $off "\tWRITE_FLOAT_FIELD($f.per_tuple, \"%.2f\");\n";
+ print $off "\tWRITE_FLOAT_FIELD($f.startup);\n";
+ print $off "\tWRITE_FLOAT_FIELD($f.per_tuple);\n";
print $rff "\tREAD_FLOAT_FIELD($f.startup);\n" unless $no_read;
print $rff "\tREAD_FLOAT_FIELD($f.per_tuple);\n" unless $no_read;
}
elsif ($t eq 'Selectivity')
{
- print $off "\tWRITE_FLOAT_FIELD($f, \"%.4f\");\n";
+ print $off "\tWRITE_FLOAT_FIELD($f);\n";
print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
}
elsif ($t eq 'char*')
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 63dda75ae5..64c65f060b 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -17,6 +17,7 @@
#include <ctype.h>
#include "access/attnum.h"
+#include "common/shortest_dec.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "nodes/bitmapset.h"
@@ -25,6 +26,7 @@
#include "utils/datum.h"
static void outChar(StringInfo str, char c);
+static void outDouble(StringInfo str, double d);
/*
@@ -69,9 +71,10 @@ static void outChar(StringInfo str, char c);
appendStringInfo(str, " :" CppAsString(fldname) " %d", \
(int) node->fldname)
-/* Write a float field --- caller must give format to define precision */
-#define WRITE_FLOAT_FIELD(fldname,format) \
- appendStringInfo(str, " :" CppAsString(fldname) " " format, node->fldname)
+/* Write a float field (actually, they're double) */
+#define WRITE_FLOAT_FIELD(fldname) \
+ (appendStringInfo(str, " :" CppAsString(fldname) " "), \
+ outDouble(str, node->fldname))
/* Write a boolean field */
#define WRITE_BOOL_FIELD(fldname) \
@@ -199,6 +202,18 @@ outChar(StringInfo str, char c)
}
/*
+ * Convert a double value, attempting to ensure the value is preserved exactly.
+ */
+static void
+outDouble(StringInfo str, double d)
+{
+ char buf[DOUBLE_SHORTEST_DECIMAL_LEN];
+
+ double_to_shortest_decimal_buf(d, buf);
+ appendStringInfoString(str, buf);
+}
+
+/*
* common implementation for scalar-array-writing functions
*
* The data format is either "<>" for a NULL pointer or "(item item item)".
@@ -525,7 +540,7 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
break;
case RTE_NAMEDTUPLESTORE:
WRITE_STRING_FIELD(enrname);
- WRITE_FLOAT_FIELD(enrtuples, "%.0f");
+ WRITE_FLOAT_FIELD(enrtuples);
WRITE_OID_FIELD(relid);
WRITE_NODE_FIELD(coltypes);
WRITE_NODE_FIELD(coltypmods);