From c8e97cdff6c80a830fe9cd84c89f342c7d02a32d Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Thu, 10 Sep 2026 15:49:20 +0800
Subject: [PATCH v34 2/3] introduce pg_proc.proerrorsafe
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

ERROR { UNSAFE | SAFE }

ERROR UNSAFE indicates that the function aborts the transaction when an error is
encountered. This is the default behavior. ERROR SAFE indicates that the
function can report an invalid result as a “soft” error instead of aborting the
transaction. Otherwise, an invalid result causes the transaction to abort, just
as it would if the function were processed normally.
------------------------------------

-- Using the below query to list all the pg_catalog function support error safe

select pp.proname, pp.prosrc
from pg_cast pc join pg_proc pp on pp.oid = pc.castfunc
join pg_type pt on pt.oid = castsource
join pg_type pt1 on pt1.oid = casttarget
and pc.castfunc > 0 and pt.typnamespace = 'pg_catalog'::regnamespace
and pt1.typnamespace = 'pg_catalog'::regnamespace and proerrorsafe is false
order by pp.proname, pp.prosrc;

Inspired-by: Henson Choi <assam258@gmail.com>
Discussion: https://postgr.es/m/CADkLM=fv1JfY4Ufa-jcwwNbjQixNViskQ8jZu3Tz_p656i_4hQ@mail.gmail.com
Commitfest: https://commitfest.postgresql.org/patch/5941
---
 doc/src/sgml/catalogs.sgml                    |  14 +
 doc/src/sgml/ref/alter_function.sgml          |  12 +
 doc/src/sgml/ref/create_function.sgml         |  35 +++
 src/backend/catalog/pg_aggregate.c            |   1 +
 src/backend/catalog/pg_proc.c                 |   3 +
 src/backend/commands/functioncmds.c           |  52 +++-
 src/backend/commands/typecmds.c               |   4 +
 src/backend/parser/gram.y                     |   4 +
 src/backend/utils/adt/ruleutils.c             |   3 +
 src/bin/pg_dump/pg_dump.c                     |  12 +
 src/include/catalog/pg_proc.dat               | 258 +++++++++---------
 src/include/catalog/pg_proc.h                 |   4 +
 .../regress/expected/create_function_sql.out  |   8 +-
 .../regress/expected/create_procedure.out     |  12 +
 src/test/regress/expected/misc_functions.out  |  13 +
 src/test/regress/expected/opr_sanity.out      |  13 +
 src/test/regress/sql/create_function_sql.sql  |   5 +-
 src/test/regress/sql/create_procedure.sql     |   4 +
 src/test/regress/sql/misc_functions.sql       |   4 +
 src/test/regress/sql/opr_sanity.sql           |   8 +
 20 files changed, 329 insertions(+), 140 deletions(-)

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 78cce7e370d..6b14db151ea 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -6147,6 +6147,20 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       </para></entry>
      </row>
 
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>proerrorsafe</structfield> <type>bool</type>
+      </para>
+      <para>
+       <structfield>proerrorsafe</structfield> indicates whether a function
+       avoids aborting the transaction when an error occurs.  It is
+       <literal>true</literal> for functions that can report an invalid result
+       as a <quote>soft</quote> error instead of aborting the transaction.  It
+       is <literal>false</literal> for functions that abort the transaction when
+       an error occurs.
+      </para></entry>
+     </row>
+
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>pronargs</structfield> <type>int2</type>
diff --git a/doc/src/sgml/ref/alter_function.sgml b/doc/src/sgml/ref/alter_function.sgml
index 8193b17f255..b6601364dac 100644
--- a/doc/src/sgml/ref/alter_function.sgml
+++ b/doc/src/sgml/ref/alter_function.sgml
@@ -39,6 +39,7 @@ ALTER FUNCTION <replaceable>name</replaceable> [ ( [ [ <replaceable class="param
     [ NOT ] LEAKPROOF
     [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
     PARALLEL { UNSAFE | RESTRICTED | SAFE }
+    ERROR { UNSAFE | SAFE }
     COST <replaceable class="parameter">execution_cost</replaceable>
     ROWS <replaceable class="parameter">result_rows</replaceable>
     SUPPORT <replaceable class="parameter">support_function</replaceable>
@@ -223,6 +224,17 @@ ALTER FUNCTION <replaceable>name</replaceable> [ ( [ [ <replaceable class="param
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><literal>ERROR</literal></term>
+
+    <listitem>
+     <para>
+      Change whether the function is deemed error safe.
+      See <xref linkend="sql-createfunction"/> for details.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><literal>LEAKPROOF</literal></term>
     <listitem>
diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml
index 8e7f4aa08b6..635d4424afe 100644
--- a/doc/src/sgml/ref/create_function.sgml
+++ b/doc/src/sgml/ref/create_function.sgml
@@ -33,6 +33,7 @@ CREATE [ OR REPLACE ] FUNCTION
     | { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }
     | { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }
     | PARALLEL { UNSAFE | RESTRICTED | SAFE }
+    | ERROR { UNSAFE | SAFE }
     | COST <replaceable class="parameter">execution_cost</replaceable>
     | ROWS <replaceable class="parameter">result_rows</replaceable>
     | SUPPORT <replaceable class="parameter">support_function</replaceable>
@@ -463,6 +464,40 @@ CREATE [ OR REPLACE ] FUNCTION
     </listitem>
    </varlistentry>
 
+    <varlistentry>
+     <term><literal>ERROR</literal></term>
+
+     <listitem>
+      <para>
+       <literal>ERROR UNSAFE</literal> indicates that the function aborts the
+        transaction when an error is encountered. This is the default behavior.
+       </para>
+
+     <para>
+       <literal>ERROR SAFE</literal> indicates that the function can report
+       some errors, such as invalid input, as <quote>soft</quote> errors
+       when the caller requests it, instead of aborting the transaction.
+       <literal>ERROR UNSAFE</literal>, the default, indicates that every
+       error aborts the transaction.
+     </para>
+
+     <para>
+       Currently this is only used for data type cast functions.  For
+       example, casting the <type>integer</type> value
+       <literal>65536</literal> to <type>smallint</type> normally raises an
+       error.  If the cast function is marked <literal>ERROR SAFE</literal>,
+       a caller that tolerates invalid input can instead be told that the
+       conversion failed, which makes it possible to attempt a cast without
+       aborting the transaction when the value does not fit.
+
+       Errors that the function does not report softly, such as exceeding
+       the stack depth limit or running out of memory, still abort the
+       transaction.
+     </para>
+
+     </listitem>
+    </varlistentry>
+
     <varlistentry>
      <term><literal>COST</literal> <replaceable class="parameter">execution_cost</replaceable></term>
 
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 4d98a7584ae..a3860964e60 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -662,6 +662,7 @@ AggregateCreate(const char *aggName,
 							 PROVOLATILE_IMMUTABLE, /* volatility (not needed
 													 * for agg) */
 							 proparallel,
+							 false,	/* proerrorsafe */
 							 parameterTypes,	/* paramTypes */
 							 allParameterTypes, /* allParamTypes */
 							 parameterModes,	/* parameterModes */
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 53e27dd10e6..0ae6723cccd 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -78,6 +78,7 @@ static bool match_prosrc_to_literal(const char *prosrc, const char *literal,
  *	isStrict: strict? (proisstrict)
  *	volatility: volatility code (provolatile)
  *	parallel: parallel safety code (proparallel)
+ *	isErrorSafe: error safe? (proerrorsafe)
  *	parameterTypes: input parameter types, as an oidvector (proargtypes)
  *	allParameterTypes: all parameter types, as an OID array (proallargtypes)
  *	parameterModes: parameter modes, as a "char" array (proargmodes)
@@ -113,6 +114,7 @@ ProcedureCreate(const char *procedureName,
 				bool isStrict,
 				char volatility,
 				char parallel,
+				bool isErrorSafe,
 				oidvector *parameterTypes,
 				Datum allParameterTypes,
 				Datum parameterModes,
@@ -342,6 +344,7 @@ ProcedureCreate(const char *procedureName,
 	values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet);
 	values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility);
 	values[Anum_pg_proc_proparallel - 1] = CharGetDatum(parallel);
+	values[Anum_pg_proc_proerrorsafe - 1] = BoolGetDatum(isErrorSafe);
 	values[Anum_pg_proc_pronargs - 1] = Int16GetDatum(parameterCount);
 	values[Anum_pg_proc_pronargdefaults - 1] = Int16GetDatum(list_length(parameterDefaults));
 	values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 4d46013d7de..5624439a95a 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -538,7 +538,8 @@ compute_common_attribute(ParseState *pstate,
 						 DefElem **cost_item,
 						 DefElem **rows_item,
 						 DefElem **support_item,
-						 DefElem **parallel_item)
+						 DefElem **parallel_item,
+						 DefElem **errorsafe_item)
 {
 	if (strcmp(defel->defname, "volatility") == 0)
 	{
@@ -614,6 +615,15 @@ compute_common_attribute(ParseState *pstate,
 
 		*parallel_item = defel;
 	}
+	else if (strcmp(defel->defname, "error") == 0)
+	{
+		if (is_procedure)
+			goto procedure_error;
+		if (*errorsafe_item)
+			errorConflictingDefElem(defel, pstate);
+
+		*errorsafe_item = defel;
+	}
 	else
 		return false;
 
@@ -666,6 +676,24 @@ interpret_func_parallel(DefElem *defel)
 	}
 }
 
+static bool
+interpret_func_errorsafe(DefElem *defel)
+{
+	char	   *str = strVal(defel->arg);
+
+	if (strcmp(str, "safe") == 0)
+		return true;
+	else if (strcmp(str, "unsafe") == 0)
+		return false;
+	else
+	{
+		ereport(ERROR,
+				errcode(ERRCODE_SYNTAX_ERROR),
+				errmsg("parameter \"error\" must be SAFE or UNSAFE"));
+		return false;			/* keep compiler quiet */
+	}
+}
+
 /*
  * Update a proconfig value according to a list of VariableSetStmt items.
  *
@@ -756,7 +784,8 @@ compute_function_attributes(ParseState *pstate,
 							float4 *procost,
 							float4 *prorows,
 							Oid *prosupport,
-							char *parallel_p)
+							char *parallel_p,
+							bool *errorsafe_p)
 {
 	ListCell   *option;
 	DefElem    *as_item = NULL;
@@ -772,6 +801,7 @@ compute_function_attributes(ParseState *pstate,
 	DefElem    *rows_item = NULL;
 	DefElem    *support_item = NULL;
 	DefElem    *parallel_item = NULL;
+	DefElem    *errorsafe_item = NULL;
 
 	foreach(option, options)
 	{
@@ -817,7 +847,8 @@ compute_function_attributes(ParseState *pstate,
 										  &cost_item,
 										  &rows_item,
 										  &support_item,
-										  &parallel_item))
+										  &parallel_item,
+										  &errorsafe_item))
 		{
 			/* recognized common option */
 			continue;
@@ -865,6 +896,8 @@ compute_function_attributes(ParseState *pstate,
 		*prosupport = interpret_func_support(support_item);
 	if (parallel_item)
 		*parallel_p = interpret_func_parallel(parallel_item);
+	if (errorsafe_item)
+		*errorsafe_p = interpret_func_errorsafe(errorsafe_item);
 }
 
 
@@ -1067,7 +1100,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
 	bool		isWindowFunc,
 				isStrict,
 				security,
-				isLeakProof;
+				isLeakProof,
+				isErrorSafe;
 	char		volatility;
 	ArrayType  *proconfig;
 	float4		procost;
@@ -1096,6 +1130,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
 	security = false;
 	isLeakProof = false;
 	volatility = PROVOLATILE_VOLATILE;
+	isErrorSafe = false;
 	proconfig = NULL;
 	procost = -1;				/* indicates not set */
 	prorows = -1;				/* indicates not set */
@@ -1110,7 +1145,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
 								&isWindowFunc, &volatility,
 								&isStrict, &security, &isLeakProof,
 								&proconfig, &procost, &prorows,
-								&prosupport, &parallel);
+								&prosupport, &parallel, &isErrorSafe);
 
 	if (!language)
 	{
@@ -1303,6 +1338,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
 						   isStrict,
 						   volatility,
 						   parallel,
+						   isErrorSafe,
 						   parameterTypes,
 						   PointerGetDatum(allParameterTypes),
 						   PointerGetDatum(parameterModes),
@@ -1390,6 +1426,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
 	DefElem    *rows_item = NULL;
 	DefElem    *support_item = NULL;
 	DefElem    *parallel_item = NULL;
+	DefElem    *errorsafe_item = NULL;
 	ObjectAddress address;
 
 	rel = table_open(ProcedureRelationId, RowExclusiveLock);
@@ -1433,7 +1470,8 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
 									 &cost_item,
 									 &rows_item,
 									 &support_item,
-									 &parallel_item) == false)
+									 &parallel_item,
+									 &errorsafe_item) == false)
 			elog(ERROR, "option \"%s\" not recognized", defel->defname);
 	}
 
@@ -1499,6 +1537,8 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
 	}
 	if (parallel_item)
 		procForm->proparallel = interpret_func_parallel(parallel_item);
+	if (errorsafe_item)
+		procForm->proerrorsafe = interpret_func_errorsafe(errorsafe_item);
 	if (set_items)
 	{
 		Datum		datum;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 99a0ae2228e..9f072a08eb3 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -1848,6 +1848,7 @@ makeRangeConstructors(const char *name, Oid namespace,
 								 false, /* isStrict */
 								 PROVOLATILE_IMMUTABLE, /* volatility */
 								 PROPARALLEL_SAFE,	/* parallel safety */
+								 false, /* proerrorsafe */
 								 constructorArgTypesVector, /* parameterTypes */
 								 PointerGetDatum(NULL), /* allParameterTypes */
 								 PointerGetDatum(NULL), /* parameterModes */
@@ -1919,6 +1920,7 @@ makeMultirangeConstructors(const char *name, Oid namespace,
 							 true,	/* isStrict */
 							 PROVOLATILE_IMMUTABLE, /* volatility */
 							 PROPARALLEL_SAFE,	/* parallel safety */
+							 false, /* proerrorsafe */
 							 argtypes,	/* parameterTypes */
 							 PointerGetDatum(NULL), /* allParameterTypes */
 							 PointerGetDatum(NULL), /* parameterModes */
@@ -1965,6 +1967,7 @@ makeMultirangeConstructors(const char *name, Oid namespace,
 							 true,	/* isStrict */
 							 PROVOLATILE_IMMUTABLE, /* volatility */
 							 PROPARALLEL_SAFE,	/* parallel safety */
+							 false, /* proerrorsafe */
 							 argtypes,	/* parameterTypes */
 							 PointerGetDatum(NULL), /* allParameterTypes */
 							 PointerGetDatum(NULL), /* parameterModes */
@@ -2004,6 +2007,7 @@ makeMultirangeConstructors(const char *name, Oid namespace,
 							 true,	/* isStrict */
 							 PROVOLATILE_IMMUTABLE, /* volatility */
 							 PROPARALLEL_SAFE,	/* parallel safety */
+							 false, /* proerrorsafe */
 							 argtypes,	/* parameterTypes */
 							 PointerGetDatum(allParameterTypes),	/* allParameterTypes */
 							 PointerGetDatum(parameterModes),	/* parameterModes */
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0563453fe24..24a13ebbafe 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -8944,6 +8944,10 @@ common_func_opt_item:
 				{
 					$$ = makeDefElem("parallel", (Node *) makeString($2), @1);
 				}
+			| ERROR_P ColId
+				{
+					$$ = makeDefElem("error", (Node *) makeString($2), @1);
+				}
 		;
 
 createfunc_opt_item:
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 8f6a46fa614..294228bad82 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3010,6 +3010,9 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
 			break;
 	}
 
+	if (proc->proerrorsafe)
+		appendStringInfoString(&buf, " ERROR SAFE");
+
 	if (proc->proisstrict)
 		appendStringInfoString(&buf, " STRICT");
 	if (proc->prosecdef)
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 69171d6b859..1af0a84a04d 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -13431,6 +13431,7 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
 	char	   *prorows;
 	char	   *prosupport;
 	char	   *proparallel;
+	char	   *proerrorsafe;
 	char	   *lanname;
 	char	  **configitems = NULL;
 	int			nconfigitems = 0;
@@ -13474,6 +13475,13 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
 		appendPQExpBufferStr(query,
 							 "proparallel,\n");
 
+		if (fout->remoteVersion >= 200000)
+			appendPQExpBufferStr(query,
+								 "proerrorsafe,\n");
+		else
+			appendPQExpBufferStr(query,
+								 "false AS proerrorsafe,\n");
+
 		if (fout->remoteVersion >= 110000)
 			appendPQExpBufferStr(query,
 								 "prokind,\n");
@@ -13538,6 +13546,7 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
 	prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
 	prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
 	proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
+	proerrorsafe = PQgetvalue(res, 0, PQfnumber(res, "proerrorsafe"));
 	lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
 
 	/*
@@ -13703,6 +13712,9 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
 					 finfo->dobj.name);
 	}
 
+	if (proerrorsafe[0] == 't')
+		appendPQExpBufferStr(q, " ERROR SAFE");
+
 	for (int i = 0; i < nconfigitems; i++)
 	{
 		/* we feel free to scribble on configitems[] here */
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 1f21a8eb6d4..037cdc3ce3d 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -202,7 +202,7 @@
   proargtypes => 'xid8 xid8', prosrc => 'xid8cmp' },
 { oid => '5071', descr => 'convert xid8 to xid',
   proname => 'xid', prorettype => 'xid', proargtypes => 'xid8',
-  prosrc => 'xid8toxid' },
+  prosrc => 'xid8toxid', proerrorsafe => 't' },
 { oid => '5097', descr => 'larger of two',
   proname => 'xid8_larger', prorettype => 'xid8', proargtypes => 'xid8 xid8',
   prosrc => 'xid8_larger' },
@@ -229,10 +229,10 @@
   proargtypes => 'char char', prosrc => 'charge' },
 { oid => '77', descr => 'convert char to int4',
   proname => 'int4', prorettype => 'int4', proargtypes => 'char',
-  prosrc => 'chartoi4' },
+  prosrc => 'chartoi4', proerrorsafe => 't' },
 { oid => '78', descr => 'convert int4 to char',
   proname => 'char', prorettype => 'char', proargtypes => 'int4',
-  prosrc => 'i4tochar' },
+  prosrc => 'i4tochar', proerrorsafe => 't' },
 
 { oid => '79',
   proname => 'nameregexeq', prosupport => 'textregexeq_support',
@@ -410,7 +410,7 @@
   prosrc => 'on_ppath' },
 { oid => '138',
   proname => 'box_center', prorettype => 'point', proargtypes => 'box',
-  prosrc => 'box_center' },
+  prosrc => 'box_center', proerrorsafe => 't' },
 { oid => '139',
   descr => 'restriction selectivity for area-comparison operators',
   proname => 'areasel', provolatile => 's', prorettype => 'float8',
@@ -663,10 +663,10 @@
 
 { oid => '225',
   proname => 'lseg_center', prorettype => 'point', proargtypes => 'lseg',
-  prosrc => 'lseg_center' },
+  prosrc => 'lseg_center', proerrorsafe => 't' },
 { oid => '227',
   proname => 'poly_center', prorettype => 'point', proargtypes => 'polygon',
-  prosrc => 'poly_center' },
+  prosrc => 'poly_center', proerrorsafe => 't' },
 
 { oid => '228', descr => 'round to nearest integer',
   proname => 'dround', prorettype => 'float8', proargtypes => 'float8',
@@ -703,16 +703,16 @@
   prosrc => 'dlog1' },
 { oid => '235', descr => 'convert int2 to float8',
   proname => 'float8', proleakproof => 't', prorettype => 'float8',
-  proargtypes => 'int2', prosrc => 'i2tod' },
+  proargtypes => 'int2', prosrc => 'i2tod', proerrorsafe => 't' },
 { oid => '236', descr => 'convert int2 to float4',
   proname => 'float4', proleakproof => 't', prorettype => 'float4',
-  proargtypes => 'int2', prosrc => 'i2tof' },
+  proargtypes => 'int2', prosrc => 'i2tof', proerrorsafe => 't' },
 { oid => '237', descr => 'convert float8 to int2',
   proname => 'int2', prorettype => 'int2', proargtypes => 'float8',
-  prosrc => 'dtoi2' },
+  prosrc => 'dtoi2', proerrorsafe => 't' },
 { oid => '238', descr => 'convert float4 to int2',
   proname => 'int2', prorettype => 'int2', proargtypes => 'float4',
-  prosrc => 'ftoi2' },
+  prosrc => 'ftoi2', proerrorsafe => 't' },
 { oid => '239',
   proname => 'line_distance', prorettype => 'float8',
   proargtypes => 'line line', prosrc => 'line_distance' },
@@ -884,28 +884,28 @@
 
 { oid => '311', descr => 'convert float4 to float8',
   proname => 'float8', proleakproof => 't', prorettype => 'float8',
-  proargtypes => 'float4', prosrc => 'ftod' },
+  proargtypes => 'float4', prosrc => 'ftod', proerrorsafe => 't' },
 { oid => '312', descr => 'convert float8 to float4',
   proname => 'float4', prorettype => 'float4', proargtypes => 'float8',
-  prosrc => 'dtof' },
+  prosrc => 'dtof', proerrorsafe => 't' },
 { oid => '313', descr => 'convert int2 to int4',
   proname => 'int4', proleakproof => 't', prorettype => 'int4',
-  proargtypes => 'int2', prosrc => 'i2toi4' },
+  proargtypes => 'int2', prosrc => 'i2toi4', proerrorsafe => 't' },
 { oid => '314', descr => 'convert int4 to int2',
   proname => 'int2', prorettype => 'int2', proargtypes => 'int4',
-  prosrc => 'i4toi2' },
+  prosrc => 'i4toi2', proerrorsafe => 't' },
 { oid => '316', descr => 'convert int4 to float8',
   proname => 'float8', proleakproof => 't', prorettype => 'float8',
-  proargtypes => 'int4', prosrc => 'i4tod' },
+  proargtypes => 'int4', prosrc => 'i4tod', proerrorsafe => 't' },
 { oid => '317', descr => 'convert float8 to int4',
   proname => 'int4', prorettype => 'int4', proargtypes => 'float8',
-  prosrc => 'dtoi4' },
+  prosrc => 'dtoi4', proerrorsafe => 't' },
 { oid => '318', descr => 'convert int4 to float4',
   proname => 'float4', proleakproof => 't', prorettype => 'float4',
-  proargtypes => 'int4', prosrc => 'i4tof' },
+  proargtypes => 'int4', prosrc => 'i4tof', proerrorsafe => 't' },
 { oid => '319', descr => 'convert float4 to int4',
   proname => 'int4', prorettype => 'int4', proargtypes => 'float4',
-  prosrc => 'ftoi4' },
+  prosrc => 'ftoi4', proerrorsafe => 't' },
 
 # Table access method handlers
 { oid => '3', descr => 'row-oriented heap table access method handler',
@@ -1175,45 +1175,45 @@
 
 { oid => '401', descr => 'convert char(n) to text',
   proname => 'text', prorettype => 'text', proargtypes => 'bpchar',
-  prosrc => 'rtrim1' },
+  prosrc => 'rtrim1', proerrorsafe => 't' },
 { oid => '406', descr => 'convert name to text',
   proname => 'text', proleakproof => 't', prorettype => 'text',
-  proargtypes => 'name', prosrc => 'name_text' },
+  proargtypes => 'name', prosrc => 'name_text', proerrorsafe => 't' },
 { oid => '407', descr => 'convert text to name',
   proname => 'name', proleakproof => 't', prorettype => 'name',
-  proargtypes => 'text', prosrc => 'text_name' },
+  proargtypes => 'text', prosrc => 'text_name', proerrorsafe => 't' },
 { oid => '408', descr => 'convert name to char(n)',
   proname => 'bpchar', prorettype => 'bpchar', proargtypes => 'name',
-  prosrc => 'name_bpchar' },
+  prosrc => 'name_bpchar', proerrorsafe => 't' },
 { oid => '409', descr => 'convert char(n) to name',
   proname => 'name', proleakproof => 't', prorettype => 'name',
-  proargtypes => 'bpchar', prosrc => 'bpchar_name' },
+  proargtypes => 'bpchar', prosrc => 'bpchar_name', proerrorsafe => 't' },
 
 { oid => '6367', descr => 'convert int2 to bytea',
   proname => 'bytea', proleakproof => 't', prorettype => 'bytea',
-  proargtypes => 'int2', prosrc => 'int2_bytea' },
+  proargtypes => 'int2', prosrc => 'int2_bytea', proerrorsafe => 't' },
 { oid => '6368', descr => 'convert int4 to bytea',
   proname => 'bytea', proleakproof => 't', prorettype => 'bytea',
-  proargtypes => 'int4', prosrc => 'int4_bytea' },
+  proargtypes => 'int4', prosrc => 'int4_bytea', proerrorsafe => 't' },
 { oid => '6369', descr => 'convert int8 to bytea',
   proname => 'bytea', proleakproof => 't', prorettype => 'bytea',
-  proargtypes => 'int8', prosrc => 'int8_bytea' },
+  proargtypes => 'int8', prosrc => 'int8_bytea', proerrorsafe => 't' },
 { oid => '6370', descr => 'convert bytea to int2',
   proname => 'int2', prorettype => 'int2', proargtypes => 'bytea',
-  prosrc => 'bytea_int2' },
+  prosrc => 'bytea_int2', proerrorsafe => 't' },
 { oid => '6371', descr => 'convert bytea to int4',
   proname => 'int4', prorettype => 'int4', proargtypes => 'bytea',
-  prosrc => 'bytea_int4' },
+  prosrc => 'bytea_int4', proerrorsafe => 't' },
 { oid => '6372', descr => 'convert bytea to int8',
   proname => 'int8', prorettype => 'int8', proargtypes => 'bytea',
-  prosrc => 'bytea_int8' },
+  prosrc => 'bytea_int8', proerrorsafe => 't' },
 
 { oid => '6510', descr => 'convert uuid to bytea',
   proname => 'bytea', proleakproof => 't', prorettype => 'bytea',
-  proargtypes => 'uuid', prosrc => 'uuid_bytea' },
+  proargtypes => 'uuid', prosrc => 'uuid_bytea', proerrorsafe => 't' },
 { oid => '6511', descr => 'convert bytea to uuid',
   proname => 'uuid', prorettype => 'uuid', proargtypes => 'bytea',
-  prosrc => 'bytea_uuid' },
+  prosrc => 'bytea_uuid', proerrorsafe => 't' },
 
 { oid => '449', descr => 'hash',
   proname => 'hashint2', prorettype => 'int4', proargtypes => 'int2',
@@ -1432,16 +1432,16 @@
 
 { oid => '480', descr => 'convert int8 to int4',
   proname => 'int4', prorettype => 'int4', proargtypes => 'int8',
-  prosrc => 'int84' },
+  prosrc => 'int84', proerrorsafe => 't' },
 { oid => '481', descr => 'convert int4 to int8',
   proname => 'int8', proleakproof => 't', prorettype => 'int8',
-  proargtypes => 'int4', prosrc => 'int48' },
+  proargtypes => 'int4', prosrc => 'int48', proerrorsafe => 't' },
 { oid => '482', descr => 'convert int8 to float8',
   proname => 'float8', proleakproof => 't', prorettype => 'float8',
-  proargtypes => 'int8', prosrc => 'i8tod' },
+  proargtypes => 'int8', prosrc => 'i8tod', proerrorsafe => 't' },
 { oid => '483', descr => 'convert float8 to int8',
   proname => 'int8', prorettype => 'int8', proargtypes => 'float8',
-  prosrc => 'dtoi8' },
+  prosrc => 'dtoi8', proerrorsafe => 't' },
 
 # OIDS 500 - 599
 
@@ -1456,17 +1456,17 @@
 
 { oid => '652', descr => 'convert int8 to float4',
   proname => 'float4', proleakproof => 't', prorettype => 'float4',
-  proargtypes => 'int8', prosrc => 'i8tof' },
+  proargtypes => 'int8', prosrc => 'i8tof', proerrorsafe => 't' },
 { oid => '653', descr => 'convert float4 to int8',
   proname => 'int8', prorettype => 'int8', proargtypes => 'float4',
-  prosrc => 'ftoi8' },
+  prosrc => 'ftoi8', proerrorsafe => 't' },
 
 { oid => '714', descr => 'convert int8 to int2',
   proname => 'int2', prorettype => 'int2', proargtypes => 'int8',
-  prosrc => 'int82' },
+  prosrc => 'int82', proerrorsafe => 't' },
 { oid => '754', descr => 'convert int2 to int8',
   proname => 'int8', proleakproof => 't', prorettype => 'int8',
-  proargtypes => 'int2', prosrc => 'int28' },
+  proargtypes => 'int2', prosrc => 'int28', proerrorsafe => 't' },
 
 { oid => '655',
   proname => 'namelt', proleakproof => 't', prorettype => 'bool',
@@ -1486,14 +1486,14 @@
 
 { oid => '668', descr => 'adjust char() to typmod length',
   proname => 'bpchar', prorettype => 'bpchar',
-  proargtypes => 'bpchar int4 bool', prosrc => 'bpchar' },
+  proargtypes => 'bpchar int4 bool', prosrc => 'bpchar', proerrorsafe => 't' },
 { oid => '3097', descr => 'planner support for varchar length coercion',
   proname => 'varchar_support', prorettype => 'internal',
   proargtypes => 'internal', prosrc => 'varchar_support' },
 { oid => '669', descr => 'adjust varchar() to typmod length',
   proname => 'varchar', prosupport => 'varchar_support',
   prorettype => 'varchar', proargtypes => 'varchar int4 bool',
-  prosrc => 'varchar' },
+  prosrc => 'varchar', proerrorsafe => 't' },
 
 { oid => '619',
   proname => 'oidvectorne', proleakproof => 't', prorettype => 'bool',
@@ -1906,7 +1906,7 @@
 
 { oid => '860', descr => 'convert char to char(n)',
   proname => 'bpchar', prorettype => 'bpchar', proargtypes => 'char',
-  prosrc => 'char_bpchar' },
+  prosrc => 'char_bpchar', proerrorsafe => 't' },
 
 { oid => '861', descr => 'name of the current database',
   proname => 'current_database', provolatile => 's', prorettype => 'name',
@@ -2000,13 +2000,13 @@
   proargtypes => 'money', prosrc => 'cash_numeric' },
 { oid => '3824', descr => 'convert numeric to money',
   proname => 'money', provolatile => 's', prorettype => 'money',
-  proargtypes => 'numeric', prosrc => 'numeric_cash' },
+  proargtypes => 'numeric', prosrc => 'numeric_cash', proerrorsafe => 't' },
 { oid => '3811', descr => 'convert int4 to money',
   proname => 'money', provolatile => 's', prorettype => 'money',
-  proargtypes => 'int4', prosrc => 'int4_cash' },
+  proargtypes => 'int4', prosrc => 'int4_cash', proerrorsafe => 't' },
 { oid => '3812', descr => 'convert int8 to money',
   proname => 'money', provolatile => 's', prorettype => 'money',
-  proargtypes => 'int8', prosrc => 'int8_cash' },
+  proargtypes => 'int8', prosrc => 'int8_cash', proerrorsafe => 't' },
 
 # OIDS 900 - 999
 
@@ -2040,10 +2040,10 @@
 
 { oid => '944', descr => 'convert text to char',
   proname => 'char', prorettype => 'char', proargtypes => 'text',
-  prosrc => 'text_char' },
+  prosrc => 'text_char', proerrorsafe => 't' },
 { oid => '946', descr => 'convert char to text',
   proname => 'text', prorettype => 'text', proargtypes => 'char',
-  prosrc => 'char_text' },
+  prosrc => 'char_text', proerrorsafe => 't' },
 
 { oid => '952', descr => 'large object open',
   proname => 'lo_open', provolatile => 'v', proparallel => 'u',
@@ -2142,7 +2142,7 @@
   prosrc => 'boxes_bound_box' },
 { oid => '981', descr => 'box diagonal',
   proname => 'diagonal', prorettype => 'lseg', proargtypes => 'box',
-  prosrc => 'box_diagonal' },
+  prosrc => 'box_diagonal', proerrorsafe => 't' },
 { oid => '982',
   proname => 'path_n_lt', prorettype => 'bool', proargtypes => 'path path',
   prosrc => 'path_n_lt' },
@@ -2495,7 +2495,7 @@
   prosrc => 'extract_interval' },
 { oid => '1174', descr => 'convert date to timestamp with time zone',
   proname => 'timestamptz', provolatile => 's', prorettype => 'timestamptz',
-  proargtypes => 'date', prosrc => 'date_timestamptz' },
+  proargtypes => 'date', prosrc => 'date_timestamptz', proerrorsafe => 't' },
 { oid => '2711',
   descr => 'promote groups of 24 hours to numbers of days and promote groups of 30 days to numbers of months',
   proname => 'justify_interval', prorettype => 'interval',
@@ -2512,7 +2512,7 @@
   prosrc => 'see system_functions.sql' },
 { oid => '1178', descr => 'convert timestamp with time zone to date',
   proname => 'date', provolatile => 's', prorettype => 'date',
-  proargtypes => 'timestamptz', prosrc => 'timestamptz_date' },
+  proargtypes => 'timestamptz', prosrc => 'timestamptz_date', proerrorsafe => 't' },
 { oid => '1181',
   descr => 'age of a transaction ID, in transactions before current transaction',
   proname => 'age', provolatile => 's', proparallel => 'r',
@@ -2573,7 +2573,7 @@
 { oid => '1200', descr => 'adjust interval precision',
   proname => 'interval', prosupport => 'interval_support',
   prorettype => 'interval', proargtypes => 'interval int4',
-  prosrc => 'interval_scale' },
+  prosrc => 'interval_scale', proerrorsafe => 't' },
 
 { oid => '1215', descr => 'get description for object id and catalog name',
   proname => 'obj_description', prolang => 'sql', procost => '100',
@@ -2711,10 +2711,10 @@
 
 { oid => '1287', descr => 'convert int8 to oid',
   proname => 'oid', prorettype => 'oid', proargtypes => 'int8',
-  prosrc => 'i8tooid' },
+  prosrc => 'i8tooid', proerrorsafe => 't' },
 { oid => '1288', descr => 'convert oid to int8',
   proname => 'int8', proleakproof => 't', prorettype => 'int8',
-  proargtypes => 'oid', prosrc => 'oidtoi8' },
+  proargtypes => 'oid', prosrc => 'oidtoi8', proerrorsafe => 't' },
 
 { oid => '1291',
   descr => 'trigger to suppress updates when new and old records match',
@@ -2866,7 +2866,7 @@
   proargtypes => 'interval interval', prosrc => 'interval_cmp' },
 { oid => '1316', descr => 'convert timestamp to time',
   proname => 'time', prorettype => 'time', proargtypes => 'timestamp',
-  prosrc => 'timestamp_time' },
+  prosrc => 'timestamp_time', proerrorsafe => 't' },
 
 { oid => '1317', descr => 'length',
   proname => 'length', prorettype => 'int4', proargtypes => 'text',
@@ -2978,7 +2978,7 @@
 
 { oid => '1370', descr => 'convert time to interval',
   proname => 'interval', proleakproof => 't', prorettype => 'interval',
-  proargtypes => 'time', prosrc => 'time_interval' },
+  proargtypes => 'time', prosrc => 'time_interval', proerrorsafe => 't' },
 { oid => '1372', descr => 'character length',
   proname => 'char_length', prorettype => 'int4', proargtypes => 'bpchar',
   prosrc => 'bpcharlen' },
@@ -3027,7 +3027,7 @@
 { oid => '1388',
   descr => 'convert timestamp with time zone to time with time zone',
   proname => 'timetz', provolatile => 's', prorettype => 'timetz',
-  proargtypes => 'timestamptz', prosrc => 'timestamptz_timetz' },
+  proargtypes => 'timestamptz', prosrc => 'timestamptz_timetz', proerrorsafe => 't' },
 
 { oid => '1373', descr => 'finite date?',
   proname => 'isfinite', prorettype => 'bool', proargtypes => 'date',
@@ -3062,10 +3062,10 @@
 
 { oid => '1400', descr => 'convert varchar to name',
   proname => 'name', proleakproof => 't', prorettype => 'name',
-  proargtypes => 'varchar', prosrc => 'text_name' },
+  proargtypes => 'varchar', prosrc => 'text_name', proerrorsafe => 't' },
 { oid => '1401', descr => 'convert name to varchar',
   proname => 'varchar', proleakproof => 't', prorettype => 'varchar',
-  proargtypes => 'name', prosrc => 'name_text' },
+  proargtypes => 'name', prosrc => 'name_text', proerrorsafe => 't' },
 
 { oid => '1402', descr => 'current schema name',
   proname => 'current_schema', provolatile => 's', proparallel => 'u',
@@ -3113,11 +3113,11 @@
   prosrc => 'line_horizontal' },
 { oid => '1416', descr => 'center of',
   proname => 'point', prorettype => 'point', proargtypes => 'circle',
-  prosrc => 'circle_center' },
+  prosrc => 'circle_center', proerrorsafe => 't' },
 
 { oid => '1419', descr => 'convert interval to time',
   proname => 'time', prorettype => 'time', proargtypes => 'interval',
-  prosrc => 'interval_time' },
+  prosrc => 'interval_time', proerrorsafe => 't' },
 
 { oid => '1421', descr => 'convert points to box',
   proname => 'box', prorettype => 'box', proargtypes => 'point point',
@@ -3200,16 +3200,16 @@
   prosrc => 'poly_npoints' },
 { oid => '1446', descr => 'convert polygon to bounding box',
   proname => 'box', prorettype => 'box', proargtypes => 'polygon',
-  prosrc => 'poly_box' },
+  prosrc => 'poly_box', proerrorsafe => 't' },
 { oid => '1447', descr => 'convert polygon to path',
   proname => 'path', prorettype => 'path', proargtypes => 'polygon',
-  prosrc => 'poly_path' },
+  prosrc => 'poly_path', proerrorsafe => 't' },
 { oid => '1448', descr => 'convert box to polygon',
   proname => 'polygon', prorettype => 'polygon', proargtypes => 'box',
-  prosrc => 'box_poly' },
+  prosrc => 'box_poly', proerrorsafe => 't' },
 { oid => '1449', descr => 'convert path to polygon',
   proname => 'polygon', prorettype => 'polygon', proargtypes => 'path',
-  prosrc => 'path_poly' },
+  prosrc => 'path_poly', proerrorsafe => 't' },
 
 { oid => '1450', descr => 'I/O',
   proname => 'circle_in', prorettype => 'circle', proargtypes => 'cstring',
@@ -3279,13 +3279,13 @@
   proargtypes => 'circle circle', prosrc => 'circle_distance' },
 { oid => '1472',
   proname => 'circle_center', prorettype => 'point', proargtypes => 'circle',
-  prosrc => 'circle_center' },
+  prosrc => 'circle_center', proerrorsafe => 't' },
 { oid => '1473', descr => 'convert point and radius to circle',
   proname => 'circle', prorettype => 'circle', proargtypes => 'point float8',
   prosrc => 'cr_circle' },
 { oid => '1474', descr => 'convert polygon to circle',
   proname => 'circle', prorettype => 'circle', proargtypes => 'polygon',
-  prosrc => 'poly_circle' },
+  prosrc => 'poly_circle', proerrorsafe => 't' },
 { oid => '1475', descr => 'convert vertex count and circle to polygon',
   proname => 'polygon', prorettype => 'polygon', proargtypes => 'int4 circle',
   prosrc => 'circle_poly' },
@@ -3300,13 +3300,13 @@
   proargtypes => 'point circle', prosrc => 'pt_contained_circle' },
 { oid => '4091', descr => 'convert point to empty box',
   proname => 'box', prorettype => 'box', proargtypes => 'point',
-  prosrc => 'point_box' },
+  prosrc => 'point_box', proerrorsafe => 't' },
 { oid => '1479', descr => 'convert box to circle',
   proname => 'circle', prorettype => 'circle', proargtypes => 'box',
-  prosrc => 'box_circle' },
+  prosrc => 'box_circle', proerrorsafe => 't' },
 { oid => '1480', descr => 'convert circle to box',
   proname => 'box', prorettype => 'box', proargtypes => 'circle',
-  prosrc => 'circle_box' },
+  prosrc => 'circle_box', proerrorsafe => 't' },
 
 { oid => '1482',
   proname => 'lseg_ne', proleakproof => 't', prorettype => 'bool',
@@ -3375,25 +3375,25 @@
 
 { oid => '1532', descr => 'center of',
   proname => 'point', prorettype => 'point', proargtypes => 'lseg',
-  prosrc => 'lseg_center' },
+  prosrc => 'lseg_center', proerrorsafe => 't' },
 { oid => '1534', descr => 'center of',
   proname => 'point', prorettype => 'point', proargtypes => 'box',
-  prosrc => 'box_center' },
+  prosrc => 'box_center', proerrorsafe => 't' },
 { oid => '1540', descr => 'center of',
   proname => 'point', prorettype => 'point', proargtypes => 'polygon',
-  prosrc => 'poly_center' },
+  prosrc => 'poly_center', proerrorsafe => 't' },
 { oid => '1541', descr => 'diagonal of',
   proname => 'lseg', prorettype => 'lseg', proargtypes => 'box',
-  prosrc => 'box_diagonal' },
+  prosrc => 'box_diagonal', proerrorsafe => 't' },
 { oid => '1542', descr => 'center of',
   proname => 'center', prorettype => 'point', proargtypes => 'box',
-  prosrc => 'box_center' },
+  prosrc => 'box_center', proerrorsafe => 't' },
 { oid => '1543', descr => 'center of',
   proname => 'center', prorettype => 'point', proargtypes => 'circle',
-  prosrc => 'circle_center' },
+  prosrc => 'circle_center', proerrorsafe => 't' },
 { oid => '1544', descr => 'convert circle to 12-vertex polygon',
   proname => 'polygon', prorettype => 'polygon', proargtypes => 'circle',
-  prosrc => 'circle_to_poly' },
+  prosrc => 'circle_to_poly', proerrorsafe => 't' },
 { oid => '1545', descr => 'number of points',
   proname => 'npoints', prorettype => 'int4', proargtypes => 'path',
   prosrc => 'path_npoints' },
@@ -3756,7 +3756,7 @@
   prosrc => 'ltrim1' },
 { oid => '882', descr => 'trim spaces from right end of string',
   proname => 'rtrim', prorettype => 'text', proargtypes => 'text',
-  prosrc => 'rtrim1' },
+  prosrc => 'rtrim1', proerrorsafe => 't' },
 { oid => '883', descr => 'extract portion of string',
   proname => 'substr', prorettype => 'text', proargtypes => 'text int4',
   prosrc => 'text_substr_no_len' },
@@ -4198,20 +4198,20 @@
   prosrc => 'bitoctetlength' },
 { oid => '1683', descr => 'convert int4 to bitstring',
   proname => 'bit', prorettype => 'bit', proargtypes => 'int4 int4',
-  prosrc => 'bitfromint4' },
+  prosrc => 'bitfromint4', proerrorsafe => 't' },
 { oid => '1684', descr => 'convert bitstring to int4',
   proname => 'int4', prorettype => 'int4', proargtypes => 'bit',
-  prosrc => 'bittoint4' },
+  prosrc => 'bittoint4', proerrorsafe => 't' },
 
 { oid => '1685', descr => 'adjust bit() to typmod length',
   proname => 'bit', prorettype => 'bit', proargtypes => 'bit int4 bool',
-  prosrc => 'bit' },
+  prosrc => 'bit', proerrorsafe => 't' },
 { oid => '3158', descr => 'planner support for varbit length coercion',
   proname => 'varbit_support', prorettype => 'internal',
   proargtypes => 'internal', prosrc => 'varbit_support' },
 { oid => '1687', descr => 'adjust varbit() to typmod length',
   proname => 'varbit', prosupport => 'varbit_support', prorettype => 'varbit',
-  proargtypes => 'varbit int4 bool', prosrc => 'varbit' },
+  proargtypes => 'varbit int4 bool', prosrc => 'varbit', proerrorsafe => 't' },
 
 { oid => '1698', descr => 'position of sub-bitstring',
   proname => 'position', prorettype => 'int4', proargtypes => 'bit bit',
@@ -4326,10 +4326,10 @@
   proargtypes => 'macaddr8 macaddr8', prosrc => 'macaddr8_or' },
 { oid => '4123', descr => 'convert macaddr to macaddr8',
   proname => 'macaddr8', proleakproof => 't', prorettype => 'macaddr8',
-  proargtypes => 'macaddr', prosrc => 'macaddrtomacaddr8' },
+  proargtypes => 'macaddr', prosrc => 'macaddrtomacaddr8', proerrorsafe => 't' },
 { oid => '4124', descr => 'convert macaddr8 to macaddr',
   proname => 'macaddr', prorettype => 'macaddr', proargtypes => 'macaddr8',
-  prosrc => 'macaddr8tomacaddr' },
+  prosrc => 'macaddr8tomacaddr', proerrorsafe => 't' },
 { oid => '4125', descr => 'set 7th bit in macaddr8',
   proname => 'macaddr8_set7bit', prorettype => 'macaddr8',
   proargtypes => 'macaddr8', prosrc => 'macaddr8_set7bit' },
@@ -4434,13 +4434,13 @@
   prosrc => 'network_host' },
 { oid => '730', descr => 'show all parts of inet/cidr value',
   proname => 'text', prorettype => 'text', proargtypes => 'inet',
-  prosrc => 'network_show' },
+  prosrc => 'network_show', proerrorsafe => 't' },
 { oid => '1362', descr => 'hostmask of address',
   proname => 'hostmask', prorettype => 'inet', proargtypes => 'inet',
   prosrc => 'network_hostmask' },
 { oid => '1715', descr => 'convert inet to cidr',
   proname => 'cidr', prorettype => 'cidr', proargtypes => 'inet',
-  prosrc => 'inet_to_cidr' },
+  prosrc => 'inet_to_cidr', proerrorsafe => 't' },
 
 { oid => '2196', descr => 'inet address of the client',
   proname => 'inet_client_addr', proisstrict => 'f', provolatile => 's',
@@ -4593,7 +4593,7 @@
   proargtypes => 'internal', prosrc => 'numeric_support' },
 { oid => '1703', descr => 'adjust numeric to typmod precision/scale',
   proname => 'numeric', prosupport => 'numeric_support',
-  prorettype => 'numeric', proargtypes => 'numeric int4', prosrc => 'numeric' },
+  prorettype => 'numeric', proargtypes => 'numeric int4', prosrc => 'numeric', proerrorsafe => 't' },
 { oid => '1704',
   proname => 'numeric_abs', prorettype => 'numeric', proargtypes => 'numeric',
   prosrc => 'numeric_abs' },
@@ -4711,7 +4711,7 @@
   prosrc => 'numeric_trim_scale' },
 { oid => '1740', descr => 'convert int4 to numeric',
   proname => 'numeric', proleakproof => 't', prorettype => 'numeric',
-  proargtypes => 'int4', prosrc => 'int4_numeric' },
+  proargtypes => 'int4', prosrc => 'int4_numeric', proerrorsafe => 't' },
 { oid => '1741', descr => 'base 10 logarithm',
   proname => 'log', prolang => 'sql', prorettype => 'numeric',
   proargtypes => 'numeric', prosrc => 'see system_functions.sql' },
@@ -4720,19 +4720,19 @@
   proargtypes => 'numeric', prosrc => 'see system_functions.sql' },
 { oid => '1742', descr => 'convert float4 to numeric',
   proname => 'numeric', proleakproof => 't', prorettype => 'numeric',
-  proargtypes => 'float4', prosrc => 'float4_numeric' },
+  proargtypes => 'float4', prosrc => 'float4_numeric', proerrorsafe => 't' },
 { oid => '1743', descr => 'convert float8 to numeric',
   proname => 'numeric', proleakproof => 't', prorettype => 'numeric',
-  proargtypes => 'float8', prosrc => 'float8_numeric' },
+  proargtypes => 'float8', prosrc => 'float8_numeric', proerrorsafe => 't' },
 { oid => '1744', descr => 'convert numeric to int4',
   proname => 'int4', prorettype => 'int4', proargtypes => 'numeric',
-  prosrc => 'numeric_int4' },
+  prosrc => 'numeric_int4', proerrorsafe => 't' },
 { oid => '1745', descr => 'convert numeric to float4',
   proname => 'float4', prorettype => 'float4', proargtypes => 'numeric',
-  prosrc => 'numeric_float4' },
+  prosrc => 'numeric_float4', proerrorsafe => 't' },
 { oid => '1746', descr => 'convert numeric to float8',
   proname => 'float8', prorettype => 'float8', proargtypes => 'numeric',
-  prosrc => 'numeric_float8' },
+  prosrc => 'numeric_float8', proerrorsafe => 't' },
 { oid => '1973', descr => 'trunc(x/y)',
   proname => 'div', prorettype => 'numeric', proargtypes => 'numeric numeric',
   prosrc => 'numeric_div_trunc' },
@@ -4777,41 +4777,41 @@
   proargtypes => 'numeric', prosrc => 'numeric_uminus' },
 { oid => '1779', descr => 'convert numeric to int8',
   proname => 'int8', prorettype => 'int8', proargtypes => 'numeric',
-  prosrc => 'numeric_int8' },
+  prosrc => 'numeric_int8', proerrorsafe => 't' },
 { oid => '1781', descr => 'convert int8 to numeric',
   proname => 'numeric', proleakproof => 't', prorettype => 'numeric',
-  proargtypes => 'int8', prosrc => 'int8_numeric' },
+  proargtypes => 'int8', prosrc => 'int8_numeric', proerrorsafe => 't' },
 { oid => '1782', descr => 'convert int2 to numeric',
   proname => 'numeric', proleakproof => 't', prorettype => 'numeric',
-  proargtypes => 'int2', prosrc => 'int2_numeric' },
+  proargtypes => 'int2', prosrc => 'int2_numeric', proerrorsafe => 't' },
 { oid => '1783', descr => 'convert numeric to int2',
   proname => 'int2', prorettype => 'int2', proargtypes => 'numeric',
-  prosrc => 'numeric_int2' },
+  prosrc => 'numeric_int2', proerrorsafe => 't' },
 { oid => '6103', descr => 'convert numeric to pg_lsn',
   proname => 'pg_lsn', prorettype => 'pg_lsn', proargtypes => 'numeric',
   prosrc => 'numeric_pg_lsn' },
 
 { oid => '3556', descr => 'convert jsonb to boolean',
   proname => 'bool', prorettype => 'bool', proargtypes => 'jsonb',
-  prosrc => 'jsonb_bool' },
+  prosrc => 'jsonb_bool', proerrorsafe => 't' },
 { oid => '3449', descr => 'convert jsonb to numeric',
   proname => 'numeric', prorettype => 'numeric', proargtypes => 'jsonb',
-  prosrc => 'jsonb_numeric' },
+  prosrc => 'jsonb_numeric', proerrorsafe => 't' },
 { oid => '3450', descr => 'convert jsonb to int2',
   proname => 'int2', prorettype => 'int2', proargtypes => 'jsonb',
-  prosrc => 'jsonb_int2' },
+  prosrc => 'jsonb_int2', proerrorsafe => 't' },
 { oid => '3451', descr => 'convert jsonb to int4',
   proname => 'int4', prorettype => 'int4', proargtypes => 'jsonb',
-  prosrc => 'jsonb_int4' },
+  prosrc => 'jsonb_int4', proerrorsafe => 't' },
 { oid => '3452', descr => 'convert jsonb to int8',
   proname => 'int8', prorettype => 'int8', proargtypes => 'jsonb',
-  prosrc => 'jsonb_int8' },
+  prosrc => 'jsonb_int8', proerrorsafe => 't' },
 { oid => '3453', descr => 'convert jsonb to float4',
   proname => 'float4', prorettype => 'float4', proargtypes => 'jsonb',
-  prosrc => 'jsonb_float4' },
+  prosrc => 'jsonb_float4', proerrorsafe => 't' },
 { oid => '2580', descr => 'convert jsonb to float8',
   proname => 'float8', prorettype => 'float8', proargtypes => 'jsonb',
-  prosrc => 'jsonb_float8' },
+  prosrc => 'jsonb_float8', proerrorsafe => 't' },
 
 # formatting
 { oid => '1770', descr => 'format timestamp with time zone to text',
@@ -6376,7 +6376,7 @@
 { oid => '1961', descr => 'adjust timestamp precision',
   proname => 'timestamp', prosupport => 'timestamp_support',
   prorettype => 'timestamp', proargtypes => 'timestamp int4',
-  prosrc => 'timestamp_scale' },
+  prosrc => 'timestamp_scale', proerrorsafe => 't' },
 
 { oid => '1965', descr => 'larger of two',
   proname => 'oidlarger', prorettype => 'oid', proargtypes => 'oid oid',
@@ -6388,13 +6388,13 @@
 { oid => '1967', descr => 'adjust timestamptz precision',
   proname => 'timestamptz', prosupport => 'timestamp_support',
   prorettype => 'timestamptz', proargtypes => 'timestamptz int4',
-  prosrc => 'timestamptz_scale' },
+  prosrc => 'timestamptz_scale', proerrorsafe => 't' },
 { oid => '1968', descr => 'adjust time precision',
   proname => 'time', prosupport => 'time_support', prorettype => 'time',
-  proargtypes => 'time int4', prosrc => 'time_scale' },
+  proargtypes => 'time int4', prosrc => 'time_scale', proerrorsafe => 't' },
 { oid => '1969', descr => 'adjust time with time zone precision',
   proname => 'timetz', prosupport => 'time_support', prorettype => 'timetz',
-  proargtypes => 'timetz int4', prosrc => 'timetz_scale' },
+  proargtypes => 'timetz int4', prosrc => 'timetz_scale', proerrorsafe => 't' },
 
 { oid => '2003',
   proname => 'textanycat', prolang => 'sql', provolatile => 's',
@@ -6453,7 +6453,7 @@
 
 { oid => '2019', descr => 'convert timestamp with time zone to time',
   proname => 'time', provolatile => 's', prorettype => 'time',
-  proargtypes => 'timestamptz', prosrc => 'timestamptz_time' },
+  proargtypes => 'timestamptz', prosrc => 'timestamptz_time', proerrorsafe => 't' },
 { oid => '2020', descr => 'truncate timestamp to specified units',
   proname => 'date_trunc', prorettype => 'timestamp',
   proargtypes => 'text timestamp', prosrc => 'timestamp_trunc' },
@@ -6475,19 +6475,19 @@
   proargtypes => 'text timestamp', prosrc => 'extract_timestamp' },
 { oid => '2024', descr => 'convert date to timestamp',
   proname => 'timestamp', prorettype => 'timestamp', proargtypes => 'date',
-  prosrc => 'date_timestamp' },
+  prosrc => 'date_timestamp', proerrorsafe => 't' },
 { oid => '2025', descr => 'convert date and time to timestamp',
   proname => 'timestamp', prorettype => 'timestamp', proargtypes => 'date time',
   prosrc => 'datetime_timestamp' },
 { oid => '2027', descr => 'convert timestamp with time zone to timestamp',
   proname => 'timestamp', provolatile => 's', prorettype => 'timestamp',
-  proargtypes => 'timestamptz', prosrc => 'timestamptz_timestamp' },
+  proargtypes => 'timestamptz', prosrc => 'timestamptz_timestamp', proerrorsafe => 't' },
 { oid => '2028', descr => 'convert timestamp to timestamp with time zone',
   proname => 'timestamptz', provolatile => 's', prorettype => 'timestamptz',
-  proargtypes => 'timestamp', prosrc => 'timestamp_timestamptz' },
+  proargtypes => 'timestamp', prosrc => 'timestamp_timestamptz', proerrorsafe => 't' },
 { oid => '2029', descr => 'convert timestamp to date',
   proname => 'date', prorettype => 'date', proargtypes => 'timestamp',
-  prosrc => 'timestamp_date' },
+  prosrc => 'timestamp_date', proerrorsafe => 't' },
 { oid => '2031',
   proname => 'timestamp_mi', prorettype => 'interval',
   proargtypes => 'timestamp timestamp', prosrc => 'timestamp_mi' },
@@ -6573,10 +6573,10 @@
 
 { oid => '2046', descr => 'convert time with time zone to time',
   proname => 'time', prorettype => 'time', proargtypes => 'timetz',
-  prosrc => 'timetz_time' },
+  prosrc => 'timetz_time', proerrorsafe => 't' },
 { oid => '2047', descr => 'convert time to time with time zone',
   proname => 'timetz', provolatile => 's', prorettype => 'timetz',
-  proargtypes => 'time', prosrc => 'time_timetz' },
+  proargtypes => 'time', prosrc => 'time_timetz', proerrorsafe => 't' },
 { oid => '2048', descr => 'finite timestamp?',
   proname => 'isfinite', prorettype => 'bool', proargtypes => 'timestamp',
   prosrc => 'timestamp_finite' },
@@ -6635,10 +6635,10 @@
 
 { oid => '2075', descr => 'convert int8 to bitstring',
   proname => 'bit', prorettype => 'bit', proargtypes => 'int8 int4',
-  prosrc => 'bitfromint8' },
+  prosrc => 'bitfromint8', proerrorsafe => 't' },
 { oid => '2076', descr => 'convert bitstring to int8',
   proname => 'int8', prorettype => 'int8', proargtypes => 'bit',
-  prosrc => 'bittoint8' },
+  prosrc => 'bittoint8', proerrorsafe => 't' },
 
 { oid => '2077', descr => 'SHOW X as a function',
   proname => 'current_setting', provolatile => 's', prorettype => 'text',
@@ -7046,7 +7046,7 @@
 
 { oid => '2971', descr => 'convert boolean to text',
   proname => 'text', prorettype => 'text', proargtypes => 'bool',
-  prosrc => 'booltext' },
+  prosrc => 'booltext', proerrorsafe => 't' },
 
 # Aggregates (moved here from pg_aggregate for 7.3)
 
@@ -7605,7 +7605,7 @@
   proargtypes => 'text', prosrc => 'to_regtypemod' },
 { oid => '1079', descr => 'convert text to regclass',
   proname => 'regclass', provolatile => 's', prorettype => 'regclass',
-  proargtypes => 'text', prosrc => 'text_regclass' },
+  proargtypes => 'text', prosrc => 'text_regclass', proerrorsafe => 't' },
 
 { oid => '4098', descr => 'I/O',
   proname => 'regrolein', provolatile => 's', prorettype => 'regrole',
@@ -8952,10 +8952,10 @@
 
 { oid => '2557', descr => 'convert int4 to boolean',
   proname => 'bool', proleakproof => 't', prorettype => 'bool',
-  proargtypes => 'int4', prosrc => 'int4_bool' },
+  proargtypes => 'int4', prosrc => 'int4_bool', proerrorsafe => 't' },
 { oid => '2558', descr => 'convert boolean to int4',
   proname => 'int4', proleakproof => 't', prorettype => 'int4',
-  proargtypes => 'bool', prosrc => 'bool_int4' },
+  proargtypes => 'bool', prosrc => 'bool_int4', proerrorsafe => 't' },
 { oid => '2559', descr => 'current value from last used sequence',
   proname => 'lastval', provolatile => 'v', proparallel => 'u',
   prorettype => 'int8', proargtypes => '', prosrc => 'lastval' },
@@ -9336,7 +9336,7 @@
 { oid => '2896',
   descr => 'perform a non-validating parse of a character string to produce an XML value',
   proname => 'xml', provolatile => 's', prorettype => 'xml',
-  proargtypes => 'text', prosrc => 'texttoxml' },
+  proargtypes => 'text', prosrc => 'texttoxml', proerrorsafe => 't' },
 { oid => '2897', descr => 'validate an XML value',
   proname => 'xmlvalidate', prorettype => 'bool', proargtypes => 'xml text',
   prosrc => 'xmlvalidate' },
@@ -11479,7 +11479,7 @@
   proargtypes => '', prosrc => 'multirange_constructor0' },
 { oid => '4281', descr => 'int4multirange constructor',
   proname => 'int4multirange', prorettype => 'int4multirange',
-  proargtypes => 'int4range', prosrc => 'multirange_constructor1' },
+  proargtypes => 'int4range', prosrc => 'multirange_constructor1', proerrorsafe => 't' },
 { oid => '4282', descr => 'int4multirange constructor',
   proname => 'int4multirange', provariadic => 'int4range',
   prorettype => 'int4multirange', proargtypes => '_int4range',
@@ -11490,7 +11490,7 @@
   prosrc => 'multirange_constructor0' },
 { oid => '4284', descr => 'nummultirange constructor',
   proname => 'nummultirange', prorettype => 'nummultirange',
-  proargtypes => 'numrange', prosrc => 'multirange_constructor1' },
+  proargtypes => 'numrange', prosrc => 'multirange_constructor1', proerrorsafe => 't' },
 { oid => '4285', descr => 'nummultirange constructor',
   proname => 'nummultirange', provariadic => 'numrange',
   prorettype => 'nummultirange', proargtypes => '_numrange',
@@ -11501,7 +11501,7 @@
   prosrc => 'multirange_constructor0' },
 { oid => '4287', descr => 'tsmultirange constructor',
   proname => 'tsmultirange', prorettype => 'tsmultirange',
-  proargtypes => 'tsrange', prosrc => 'multirange_constructor1' },
+  proargtypes => 'tsrange', prosrc => 'multirange_constructor1', proerrorsafe => 't' },
 { oid => '4288', descr => 'tsmultirange constructor',
   proname => 'tsmultirange', provariadic => 'tsrange',
   prorettype => 'tsmultirange', proargtypes => '_tsrange',
@@ -11512,7 +11512,7 @@
   proargtypes => '', prosrc => 'multirange_constructor0' },
 { oid => '4290', descr => 'tstzmultirange constructor',
   proname => 'tstzmultirange', prorettype => 'tstzmultirange',
-  proargtypes => 'tstzrange', prosrc => 'multirange_constructor1' },
+  proargtypes => 'tstzrange', prosrc => 'multirange_constructor1', proerrorsafe => 't' },
 { oid => '4291', descr => 'tstzmultirange constructor',
   proname => 'tstzmultirange', provariadic => 'tstzrange',
   prorettype => 'tstzmultirange', proargtypes => '_tstzrange',
@@ -11523,7 +11523,7 @@
   proargtypes => '', prosrc => 'multirange_constructor0' },
 { oid => '4293', descr => 'datemultirange constructor',
   proname => 'datemultirange', prorettype => 'datemultirange',
-  proargtypes => 'daterange', prosrc => 'multirange_constructor1' },
+  proargtypes => 'daterange', prosrc => 'multirange_constructor1', proerrorsafe => 't' },
 { oid => '4294', descr => 'datemultirange constructor',
   proname => 'datemultirange', provariadic => 'daterange',
   prorettype => 'datemultirange', proargtypes => '_daterange',
@@ -11534,7 +11534,7 @@
   proargtypes => '', prosrc => 'multirange_constructor0' },
 { oid => '4296', descr => 'int8multirange constructor',
   proname => 'int8multirange', prorettype => 'int8multirange',
-  proargtypes => 'int8range', prosrc => 'multirange_constructor1' },
+  proargtypes => 'int8range', prosrc => 'multirange_constructor1', proerrorsafe => 't' },
 { oid => '4297', descr => 'int8multirange constructor',
   proname => 'int8multirange', provariadic => 'int8range',
   prorettype => 'int8multirange', proargtypes => '_int8range',
@@ -11542,7 +11542,7 @@
   prosrc => 'multirange_constructor2' },
 { oid => '4298', descr => 'anymultirange cast',
   proname => 'multirange', prorettype => 'anymultirange',
-  proargtypes => 'anyrange', prosrc => 'multirange_constructor1' },
+  proargtypes => 'anyrange', prosrc => 'multirange_constructor1', proerrorsafe => 't' },
 { oid => '4299', descr => 'aggregate transition function',
   proname => 'range_agg_transfn', proisstrict => 'f', prorettype => 'internal',
   proargtypes => 'internal anyrange', prosrc => 'range_agg_transfn' },
@@ -12727,7 +12727,7 @@
 # oid8 related functions
 { oid => '6436', descr => 'convert oid to oid8',
   proname => 'oid8', prorettype => 'oid8', proargtypes => 'oid',
-  prosrc => 'oidtooid8' },
+  prosrc => 'oidtooid8', proerrorsafe => 't' },
 { oid => '6438', descr => 'I/O',
   proname => 'oid8in', prorettype => 'oid8', proargtypes => 'cstring',
   prosrc => 'oid8in' },
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 48010e93313..84d8d143678 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -78,6 +78,9 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce
 	/* see PROPARALLEL_ categories below */
 	char		proparallel BKI_DEFAULT(s);
 
+	/* can report a soft error instead of aborting (ERROR SAFE) */
+	bool		proerrorsafe BKI_DEFAULT(f);
+
 	/* number of arguments */
 	/* Note: need not be given in pg_proc.dat; genbki.pl will compute it */
 	int16		pronargs;
@@ -209,6 +212,7 @@ extern ObjectAddress ProcedureCreate(const char *procedureName,
 									 bool isStrict,
 									 char volatility,
 									 char parallel,
+									 bool isErrorSafe,
 									 oidvector *parameterTypes,
 									 Datum allParameterTypes,
 									 Datum parameterModes,
diff --git a/src/test/regress/expected/create_function_sql.out b/src/test/regress/expected/create_function_sql.out
index 42524230d2b..f89536dbf75 100644
--- a/src/test/regress/expected/create_function_sql.out
+++ b/src/test/regress/expected/create_function_sql.out
@@ -176,7 +176,7 @@ RESET SESSION AUTHORIZATION;
 --
 CREATE FUNCTION functest_F_1(int) RETURNS bool LANGUAGE 'sql'
        AS 'SELECT $1 > 50';
-CREATE FUNCTION functest_F_2(int) RETURNS bool LANGUAGE 'sql'
+CREATE FUNCTION functest_F_2(int) RETURNS bool LANGUAGE 'sql' ERROR UNSAFE
        CALLED ON NULL INPUT AS 'SELECT $1 = 50';
 CREATE FUNCTION functest_F_3(int) RETURNS bool LANGUAGE 'sql'
        RETURNS NULL ON NULL INPUT AS 'SELECT $1 < 50';
@@ -197,6 +197,7 @@ SELECT proname, proisstrict FROM pg_proc
 
 ALTER FUNCTION functest_F_1(int) IMMUTABLE;	-- unrelated change, no effect
 ALTER FUNCTION functest_F_2(int) STRICT;
+ALTER FUNCTION functest_F_2(int) ERROR SAFE;
 ALTER FUNCTION functest_F_3(int) CALLED ON NULL INPUT;
 SELECT proname, proisstrict FROM pg_proc
        WHERE oid in ('functest_F_1'::regproc,
@@ -250,7 +251,7 @@ SELECT pg_get_functiondef('functest_F_2'::regproc);
  CREATE OR REPLACE FUNCTION temp_func_test.functest_f_2(integer)+
   RETURNS boolean                                               +
   LANGUAGE sql                                                  +
-  STRICT                                                        +
+  ERROR SAFE STRICT                                             +
  AS $function$SELECT $1 = 50$function$                          +
  
 (1 row)
@@ -259,7 +260,7 @@ SELECT pg_get_functiondef('functest_F_2'::regproc);
 -- SQL-standard body
 --
 CREATE FUNCTION functest_S_1(a text, b date) RETURNS boolean
-    LANGUAGE SQL
+    LANGUAGE SQL ERROR SAFE
     RETURN a = 'abcd' AND b > '2001-01-01';
 CREATE FUNCTION functest_S_2(a text[]) RETURNS int
     RETURN a[1]::int;
@@ -348,6 +349,7 @@ SELECT pg_get_functiondef('functest_S_1'::regproc);
  CREATE OR REPLACE FUNCTION temp_func_test.functest_s_1(a text, b date)+
   RETURNS boolean                                                      +
   LANGUAGE sql                                                         +
+  ERROR SAFE                                                           +
  RETURN ((a = 'abcd'::text) AND (b > '01-01-2001'::date))              +
  
 (1 row)
diff --git a/src/test/regress/expected/create_procedure.out b/src/test/regress/expected/create_procedure.out
index f89042cf798..15b4169b198 100644
--- a/src/test/regress/expected/create_procedure.out
+++ b/src/test/regress/expected/create_procedure.out
@@ -8,6 +8,14 @@ ERROR:  random() is not a procedure
 LINE 1: CALL random();
              ^
 HINT:  To call a function, use SELECT.
+CREATE PROCEDURE ptest1(x text) LANGUAGE SQL ERROR SAFE AS $$ $$;
+ERROR:  invalid attribute in procedure definition
+LINE 1: CREATE PROCEDURE ptest1(x text) LANGUAGE SQL ERROR SAFE AS $...
+                                                     ^
+CREATE PROCEDURE ptest1s(x text) LANGUAGE SQL ERROR SAFE BEGIN ATOMIC END;
+ERROR:  invalid attribute in procedure definition
+LINE 1: CREATE PROCEDURE ptest1s(x text) LANGUAGE SQL ERROR SAFE BEG...
+                                                      ^
 CREATE FUNCTION cp_testfunc1(a int) RETURNS int LANGUAGE SQL AS $$ SELECT a $$;
 CREATE TABLE cp_test (a int, b text);
 CREATE PROCEDURE ptest1(x text)
@@ -413,6 +421,10 @@ ALTER PROCEDURE ptest1(text) STRICT;
 ERROR:  invalid attribute in procedure definition
 LINE 1: ALTER PROCEDURE ptest1(text) STRICT;
                                      ^
+ALTER PROCEDURE ptest1(text) ERROR SAFE;
+ERROR:  invalid attribute in procedure definition
+LINE 1: ALTER PROCEDURE ptest1(text) ERROR SAFE;
+                                     ^
 ALTER FUNCTION ptest1(text) VOLATILE;  -- error: not a function
 ERROR:  ptest1(text) is not a function
 ALTER PROCEDURE cp_testfunc1(int) VOLATILE;  -- error: not a procedure
diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out
index 35d6ee2ce9e..49aeabb5a9f 100644
--- a/src/test/regress/expected/misc_functions.out
+++ b/src/test/regress/expected/misc_functions.out
@@ -2,6 +2,19 @@
 \getenv libdir PG_LIBDIR
 \getenv dlsuffix PG_DLSUFFIX
 \set regresslib :libdir '/regress' :dlsuffix
+create function dummyx(int) returns void language plpgsql error unsafe as $$begin end$$;
+alter function dummyx error safe;
+select pg_get_functiondef('dummyx'::regproc);
+                pg_get_functiondef                 
+---------------------------------------------------
+ CREATE OR REPLACE FUNCTION public.dummyx(integer)+
+  RETURNS void                                    +
+  LANGUAGE plpgsql                                +
+  ERROR SAFE                                      +
+ AS $function$begin end$function$                 +
+ 
+(1 row)
+
 --
 -- num_nulls()
 --
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 907d63daa3f..acccc560bc2 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1047,6 +1047,19 @@ WHERE c.castmethod = 'b' AND
  pg_ndistinct      | bytea             |        0 | i
 (10 rows)
 
+-- List build-in type cast that is not error-safe
+select pp.proname, pp.prosrc
+from pg_cast pc join pg_proc pp on pp.oid = pc.castfunc
+join pg_type pt on pt.oid = castsource
+join pg_type pt1 on pt1.oid = casttarget
+and pc.castfunc > 0 and pt.typnamespace = 'pg_catalog'::regnamespace
+and pt1.typnamespace = 'pg_catalog'::regnamespace and proerrorsafe is false
+order by pp.proname, pp.prosrc;
+ proname |    prosrc    
+---------+--------------
+ numeric | cash_numeric
+(1 row)
+
 -- **************** pg_conversion ****************
 -- Look for illegal values in pg_conversion fields.
 SELECT c.oid, c.conname
diff --git a/src/test/regress/sql/create_function_sql.sql b/src/test/regress/sql/create_function_sql.sql
index 4543273f93a..a891750a2e8 100644
--- a/src/test/regress/sql/create_function_sql.sql
+++ b/src/test/regress/sql/create_function_sql.sql
@@ -123,7 +123,7 @@ RESET SESSION AUTHORIZATION;
 --
 CREATE FUNCTION functest_F_1(int) RETURNS bool LANGUAGE 'sql'
        AS 'SELECT $1 > 50';
-CREATE FUNCTION functest_F_2(int) RETURNS bool LANGUAGE 'sql'
+CREATE FUNCTION functest_F_2(int) RETURNS bool LANGUAGE 'sql' ERROR UNSAFE
        CALLED ON NULL INPUT AS 'SELECT $1 = 50';
 CREATE FUNCTION functest_F_3(int) RETURNS bool LANGUAGE 'sql'
        RETURNS NULL ON NULL INPUT AS 'SELECT $1 < 50';
@@ -137,6 +137,7 @@ SELECT proname, proisstrict FROM pg_proc
 
 ALTER FUNCTION functest_F_1(int) IMMUTABLE;	-- unrelated change, no effect
 ALTER FUNCTION functest_F_2(int) STRICT;
+ALTER FUNCTION functest_F_2(int) ERROR SAFE;
 ALTER FUNCTION functest_F_3(int) CALLED ON NULL INPUT;
 SELECT proname, proisstrict FROM pg_proc
        WHERE oid in ('functest_F_1'::regproc,
@@ -157,7 +158,7 @@ SELECT pg_get_functiondef('functest_F_2'::regproc);
 -- SQL-standard body
 --
 CREATE FUNCTION functest_S_1(a text, b date) RETURNS boolean
-    LANGUAGE SQL
+    LANGUAGE SQL ERROR SAFE
     RETURN a = 'abcd' AND b > '2001-01-01';
 CREATE FUNCTION functest_S_2(a text[]) RETURNS int
     RETURN a[1]::int;
diff --git a/src/test/regress/sql/create_procedure.sql b/src/test/regress/sql/create_procedure.sql
index 069a3727ced..e61e053ed41 100644
--- a/src/test/regress/sql/create_procedure.sql
+++ b/src/test/regress/sql/create_procedure.sql
@@ -1,6 +1,9 @@
 CALL nonexistent();  -- error
 CALL random();  -- error
 
+CREATE PROCEDURE ptest1(x text) LANGUAGE SQL ERROR SAFE AS $$ $$;
+CREATE PROCEDURE ptest1s(x text) LANGUAGE SQL ERROR SAFE BEGIN ATOMIC END;
+
 CREATE FUNCTION cp_testfunc1(a int) RETURNS int LANGUAGE SQL AS $$ SELECT a $$;
 
 CREATE TABLE cp_test (a int, b text);
@@ -244,6 +247,7 @@ CREATE PROCEDURE ptestx(a int DEFAULT 42, b OUT int) LANGUAGE SQL
   AS $$ SELECT a $$;
 
 ALTER PROCEDURE ptest1(text) STRICT;
+ALTER PROCEDURE ptest1(text) ERROR SAFE;
 ALTER FUNCTION ptest1(text) VOLATILE;  -- error: not a function
 ALTER PROCEDURE cp_testfunc1(int) VOLATILE;  -- error: not a procedure
 ALTER PROCEDURE nonexistent() VOLATILE;
diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql
index 94b91964c04..b97b21f0ddb 100644
--- a/src/test/regress/sql/misc_functions.sql
+++ b/src/test/regress/sql/misc_functions.sql
@@ -4,6 +4,10 @@
 
 \set regresslib :libdir '/regress' :dlsuffix
 
+create function dummyx(int) returns void language plpgsql error unsafe as $$begin end$$;
+alter function dummyx error safe;
+select pg_get_functiondef('dummyx'::regproc);
+
 --
 -- num_nulls()
 --
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 5670bb14193..341aa107eaf 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -517,6 +517,14 @@ WHERE c.castmethod = 'b' AND
                     k.castsource = c.casttarget AND
                     k.casttarget = c.castsource);
 
+-- List build-in type cast that is not error-safe
+select pp.proname, pp.prosrc
+from pg_cast pc join pg_proc pp on pp.oid = pc.castfunc
+join pg_type pt on pt.oid = castsource
+join pg_type pt1 on pt1.oid = casttarget
+and pc.castfunc > 0 and pt.typnamespace = 'pg_catalog'::regnamespace
+and pt1.typnamespace = 'pg_catalog'::regnamespace and proerrorsafe is false
+order by pp.proname, pp.prosrc;
 
 -- **************** pg_conversion ****************
 
-- 
2.34.1

