From: Andres Freund Date: Mon, 9 Sep 2019 14:28:28 +0000 (-0700) Subject: Change out/readfuncs to handle floats precisely. X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=5a23372fc8166945144fbc26f51c4c3139de9067;p=users%2Fandresfreund%2Fpostgres.git Change out/readfuncs to handle floats precisely. Otherwise read/write produces node trees that aren't equal. That didn't use to be a significant issue, because most floats are in planner nodes, which can't be compared right now. But upcoming patches auto-generate them, allowing to enable previously disabled asserts. Author: Reviewed-By: Discussion: https://postgr.es/m/ Backpatch: --- diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 8b152038d9..08f3491cba 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -29,6 +29,7 @@ #include +#include "common/shortest_dec.h" #include "lib/stringinfo.h" #include "miscadmin.h" #include "nodes/extensible.h" @@ -83,8 +84,11 @@ static void outChar(StringInfo str, char c); (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) +#define WRITE_FLOAT_FIELD(fldname) \ + appendStringInfo(str, " :" CppAsString(fldname) " %s", \ + sizeof(node->fldname) == sizeof(float) ? \ + float_to_shortest_decimal(node->fldname) : \ + double_to_shortest_decimal(node->fldname)) /* Write a boolean field */ #define WRITE_BOOL_FIELD(fldname) \ @@ -361,9 +365,9 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node) static void _outPlanInfo(StringInfo str, const Plan *node) { - WRITE_FLOAT_FIELD(startup_cost, "%.2f"); - WRITE_FLOAT_FIELD(total_cost, "%.2f"); - WRITE_FLOAT_FIELD(plan_rows, "%.0f"); + WRITE_FLOAT_FIELD(startup_cost); + WRITE_FLOAT_FIELD(total_cost); + WRITE_FLOAT_FIELD(plan_rows); WRITE_INT_FIELD(plan_width); WRITE_BOOL_FIELD(parallel_aware); WRITE_BOOL_FIELD(parallel_safe); @@ -900,7 +904,7 @@ _outHash(StringInfo str, const Hash *node) WRITE_OID_FIELD(skewTable); WRITE_INT_FIELD(skewColumn); WRITE_BOOL_FIELD(skewInherit); - WRITE_FLOAT_FIELD(rows_total, "%.0f"); + WRITE_FLOAT_FIELD(rows_total); } static void @@ -1351,8 +1355,8 @@ _outSubPlan(StringInfo str, const SubPlan *node) WRITE_NODE_FIELD(setParam); WRITE_NODE_FIELD(parParam); WRITE_NODE_FIELD(args); - WRITE_FLOAT_FIELD(startup_cost, "%.2f"); - WRITE_FLOAT_FIELD(per_call_cost, "%.2f"); + WRITE_FLOAT_FIELD(startup_cost); + WRITE_FLOAT_FIELD(per_call_cost); } static void @@ -1746,9 +1750,9 @@ _outPathInfo(StringInfo str, const Path *node) WRITE_BOOL_FIELD(parallel_aware); WRITE_BOOL_FIELD(parallel_safe); WRITE_INT_FIELD(parallel_workers); - WRITE_FLOAT_FIELD(rows, "%.0f"); - WRITE_FLOAT_FIELD(startup_cost, "%.2f"); - WRITE_FLOAT_FIELD(total_cost, "%.2f"); + WRITE_FLOAT_FIELD(rows); + WRITE_FLOAT_FIELD(startup_cost); + WRITE_FLOAT_FIELD(total_cost); WRITE_NODE_FIELD(pathkeys); } @@ -1787,8 +1791,8 @@ _outIndexPath(StringInfo str, const IndexPath *node) WRITE_NODE_FIELD(indexorderbys); WRITE_NODE_FIELD(indexorderbycols); WRITE_ENUM_FIELD(indexscandir, ScanDirection); - WRITE_FLOAT_FIELD(indextotalcost, "%.2f"); - WRITE_FLOAT_FIELD(indexselectivity, "%.4f"); + WRITE_FLOAT_FIELD(indextotalcost); + WRITE_FLOAT_FIELD(indexselectivity); } static void @@ -1809,7 +1813,7 @@ _outBitmapAndPath(StringInfo str, const BitmapAndPath *node) _outPathInfo(str, (const Path *) node); WRITE_NODE_FIELD(bitmapquals); - WRITE_FLOAT_FIELD(bitmapselectivity, "%.4f"); + WRITE_FLOAT_FIELD(bitmapselectivity); } static void @@ -1820,7 +1824,7 @@ _outBitmapOrPath(StringInfo str, const BitmapOrPath *node) _outPathInfo(str, (const Path *) node); WRITE_NODE_FIELD(bitmapquals); - WRITE_FLOAT_FIELD(bitmapselectivity, "%.4f"); + WRITE_FLOAT_FIELD(bitmapselectivity); } static void @@ -1878,7 +1882,7 @@ _outAppendPath(StringInfo str, const AppendPath *node) WRITE_NODE_FIELD(partitioned_rels); WRITE_NODE_FIELD(subpaths); WRITE_INT_FIELD(first_partial_path); - WRITE_FLOAT_FIELD(limit_tuples, "%.0f"); + WRITE_FLOAT_FIELD(limit_tuples); } static void @@ -1890,7 +1894,7 @@ _outMergeAppendPath(StringInfo str, const MergeAppendPath *node) WRITE_NODE_FIELD(partitioned_rels); WRITE_NODE_FIELD(subpaths); - WRITE_FLOAT_FIELD(limit_tuples, "%.0f"); + WRITE_FLOAT_FIELD(limit_tuples); } static void @@ -2002,7 +2006,7 @@ _outAggPath(StringInfo str, const AggPath *node) WRITE_NODE_FIELD(subpath); WRITE_ENUM_FIELD(aggstrategy, AggStrategy); WRITE_ENUM_FIELD(aggsplit, AggSplit); - WRITE_FLOAT_FIELD(numGroups, "%.0f"); + WRITE_FLOAT_FIELD(numGroups); WRITE_NODE_FIELD(groupClause); WRITE_NODE_FIELD(qual); } @@ -2015,7 +2019,7 @@ _outRollupData(StringInfo str, const RollupData *node) WRITE_NODE_FIELD(groupClause); WRITE_NODE_FIELD(gsets); WRITE_NODE_FIELD(gsets_data); - WRITE_FLOAT_FIELD(numGroups, "%.0f"); + WRITE_FLOAT_FIELD(numGroups); WRITE_BOOL_FIELD(hashable); WRITE_BOOL_FIELD(is_hashed); } @@ -2026,7 +2030,7 @@ _outGroupingSetData(StringInfo str, const GroupingSetData *node) WRITE_NODE_TYPE("GSDATA"); WRITE_NODE_FIELD(set); - WRITE_FLOAT_FIELD(numGroups, "%.0f"); + WRITE_FLOAT_FIELD(numGroups); } static void @@ -2077,7 +2081,7 @@ _outSetOpPath(StringInfo str, const SetOpPath *node) WRITE_NODE_FIELD(distinctList); WRITE_INT_FIELD(flagColIdx); WRITE_INT_FIELD(firstFlag); - WRITE_FLOAT_FIELD(numGroups, "%.0f"); + WRITE_FLOAT_FIELD(numGroups); } static void @@ -2091,7 +2095,7 @@ _outRecursiveUnionPath(StringInfo str, const RecursiveUnionPath *node) WRITE_NODE_FIELD(rightpath); WRITE_NODE_FIELD(distinctList); WRITE_INT_FIELD(wtParam); - WRITE_FLOAT_FIELD(numGroups, "%.0f"); + WRITE_FLOAT_FIELD(numGroups); } static void @@ -2182,7 +2186,7 @@ _outHashPath(StringInfo str, const HashPath *node) WRITE_NODE_FIELD(path_hashclauses); WRITE_INT_FIELD(num_batches); - WRITE_FLOAT_FIELD(inner_rows_total, "%.0f"); + WRITE_FLOAT_FIELD(inner_rows_total); } static void @@ -2246,9 +2250,9 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node) WRITE_NODE_FIELD(sort_pathkeys); WRITE_NODE_FIELD(processed_tlist); WRITE_NODE_FIELD(minmax_aggs); - WRITE_FLOAT_FIELD(total_table_pages, "%.0f"); - WRITE_FLOAT_FIELD(tuple_fraction, "%.4f"); - WRITE_FLOAT_FIELD(limit_tuples, "%.0f"); + WRITE_FLOAT_FIELD(total_table_pages); + WRITE_FLOAT_FIELD(tuple_fraction); + WRITE_FLOAT_FIELD(limit_tuples); WRITE_UINT_FIELD(qual_security_level); WRITE_ENUM_FIELD(inhTargetKind, InheritanceKind); WRITE_BOOL_FIELD(hasJoinRTEs); @@ -2270,7 +2274,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node) /* NB: this isn't a complete set of fields */ WRITE_ENUM_FIELD(reloptkind, RelOptKind); WRITE_BITMAPSET_FIELD(relids); - WRITE_FLOAT_FIELD(rows, "%.0f"); + WRITE_FLOAT_FIELD(rows); WRITE_BOOL_FIELD(consider_startup); WRITE_BOOL_FIELD(consider_param_startup); WRITE_BOOL_FIELD(consider_parallel); @@ -2294,8 +2298,8 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node) WRITE_NODE_FIELD(indexlist); WRITE_NODE_FIELD(statlist); WRITE_UINT_FIELD(pages); - WRITE_FLOAT_FIELD(tuples, "%.0f"); - WRITE_FLOAT_FIELD(allvisfrac, "%.6f"); + WRITE_FLOAT_FIELD(tuples); + WRITE_FLOAT_FIELD(allvisfrac); WRITE_BITMAPSET_FIELD(eclass_indexes); WRITE_NODE_FIELD(subroot); WRITE_NODE_FIELD(subplan_params); @@ -2323,7 +2327,7 @@ _outIndexOptInfo(StringInfo str, const IndexOptInfo *node) WRITE_OID_FIELD(indexoid); /* Do NOT print rel field, else infinite recursion */ WRITE_UINT_FIELD(pages); - WRITE_FLOAT_FIELD(tuples, "%.0f"); + WRITE_FLOAT_FIELD(tuples); WRITE_INT_FIELD(tree_height); WRITE_INT_FIELD(ncolumns); /* array fields aren't really worth the trouble to print */ @@ -2441,8 +2445,8 @@ _outPathTarget(StringInfo str, const PathTarget *node) for (i = 0; i < list_length(node->exprs); i++) appendStringInfo(str, " %u", node->sortgrouprefs[i]); } - WRITE_FLOAT_FIELD(cost.startup, "%.2f"); - WRITE_FLOAT_FIELD(cost.per_tuple, "%.2f"); + WRITE_FLOAT_FIELD(cost.startup); + WRITE_FLOAT_FIELD(cost.per_tuple); WRITE_INT_FIELD(width); } @@ -2452,7 +2456,7 @@ _outParamPathInfo(StringInfo str, const ParamPathInfo *node) WRITE_NODE_TYPE("PARAMPATHINFO"); WRITE_BITMAPSET_FIELD(ppi_req_outer); - WRITE_FLOAT_FIELD(ppi_rows, "%.0f"); + WRITE_FLOAT_FIELD(ppi_rows); WRITE_NODE_FIELD(ppi_clauses); } @@ -2477,8 +2481,8 @@ _outRestrictInfo(StringInfo str, const RestrictInfo *node) WRITE_BITMAPSET_FIELD(right_relids); WRITE_NODE_FIELD(orclause); /* don't write parent_ec, leads to infinite recursion in plan tree dump */ - WRITE_FLOAT_FIELD(norm_selec, "%.4f"); - WRITE_FLOAT_FIELD(outer_selec, "%.4f"); + WRITE_FLOAT_FIELD(norm_selec); + WRITE_FLOAT_FIELD(outer_selec); WRITE_NODE_FIELD(mergeopfamilies); /* don't write left_ec, leads to infinite recursion in plan tree dump */ /* don't write right_ec, leads to infinite recursion in plan tree dump */ @@ -2565,7 +2569,7 @@ _outMinMaxAggInfo(StringInfo str, const MinMaxAggInfo *node) WRITE_NODE_FIELD(target); /* We intentionally omit subroot --- too large, not interesting enough */ WRITE_NODE_FIELD(path); - WRITE_FLOAT_FIELD(pathcost, "%.2f"); + WRITE_FLOAT_FIELD(pathcost); WRITE_NODE_FIELD(param); } @@ -3120,7 +3124,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); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 60fd406335..a5c36999e2 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -111,7 +111,8 @@ #define READ_FLOAT_FIELD(fldname) \ token = pg_strtok(&length); /* skip :fldname */ \ token = pg_strtok(&length); /* get field value */ \ - local_node->fldname = atof(token) + local_node->fldname = sizeof(local_node->fldname) == sizeof(float) ? \ + strtof(token, NULL) : strtod(token, NULL) /* Read a boolean field */ #define READ_BOOL_FIELD(fldname) \