From cabaa856a2e34882f056461d3a0e1c313ae6feab Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Fri, 20 Mar 2026 09:53:29 +0800
Subject: [PATCH v23 03/23] error safe for casting character 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 ='character'::regtype
order by castsource::regtype;

 castsource |    casttarget     | castfunc | castcontext | castmethod |   prosrc    | proname
------------+-------------------+----------+-------------+------------+-------------+---------
 character  | text              |      401 | i           | f          | rtrim1      | text
 character  | character varying |      401 | i           | f          | rtrim1      | text
 character  | "char"            |      944 | a           | f          | text_char   | char
 character  | name              |      409 | i           | f          | bpchar_name | name
 character  | xml               |     2896 | e           | f          | texttoxml   | xml
 character  | character         |      668 | i           | f          | bpchar      | bpchar
(6 rows)

only texttoxml, bpchar(PG_FUNCTION_ARGS) need take care of error handling.
other functions already error safe.

Author: jian he <jian.universality@gmail.com>
Reviewed-by: Amul Sul <sulamul@gmail.com>
Reviewed-by: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://postgr.es/m/CADkLM=fv1JfY4Ufa-jcwwNbjQixNViskQ8jZu3Tz_p656i_4hQ@mail.gmail.com
Commitfest: https://commitfest.postgresql.org/patch/5941
---
 src/backend/executor/execExprInterp.c |  2 +-
 src/backend/utils/adt/varchar.c       |  2 +-
 src/backend/utils/adt/xml.c           | 18 ++++++++++++------
 src/include/utils/xml.h               |  2 +-
 4 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 53ae0205702..43116431edf 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -4548,7 +4548,7 @@ ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
 
 				*op->resvalue = PointerGetDatum(xmlparse(data,
 														 xexpr->xmloption,
-														 preserve_whitespace));
+														 preserve_whitespace, NULL));
 				*op->resnull = false;
 			}
 			break;
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index df305098130..6f083973fe7 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -307,7 +307,7 @@ bpchar(PG_FUNCTION_ARGS)
 		{
 			for (i = maxmblen; i < len; i++)
 				if (s[i] != ' ')
-					ereport(ERROR,
+					ereturn(fcinfo->context, (Datum) 0,
 							(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
 							 errmsg("value too long for type character(%d)",
 									maxlen)));
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 79f6cf7b4fa..52f4f8fc490 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -660,7 +660,7 @@ texttoxml(PG_FUNCTION_ARGS)
 {
 	text	   *data = PG_GETARG_TEXT_PP(0);
 
-	PG_RETURN_XML_P(xmlparse(data, xmloption, true));
+	PG_RETURN_XML_P(xmlparse(data, xmloption, true, fcinfo->context));
 }
 
 
@@ -1029,19 +1029,25 @@ xmlelement(XmlExpr *xexpr,
 
 
 xmltype *
-xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace)
+xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, Node *escontext)
 {
 #ifdef USE_LIBXML
 	xmlDocPtr	doc;
 
 	doc = xml_parse(data, xmloption_arg, preserve_whitespace,
-					GetDatabaseEncoding(), NULL, NULL, NULL);
-	xmlFreeDoc(doc);
+					GetDatabaseEncoding(), NULL, NULL, escontext);
+	if (doc)
+		xmlFreeDoc(doc);
+
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return NULL;
 
 	return (xmltype *) data;
 #else
-	NO_XML_SUPPORT();
-	return NULL;
+	ereturn(escontext, NULL,
+			errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			errmsg("unsupported XML feature"),
+			errdetail("This functionality requires the server to be built with libxml support."));
 #endif
 }
 
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index 023fdeb4531..ca266f448d6 100644
--- a/src/include/utils/xml.h
+++ b/src/include/utils/xml.h
@@ -73,7 +73,7 @@ extern xmltype *xmlconcat(List *args);
 extern xmltype *xmlelement(XmlExpr *xexpr,
 						   const Datum *named_argvalue, const bool *named_argnull,
 						   const Datum *argvalue, const bool *argnull);
-extern xmltype *xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace);
+extern xmltype *xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, Node *escontext);
 extern xmltype *xmlpi(const char *target, text *arg, bool arg_is_null, bool *result_is_null);
 extern xmltype *xmlroot(xmltype *data, text *version, int standalone);
 extern bool xml_is_document(xmltype *arg);
-- 
2.34.1

