diff --git a/src/expr/src/scalar/func/impls/numeric.rs b/src/expr/src/scalar/func/impls/numeric.rs index 76fd18124ae61..6a7bc6d67a57c 100644 --- a/src/expr/src/scalar/func/impls/numeric.rs +++ b/src/expr/src/scalar/func/impls/numeric.rs @@ -121,6 +121,10 @@ fn round_numeric(mut a: Numeric) -> Numeric { return a; } numeric::cx_datum().round(&mut a); + // Canonicalize: `dec`'s round preserves the sign on zero results, so e.g. + // `round(-0.4)` yields `-0`. munge_numeric strips that, ensuring row + // encodings match decimal equality. + numeric::munge_numeric(&mut a).unwrap(); a } diff --git a/test/sqllogictest/numeric.slt b/test/sqllogictest/numeric.slt index 6978a1268d091..24be504a442d7 100644 --- a/test/sqllogictest/numeric.slt +++ b/test/sqllogictest/numeric.slt @@ -1026,6 +1026,33 @@ SELECT round (-0.10212864, -900) ---- 0 +# Rounding a small negative numeric to zero must canonicalize away the sign +# bit; otherwise the result is `-0`, which renders incorrectly via the text +# cast and survives as a distinct row encoding from `0`. +query T +SELECT round(-0.4::numeric)::text +---- +0 + +query T +SELECT round(-0.49::numeric, 0)::text +---- +0 + +query T +SELECT round(-0.000001::numeric, 2)::text +---- +0 + +query T +SELECT v::text FROM ( + SELECT round(-0.4::numeric) AS v + UNION + SELECT 0::numeric +) t +---- +0 + # ceil query RRR