Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wpjpv-001ooN-1Q for pgsql-bugs@arkaria.postgresql.org; Fri, 31 Jul 2026 09:47:27 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wpjpu-00FLB7-1I for pgsql-bugs@arkaria.postgresql.org; Fri, 31 Jul 2026 09:47:26 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wpgF2-00EdA2-2c for pgsql-bugs@lists.postgresql.org; Fri, 31 Jul 2026 05:57:08 +0000 Received: from mahout.postgresql.org ([2001:4800:3e1:1::227]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wpgF0-00000001DVF-0t5Q for pgsql-bugs@lists.postgresql.org; Fri, 31 Jul 2026 05:57:08 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=postgresql.org; s=20171124; h=Message-ID:Date:Reply-To:Cc:From:To:Subject: Content-Transfer-Encoding:MIME-Version:Content-Type:Sender:Content-ID: Content-Description:In-Reply-To:References; bh=iKuYvAQsAUrXIKno1YvHbMa9Btssl87PIILWZqsJVoo=; b=CS7p+lV3MI0/2VttfpwxCXuPqj wndBmM6/8WZxHm14X02FvkpcwK4pucA2UWi5scgRoYfYR1YCoGXn3J7qBC9LJMLNV4p3YnPDrxx33 rxzKylkZRdxivHO1b/FwwRZFfA8lqWyi9/7MFxGBIbxOcDIub1+IF23mTHvZ4D0drSDo71OumKqSO 3Wv0oz7adXXFZxCDKw5E96f/4bfy1N/KrsPMVa498MG1+SbCnFPaufEJMHznJQ2bp3XhgB5xwOtQW hyCH4MFubi6f3bjh7IZtyZAl5EDJwxtu7ig9FQCpbaUnQsKXCDeZLH6oyqZHw54MMF3f2cSYqWhTi URvy8ZFw==; Received: from wrigleys.postgresql.org ([2a02:16a8:dc51::60]) by mahout.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wpgEy-003i3l-2v for pgsql-bugs@lists.postgresql.org; Fri, 31 Jul 2026 05:57:04 +0000 Received: from localhost ([127.0.0.1] helo=wrigleys.postgresql.org) by wrigleys.postgresql.org with esmtp (Exim 4.98.2) (envelope-from ) id 1wpgEx-000000093Ze-31oJ for pgsql-bugs@lists.postgresql.org; Fri, 31 Jul 2026 05:57:03 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: BUG #19590: to_date/to_timestamp "Y,YYY" accepts out-of-range values To: pgsql-bugs@lists.postgresql.org From: PG Bug reporting form Cc: malis@pgrust.com Reply-To: malis@pgrust.com, pgsql-bugs@lists.postgresql.org Date: Fri, 31 Jul 2026 05:57:01 +0000 Message-ID: <19590-991c467c2a601be0@postgresql.org> X-Auto-Response-Suppress: All Auto-Submitted: auto-generated List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk The following bug has been logged on the website: Bug reference: 19590 Logged by: Michael Malis Email address: malis@pgrust.com PostgreSQL version: 18.4 Operating system: Debian 18.4-1.pgdg13+1, aarch64 Description: =20 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 =3D 0; lval =3D strtol(s, &endptr, 10); if (errno =3D=3D 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.