From 9e8413586b23fa53575941448dc0f019bb870294 Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Fri, 16 Aug 2024 14:44:27 -0700 Subject: [PATCH] eval: fix hlc_to_timestamp builtin Builtin function `hlc_to_timestamp` calls internal function `decimalToHLC` which was assuming all input decimals had -10 as the exponent. But some decimals may have other exponents. It's more robust to call `Int64()` on the floored decimal, which handles any exponent. Fixes: #129152 Release note (bug fix): Fix a bug that would cause `hlc_to_timestamp` to return an incorrect timestamp for some input decimals. --- pkg/sql/sem/eval/context.go | 15 ++++++++------- pkg/sql/sem/eval/testdata/eval/builtins | 10 ++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/pkg/sql/sem/eval/context.go b/pkg/sql/sem/eval/context.go index 72f4e6f71aec..c914d52952a4 100644 --- a/pkg/sql/sem/eval/context.go +++ b/pkg/sql/sem/eval/context.go @@ -672,18 +672,19 @@ func DecimalToInexactDTimestampTZ(d *tree.DDecimal) (*tree.DTimestampTZ, error) } func decimalToHLC(d *tree.DDecimal) (hlc.Timestamp, error) { - var coef apd.BigInt - coef.Set(&d.Decimal.Coeff) - // The physical portion of the HLC is stored shifted up by 10^10, so shift - // it down and clear out the logical component. - coef.Div(&coef, big10E10) - if !coef.IsInt64() { + var floorD apd.Decimal + if _, err := tree.DecimalCtx.Floor(&floorD, &d.Decimal); err != nil { + return hlc.Timestamp{}, err + } + + i, err := floorD.Int64() + if err != nil { return hlc.Timestamp{}, pgerror.Newf( pgcode.DatetimeFieldOverflow, "timestamp value out of range: %s", d.String(), ) } - return hlc.Timestamp{WallTime: coef.Int64()}, nil + return hlc.Timestamp{WallTime: i}, nil } // DecimalToInexactDTimestamp is the inverse of TimestampToDecimal. It converts diff --git a/pkg/sql/sem/eval/testdata/eval/builtins b/pkg/sql/sem/eval/testdata/eval/builtins index 1b12094db558..2987cb806731 100644 --- a/pkg/sql/sem/eval/testdata/eval/builtins +++ b/pkg/sql/sem/eval/testdata/eval/builtins @@ -172,3 +172,13 @@ eval hlc_to_timestamp(1627966319623050000.0000000000) ---- '2021-08-03 04:51:59.62305+00' + +eval +hlc_to_timestamp(1627966319623050000) +---- +'2021-08-03 04:51:59.62305+00' + +eval +hlc_to_timestamp(1627966319623050000.00) +---- +'2021-08-03 04:51:59.62305+00'