Repository navigation
Fix binary NUMERIC-to-DOUBLE rounding - #610
Merged
Merged
Conversation
Preserve PostgreSQL base-10000 digits in a scientific-notation string and convert once with DuckDB floating-point parsing. Avoid repeated rounding and intermediate overflow from large display scales. Add exact comparisons against PostgreSQL float8 across binary COPY, binary query, and text query modes, including halfway values, subnormals, high-scale decimals, and arrays. Fixes duckdb#604.
staticlibs
approved these changes
Oct 13, 2026
staticlibs
left a comment
Member
There was a problem hiding this comment.
Thanks for the PR! Looks good to me.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #604.
Unconstrained NUMERIC values and NUMERIC types outside DuckDB's DECIMAL limits are read as DOUBLE. The binary decoder currently accumulates their base-10000 digits with floating-point arithmetic, rounding at several intermediate steps. For example, PostgreSQL's
8629.433::numericcan be read as8629.432999999999. Applying the display scale can also overflow while decoding finite values such as1.5::numeric(1000,500).This builds a decimal coefficient from the stored digits with exponent
4 * (weight + 1 - ndigits), then calls DuckDB's floating-point parser once. There is no need to expand implicit zero groups or apply the display scale with floating-point arithmetic. The handling of zero, NaN, infinity, and constrained DECIMAL values stays the same.The new sqllogictest compares decoded values against PostgreSQL's float8 cast in COPY_BINARY, PLAIN_QUERY_BINARY, and PLAIN_QUERY_TEXT modes. It covers the reported values, halfway rounding, finite limits, subnormals, high display scales, NULL, special values, and NUMERIC arrays. Results are materialized before comparison so predicate pushdown cannot hide a decoder error.
Validation:
numerics_nan_inf.test,attach_types_decimal.test, andattach_types_numerics.testpass, with 295 assertions in total.CI also caught an existing giant-NUMERIC array expectation that recorded the old rounding error. The giant-NUMERIC and isolation-level expectations now use the corrected values (
1e+32and-1.2345678912345679e+26), checked against PostgreSQL's float8 and float8[] casts. Those two test files and the rounding regression pass locally with 50 assertions.I haven't run the full connector suite, cross-platform tests, malformed-wire-input tests, or throughput benchmarks.