From e53a8808bd501f08a9660920830559b5785745a8 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Thu, 9 Oct 2025 18:44:35 +0800
Subject: [PATCH v9 16/19] error safe for casting timestamp to other types per
 pg_cast

select castsource::regtype, casttarget::regtype, castfunc, castcontext,castmethod, pp.prosrc, pp.proname
from pg_cast pc join pg_proc pp on pp.oid = pc.castfunc
and pc.castfunc > 0 and (castsource::regtype ='timestamp'::regtype)
order by castsource::regtype;

         castsource          |         casttarget          | castfunc | castcontext | castmethod |        prosrc         |   proname
-----------------------------+-----------------------------+----------+-------------+------------+-----------------------+-------------
 timestamp without time zone | date                        |     2029 | a           | f          | timestamp_date        | date
 timestamp without time zone | time without time zone      |     1316 | a           | f          | timestamp_time        | time
 timestamp without time zone | timestamp with time zone    |     2028 | i           | f          | timestamp_timestamptz | timestamptz
 timestamp without time zone | timestamp without time zone |     1961 | i           | f          | timestamp_scale       | timestamp
(4 rows)

discussion: https://postgr.es/m/CADkLM=fv1JfY4Ufa-jcwwNbjQixNViskQ8jZu3Tz_p656i_4hQ@mail.gmail.com
---
 src/backend/utils/adt/date.c      | 13 +++++++++++--
 src/backend/utils/adt/timestamp.c | 17 +++++++++++++++--
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 111bfd8f519..c5562b563e5 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -1373,7 +1373,16 @@ timestamp_date(PG_FUNCTION_ARGS)
 	Timestamp	timestamp = PG_GETARG_TIMESTAMP(0);
 	DateADT		result;
 
-	result = timestamp2date_opt_overflow(timestamp, NULL);
+	if (likely(!fcinfo->context))
+		result = timestamptz2date_opt_overflow(timestamp, NULL);
+	else
+	{
+		int			overflow;
+		result = timestamp2date_opt_overflow(timestamp, &overflow);
+
+		if (overflow != 0)
+			PG_RETURN_NULL();
+	}
 	PG_RETURN_DATEADT(result);
 }
 
@@ -2089,7 +2098,7 @@ timestamp_time(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
-		ereport(ERROR,
+		ereturn(fcinfo->context, (Datum) 0,
 				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 				 errmsg("timestamp out of range")));
 
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 116e3ef28fc..7a57ac3eaf6 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -352,7 +352,8 @@ timestamp_scale(PG_FUNCTION_ARGS)
 
 	result = timestamp;
 
-	AdjustTimestampForTypmod(&result, typmod, NULL);
+	if (!AdjustTimestampForTypmod(&result, typmod, fcinfo->context))
+		PG_RETURN_NULL();
 
 	PG_RETURN_TIMESTAMP(result);
 }
@@ -6430,7 +6431,19 @@ timestamp_timestamptz(PG_FUNCTION_ARGS)
 {
 	Timestamp	timestamp = PG_GETARG_TIMESTAMP(0);
 
-	PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp));
+	if (likely(!fcinfo->context))
+		PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp));
+	else
+	{
+		TimestampTz result;
+		int			overflow;
+
+		result = timestamp2timestamptz_opt_overflow(timestamp, &overflow);
+		if (overflow != 0)
+			PG_RETURN_NULL();
+		else
+			PG_RETURN_TIMESTAMPTZ(result);
+	}
 }
 
 /*
-- 
2.34.1

