From 30fb4299bcc66aa90755fbac42e43d6d8a66b642 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Mon, 6 Oct 2025 12:39:22 +0800
Subject: [PATCH v12 15/20] error safe for casting timestamptz 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 ='timestamptz'::regtype)
order by castsource::regtype;

        castsource        |         casttarget          | castfunc | castcontext | castmethod |        prosrc         |   proname
--------------------------+-----------------------------+----------+-------------+------------+-----------------------+-------------
 timestamp with time zone | date                        |     1178 | a           | f          | timestamptz_date      | date
 timestamp with time zone | time without time zone      |     2019 | a           | f          | timestamptz_time      | time
 timestamp with time zone | timestamp without time zone |     2027 | a           | f          | timestamptz_timestamp | timestamp
 timestamp with time zone | time with time zone         |     1388 | a           | f          | timestamptz_timetz    | timetz
 timestamp with time zone | timestamp with time zone    |     1967 | i           | f          | timestamptz_scale     | timestamptz
(5 rows)

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

diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 4f0f3d26989..111bfd8f519 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -1468,7 +1468,17 @@ timestamptz_date(PG_FUNCTION_ARGS)
 	TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
 	DateADT		result;
 
-	result = timestamptz2date_opt_overflow(timestamp, NULL);
+	if (likely(!fcinfo->context))
+		result = timestamptz2date_opt_overflow(timestamp, NULL);
+	else
+	{
+		int			overflow;
+		result = timestamptz2date_opt_overflow(timestamp, &overflow);
+
+		if (overflow != 0)
+			PG_RETURN_NULL();
+	}
+
 	PG_RETURN_DATEADT(result);
 }
 
@@ -2110,7 +2120,7 @@ timestamptz_time(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
-		ereport(ERROR,
+		ereturn(fcinfo->context, (Datum) 0,
 				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 				 errmsg("timestamp out of range")));
 
@@ -3029,7 +3039,7 @@ timestamptz_timetz(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	if (timestamp2tm(timestamp, &tz, 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 7b565cc6d66..116e3ef28fc 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -875,7 +875,8 @@ timestamptz_scale(PG_FUNCTION_ARGS)
 
 	result = timestamp;
 
-	AdjustTimestampForTypmod(&result, typmod, NULL);
+	if (!AdjustTimestampForTypmod(&result, typmod, fcinfo->context))
+		PG_RETURN_NULL();
 
 	PG_RETURN_TIMESTAMPTZ(result);
 }
@@ -6507,7 +6508,19 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
 {
 	TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
 
-	PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
+	if (likely(!fcinfo->context))
+		PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
+	else
+	{
+		int			overflow;
+		Timestamp	result;
+
+		result = timestamptz2timestamp_opt_overflow(timestamp, &overflow);
+		if (overflow != 0)
+			PG_RETURN_NULL();
+		else
+			PG_RETURN_TIMESTAMP(result);
+	}
 }
 
 /*
-- 
2.34.1

