| From: | Andrey Rachitskiy <pl0h0yp1(at)gmail(dot)com> |
|---|---|
| To: | malis(at)pgrust(dot)com, pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Subject: | Re: BUG #19590: to_date/to_timestamp "Y,YYY" accepts out-of-range values |
| Date: | 2026-07-31 11:03:00 |
| Message-ID: | CAB8bMiumLaBvuX+FYU8q4BRwzb9fG1+ubR0pVtTMTT2WqRo1Bg@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
Hi, Michael!
Thanks for report.
DCH_Y_YYY used to parse millennia with sscanf("%d"). That silently
truncates values outside int range, so
```
SELECT to_date('4294969320,024', 'Y,YYY'); -- 2^32+2024
SELECT to_date('-4294965272,024', 'Y,YYY');
```
used to return 2024024-01-01 instead of erroring.
Other numeric fields already reject this via
from_char_parse_int_len(); the pg_mul_s32_overflow() check in
DCH_Y_YYY runs too late, after %d has discarded the magnitude.
This patch replaces the millennia %d with a single strtol(), using
the same ERANGE / INT_MIN / INT_MAX checks as from_char_parse_int_len().
The years part remains sscanf("%03d"): the field width limits the
conversion to three characters, so the value always fits in int. The
existing mul/add overflow checks are unchanged (they still catch
cases like 1000000000,999).
Y,YYY has two pieces: variable-width millennia up to a comma, then
three year digits. We parse and validate each separately.
Patch with tests, attached.
пт, 31 июл. 2026 г. в 14:47, PG Bug reporting form <noreply(at)postgresql(dot)org>:
> The following bug has been logged on the website:
>
> Bug reference: 19590
> Logged by: Michael Malis
> Email address: malis(at)pgrust(dot)com
> PostgreSQL version: 18.4
> Operating system: Debian 18.4-1.pgdg13+1, aarch64
> Description:
>
> The Y,YYY template field parses its millennia component with a bare
> sscanf(..., "%d", ...), which silently truncates values too large for int
> instead of rejecting them, so out-of-range input yields a wrong year:
>
> SELECT to_date('4294969320,024','Y,YYY'); -- 2024024-01-01 (expected:
> error)
> SELECT to_date('-4294965272,024','Y,YYY'); -- 2024024-01-01 (expected:
> error)
>
> 4294969320 is 2^32 + 2024, so it truncates to 2024 and is read as 2024
> millennia; any multiple of 2^32 works, and %d accepts a sign, so wrapped
> negatives too. to_timestamp() shares the code path. Every other numeric
> field rejects this:
>
> SELECT to_date('4294969320','YYYY');
> -- ERROR: value for "YYYY" in source string is out of range
>
> Cause: DCH_Y_YYY is the only numeric field using raw sscanf; the others go
> through from_char_parse_int_len(), which range-checks with strtol/ERANGE.
> The existing pg_mul_s32_overflow guard in DCH_Y_YYY runs too late. %d has
> already discarded the magnitude.
>
> Suggested fix: after the sscanf, re-scan the millennia field with strtol
> and
> reject ERANGE or out-of-int-range values, matching
> from_char_parse_int_len():
>
> errno = 0;
> lval = strtol(s, &endptr, 10);
> if (errno == ERANGE || lval < INT_MIN || lval > INT_MAX)
> ereturn(escontext,,
> (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
> errmsg("value for \"%s\" in source string is out of range",
> "Y,YYY"),
> errdetail("Value must be in the range %d to %d.", INT_MIN,
> INT_MAX)));
>
> strtol skips leading whitespace and stops at the comma exactly as %d does,
> so this only adds a rejection path; the ERANGE test covers 32-bit-long
> platforms where strtol saturates.
>
>
>
>
>
--
Regards,
Rachitskiy Andrey
| Attachment | Content-Type | Size |
|---|---|---|
| 0001-Reject-out-of-range-millennia-in-Y-YYY-parsing.patch | text/x-patch | 4.6 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | David Rowley | 2026-07-31 11:29:55 | Re: Hash Semi Join 5,000-50,000x slower on PG18 vs PG17 with 10+ equality columns and NULL values (identical plan, no spill) |
| Previous Message | Yugo Nagata | 2026-07-31 07:44:48 | Re: Two issues with REFRESH MATERIALIZED VIEW CONCURRENTLY |