From 7a8d8219ccbf0963f2171ea23e1616ee6a7823ba Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 19 Apr 2022 20:38:53 +0200 Subject: Fix extract epoch from interval calculation The new numeric code for extract epoch from interval accidentally truncated the DAYS_PER_YEAR value to an integer, leading to results that mismatched the floating-point interval_part calculations. The commit a2da77cdb4661826482ebf2ddba1f953bc74afe4 that introduced this actually contains the regression test change that this reverts. I suppose this was missed at the time. Reported-by: Joseph Koshakow Reviewed-by: Tom Lane Discussion: https://www.postgresql.org/message-id/flat/CAAvxfHd5n%3D13NYA2q_tUq%3D3%3DSuWU-CufmTf-Ozj%3DfrEgt7pXwQ%40mail.gmail.com --- src/backend/utils/adt/timestamp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/backend/utils/adt/timestamp.c') diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 1c0bf0aa5c8..fbe3c29ee10 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -5287,10 +5287,16 @@ interval_part_common(PG_FUNCTION_ARGS, bool retnumeric) int64 secs_from_day_month; int64 val; - /* this always fits into int64 */ - secs_from_day_month = ((int64) DAYS_PER_YEAR * (interval->month / MONTHS_PER_YEAR) + - (int64) DAYS_PER_MONTH * (interval->month % MONTHS_PER_YEAR) + - interval->day) * SECS_PER_DAY; + /* + * To do this calculation in integer arithmetic even though + * DAYS_PER_YEAR is fractional, multiply everything by 4 and then + * divide by 4 again at the end. This relies on DAYS_PER_YEAR + * being a multiple of 0.25 and on SECS_PER_DAY being a multiple + * of 4. + */ + secs_from_day_month = ((int64) (4 * DAYS_PER_YEAR) * (interval->month / MONTHS_PER_YEAR) + + (int64) (4 * DAYS_PER_MONTH) * (interval->month % MONTHS_PER_YEAR) + + (int64) 4 * interval->day) * (SECS_PER_DAY / 4); /*--- * result = secs_from_day_month + interval->time / 1'000'000 -- cgit v1.2.3