On Mon, Dec 12, 2022 at 12:00 AM Tom Lane <t...@sss.pgh.pa.us> wrote:
>
> Andrew Dunstan <and...@dunslane.net> writes:
> > Maybe as we work through the remaining input functions (there are about
> > 60 core candidates left on my list) we should mark them with a comment
> > if no adjustment is needed.
>
> I did a quick pass through them last night.  Assuming that we don't
> need to touch the unimplemented input functions (eg for pseudotypes),
> I count these core functions as still needing work:
>
> aclitemin
> bit_in
> box_in
> bpcharin
> byteain
> cash_in
> cidin
> cidr_in
> circle_in
> inet_in
> int2vectorin
> jsonpath_in
> line_in
> lseg_in
> macaddr8_in
> macaddr_in

Attaching patches changing these functions except bpcharin,
byteain, jsonpath_in, and cidin. I am continuing work on the next
items below:

> multirange_in
> namein
> oidin
> oidvectorin
> path_in
> pg_lsn_in
> pg_snapshot_in
> point_in
> poly_in
> range_in
> regclassin
> regcollationin
> regconfigin
> regdictionaryin
> regnamespacein
> regoperatorin
> regoperin
> regprocedurein
> regprocin
> regrolein
> regtypein
> tidin
> tsqueryin
> tsvectorin
> uuid_in
> varbit_in
> varcharin
> xid8in
> xidin
> xml_in
>
> and these contrib functions:
>
> hstore:
> hstore_in
> intarray:
> bqarr_in
> isn:
> ean13_in
> isbn_in
> ismn_in
> issn_in
> upc_in
> ltree:
> ltree_in
> lquery_in
> ltxtq_in
> seg:
> seg_in
>
> Maybe we should have a conversation about which of these are
> highest priority to get to a credible feature.  We clearly need
> to fix the remaining SQL-spec types (varchar and bpchar, mainly).
> At the other extreme, likely nobody would weep if we never fixed
> int2vectorin, for instance.
>
> I'm a little concerned about the cost-benefit of fixing the reg* types.
> The ones that accept type names actually use the core grammar to parse
> those.  Now, we probably could fix the grammar to be non-throwing, but
> it'd be very invasive and I'm not sure about the performance impact.
> It might be best to content ourselves with soft reporting of lookup
> failures, as opposed to syntax problems.
>

Regards,
Amul
From 4c4c18bd8104114351ca58a73a9d92fbb0c85dd2 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 17:29:04 +0530
Subject: [PATCH v1 13/14] Change macaddr8_in to allow non-throw error
 reporting

---
 src/backend/utils/adt/mac8.c           | 36 +++++++++++++-------------
 src/test/regress/expected/macaddr8.out | 25 ++++++++++++++++++
 src/test/regress/sql/macaddr8.sql      |  6 +++++
 3 files changed, 49 insertions(+), 18 deletions(-)

diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
index 24d219f6386..adb253a6ac0 100644
--- a/src/backend/utils/adt/mac8.c
+++ b/src/backend/utils/adt/mac8.c
@@ -35,7 +35,8 @@
 #define lobits(addr) \
   ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h)))
 
-static unsigned char hex2_to_uchar(const unsigned char *ptr, const unsigned char *str);
+static unsigned char hex2_to_uchar(const unsigned char *ptr, const unsigned char *str,
+								   Node *escontext);
 
 static const signed char hexlookup[128] = {
 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
@@ -58,7 +59,8 @@ static const signed char hexlookup[128] = {
  * the entire string, which is used only for error reporting.
  */
 static inline unsigned char
-hex2_to_uchar(const unsigned char *ptr, const unsigned char *str)
+hex2_to_uchar(const unsigned char *ptr, const unsigned char *str,
+			  Node *escontext)
 {
 	unsigned char ret = 0;
 	signed char lookup;
@@ -88,13 +90,10 @@ hex2_to_uchar(const unsigned char *ptr, const unsigned char *str)
 	return ret;
 
 invalid_input:
-	ereport(ERROR,
+	ereturn(escontext, 0,
 			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 			 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 					str)));
-
-	/* We do not actually reach here */
-	return 0;
 }
 
 /*
@@ -104,6 +103,7 @@ Datum
 macaddr8_in(PG_FUNCTION_ARGS)
 {
 	const unsigned char *str = (unsigned char *) PG_GETARG_CSTRING(0);
+	Node	   *escontext = fcinfo->context;
 	const unsigned char *ptr = str;
 	macaddr8   *result;
 	unsigned char a = 0,
@@ -136,32 +136,32 @@ macaddr8_in(PG_FUNCTION_ARGS)
 		switch (count)
 		{
 			case 1:
-				a = hex2_to_uchar(ptr, str);
+				a = hex2_to_uchar(ptr, str, escontext);
 				break;
 			case 2:
-				b = hex2_to_uchar(ptr, str);
+				b = hex2_to_uchar(ptr, str, escontext);
 				break;
 			case 3:
-				c = hex2_to_uchar(ptr, str);
+				c = hex2_to_uchar(ptr, str, escontext);
 				break;
 			case 4:
-				d = hex2_to_uchar(ptr, str);
+				d = hex2_to_uchar(ptr, str, escontext);
 				break;
 			case 5:
-				e = hex2_to_uchar(ptr, str);
+				e = hex2_to_uchar(ptr, str, escontext);
 				break;
 			case 6:
-				f = hex2_to_uchar(ptr, str);
+				f = hex2_to_uchar(ptr, str, escontext);
 				break;
 			case 7:
-				g = hex2_to_uchar(ptr, str);
+				g = hex2_to_uchar(ptr, str, escontext);
 				break;
 			case 8:
-				h = hex2_to_uchar(ptr, str);
+				h = hex2_to_uchar(ptr, str, escontext);
 				break;
 			default:
 				/* must be trailing garbage... */
-				ereport(ERROR,
+				ereturn(escontext, (Datum) 0,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 								str)));
@@ -179,7 +179,7 @@ macaddr8_in(PG_FUNCTION_ARGS)
 
 			/* Have to use the same spacer throughout */
 			else if (spacer != *ptr)
-				ereport(ERROR,
+				ereturn(escontext, (Datum) 0,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 								str)));
@@ -197,7 +197,7 @@ macaddr8_in(PG_FUNCTION_ARGS)
 
 				/* If we found a space and then non-space, it's invalid */
 				if (*ptr)
-					ereport(ERROR,
+					ereturn(escontext, (Datum) 0,
 							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 							 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 									str)));
@@ -216,7 +216,7 @@ macaddr8_in(PG_FUNCTION_ARGS)
 		e = 0xFE;
 	}
 	else if (count != 8)
-		ereport(ERROR,
+		ereturn(escontext, (Datum) 0,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 						str)));
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
index 74f53a121f2..bf681988f87 100644
--- a/src/test/regress/expected/macaddr8.out
+++ b/src/test/regress/expected/macaddr8.out
@@ -352,3 +352,28 @@ SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
 (20 rows)
 
 DROP TABLE macaddr8_data;
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
+                      pg_input_error_message                       
+-------------------------------------------------------------------
+ invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:ZZ"
+(1 row)
+
+SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8');
+                     pg_input_error_message                      
+-----------------------------------------------------------------
+ invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:"
+(1 row)
+
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
index 57a227c5ab7..b29f785b41e 100644
--- a/src/test/regress/sql/macaddr8.sql
+++ b/src/test/regress/sql/macaddr8.sql
@@ -87,3 +87,9 @@ SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
 SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
 
 DROP TABLE macaddr8_data;
+
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
+SELECT pg_input_error_message('08:00:2b:01:02:03:04:ZZ', 'macaddr8');
+SELECT pg_input_is_valid('08:00:2b:01:02:03:04:', 'macaddr8');
+SELECT pg_input_error_message('08:00:2b:01:02:03:04:', 'macaddr8');
-- 
2.18.0

From 87b35edfdef4e5255810e903a2df5e331b6003e6 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 17:36:03 +0530
Subject: [PATCH v1 14/14] Change macaddr_in to allow non-throw error reporting

---
 src/backend/utils/adt/mac.c           |  5 +++--
 src/test/regress/expected/macaddr.out | 25 +++++++++++++++++++++++++
 src/test/regress/sql/macaddr.sql      |  6 ++++++
 3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index ac7342cfca7..089450dac34 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -55,6 +55,7 @@ Datum
 macaddr_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
+	Node	   *escontext = fcinfo->context;
 	macaddr    *result;
 	int			a,
 				b,
@@ -88,7 +89,7 @@ macaddr_in(PG_FUNCTION_ARGS)
 		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
 					   &a, &b, &c, &d, &e, &f, junk);
 	if (count != 6)
-		ereport(ERROR,
+		ereturn(escontext, (Datum) 0,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr",
 						str)));
@@ -96,7 +97,7 @@ macaddr_in(PG_FUNCTION_ARGS)
 	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
 		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
 		(e < 0) || (e > 255) || (f < 0) || (f > 255))
-		ereport(ERROR,
+		ereturn(escontext, (Datum) 0,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str)));
 
diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out
index 151f9ce59bb..cb646af79bd 100644
--- a/src/test/regress/expected/macaddr.out
+++ b/src/test/regress/expected/macaddr.out
@@ -158,3 +158,28 @@ SELECT  b | '01:02:03:04:05:06' FROM macaddr_data;
 (12 rows)
 
 DROP TABLE macaddr_data;
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr');
+                   pg_input_error_message                   
+------------------------------------------------------------
+ invalid input syntax for type macaddr: "08:00:2b:01:02:ZZ"
+(1 row)
+
+SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr');
+                  pg_input_error_message                  
+----------------------------------------------------------
+ invalid input syntax for type macaddr: "08:00:2b:01:02:"
+(1 row)
+
diff --git a/src/test/regress/sql/macaddr.sql b/src/test/regress/sql/macaddr.sql
index 7bad8f5d7ae..211397c8f3c 100644
--- a/src/test/regress/sql/macaddr.sql
+++ b/src/test/regress/sql/macaddr.sql
@@ -41,3 +41,9 @@ SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr_data;
 SELECT  b | '01:02:03:04:05:06' FROM macaddr_data;
 
 DROP TABLE macaddr_data;
+
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('08:00:2b:01:02:ZZ', 'macaddr');
+SELECT pg_input_error_message('08:00:2b:01:02:ZZ', 'macaddr');
+SELECT pg_input_is_valid('08:00:2b:01:02:', 'macaddr');
+SELECT pg_input_error_message('08:00:2b:01:02:', 'macaddr');
-- 
2.18.0

From ba071042d08f9dd55de1800ac1c04ffafceecff4 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 14:41:05 +0530
Subject: [PATCH v1 10/14] Change int2vectorin to allow non-throw error
 reporting

---
 src/backend/utils/adt/int.c               |  9 +++++----
 src/test/regress/expected/type_sanity.out | 24 +++++++++++++++++++++++
 src/test/regress/sql/type_sanity.sql      |  5 +++++
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index 8de38abd11d..2c90e526a60 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -141,6 +141,7 @@ Datum
 int2vectorin(PG_FUNCTION_ARGS)
 {
 	char	   *intString = PG_GETARG_CSTRING(0);
+	Node	   *escontext = fcinfo->context;
 	int2vector *result;
 	int			n;
 
@@ -160,19 +161,19 @@ int2vectorin(PG_FUNCTION_ARGS)
 		l = strtol(intString, &endp, 10);
 
 		if (intString == endp)
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"smallint", intString)));
 
 		if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("value \"%s\" is out of range for type %s", intString,
 							"smallint")));
 
 		if (*endp && *endp != ' ')
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"integer", intString)));
@@ -183,7 +184,7 @@ int2vectorin(PG_FUNCTION_ARGS)
 	while (*intString && isspace((unsigned char) *intString))
 		intString++;
 	if (*intString)
-		ereport(ERROR,
+		ereturn(escontext, (Datum) 0,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("int2vector has too many elements")));
 
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index 0b015b424f1..241b628fb07 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -832,3 +832,27 @@ SELECT pg_input_error_message('1', 'gtsvector');
  cannot accept a value of type gtsvector
 (1 row)
 
+SELECT pg_input_is_valid('1 XYZ', 'int2vector');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('1 XYZ', 'int2vector');
+            pg_input_error_message             
+-----------------------------------------------
+ invalid input syntax for type smallint: "XYZ"
+(1 row)
+
+SELECT pg_input_is_valid('1 99999', 'int2vector');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('1 99999', 'int2vector');
+             pg_input_error_message              
+-------------------------------------------------
+ value "99999" is out of range for type smallint
+(1 row)
+
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index d024d950b3e..b59ebf9490c 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -605,3 +605,8 @@ SELECT pg_input_error_message('1', 'pg_brin_minmax_multi_summary');
 
 SELECT pg_input_is_valid('1', 'gtsvector');
 SELECT pg_input_error_message('1', 'gtsvector');
+
+SELECT pg_input_is_valid('1 XYZ', 'int2vector');
+SELECT pg_input_error_message('1 XYZ', 'int2vector');
+SELECT pg_input_is_valid('1 99999', 'int2vector');
+SELECT pg_input_error_message('1 99999', 'int2vector');
-- 
2.18.0

From 508919f004d671cda39f4f2f2bc0a06b7b377e64 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 17:12:53 +0530
Subject: [PATCH v1 12/14] Change lseg_in to allow non-throw error reporting

---
 src/backend/utils/adt/geo_ops.c    |  7 +++++--
 src/test/regress/expected/lseg.out | 13 +++++++++++++
 src/test/regress/sql/lseg.sql      |  4 ++++
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 480d3d4a64a..52bd62c4cc1 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -2065,11 +2065,14 @@ Datum
 lseg_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
+	Node	   *escontext = fcinfo->context;
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str,
-				NULL);
+	if (!path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str,
+					 escontext))
+		PG_RETURN_NULL();
+
 	PG_RETURN_LSEG_P(lseg);
 }
 
diff --git a/src/test/regress/expected/lseg.out b/src/test/regress/expected/lseg.out
index 7e878b55779..afb323fe04c 100644
--- a/src/test/regress/expected/lseg.out
+++ b/src/test/regress/expected/lseg.out
@@ -42,3 +42,16 @@ select * from LSEG_TBL;
  [(NaN,1),(NaN,90)]
 (8 rows)
 
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('[(1,2),(3)]', 'lseg');
+              pg_input_error_message               
+---------------------------------------------------
+ invalid input syntax for type lseg: "[(1,2),(3)]"
+(1 row)
+
diff --git a/src/test/regress/sql/lseg.sql b/src/test/regress/sql/lseg.sql
index f266ca3e09e..0fece162e01 100644
--- a/src/test/regress/sql/lseg.sql
+++ b/src/test/regress/sql/lseg.sql
@@ -22,3 +22,7 @@ INSERT INTO LSEG_TBL VALUES ('[(,2),(3,4)]');
 INSERT INTO LSEG_TBL VALUES ('[(1,2),(3,4)');
 
 select * from LSEG_TBL;
+
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('[(1,2),(3)]', 'lseg');
+SELECT pg_input_error_message('[(1,2),(3)]', 'lseg');
-- 
2.18.0

From 19133fbe50c39563739931374fbe937eeec2b879 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 16:10:03 +0530
Subject: [PATCH v1 11/14] Change line_in to allow non-throw error reporting

---
 src/backend/utils/adt/float.c      | 90 +++++++++++++++---------------
 src/backend/utils/adt/geo_ops.c    | 58 +++++++++++--------
 src/include/utils/float.h          | 53 ++++++++++++------
 src/test/regress/expected/line.out | 37 ++++++++++++
 src/test/regress/sql/line.sql      |  8 +++
 5 files changed, 163 insertions(+), 83 deletions(-)

diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index b02a19be24d..3662a697f8a 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -82,17 +82,17 @@ static void init_degree_constants(void);
  * This does mean that you don't get a useful error location indicator.
  */
 pg_noinline void
-float_overflow_error(void)
+float_overflow_error(Node *escontext)
 {
-	ereport(ERROR,
+	errsave(escontext,
 			(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 			 errmsg("value out of range: overflow")));
 }
 
 pg_noinline void
-float_underflow_error(void)
+float_underflow_error(Node *escontext)
 {
-	ereport(ERROR,
+	errsave(escontext,
 			(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 			 errmsg("value out of range: underflow")));
 }
@@ -1172,9 +1172,9 @@ dtof(PG_FUNCTION_ARGS)
 
 	result = (float4) num;
 	if (unlikely(isinf(result)) && !isinf(num))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0f) && num != 0.0)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT4(result);
 }
@@ -1428,9 +1428,9 @@ dsqrt(PG_FUNCTION_ARGS)
 
 	result = sqrt(arg1);
 	if (unlikely(isinf(result)) && !isinf(arg1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0) && arg1 != 0.0)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1447,9 +1447,9 @@ dcbrt(PG_FUNCTION_ARGS)
 
 	result = cbrt(arg1);
 	if (unlikely(isinf(result)) && !isinf(arg1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0) && arg1 != 0.0)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1585,24 +1585,24 @@ dpow(PG_FUNCTION_ARGS)
 				if (absx == 1.0)
 					result = 1.0;
 				else if (arg2 >= 0.0 ? (absx > 1.0) : (absx < 1.0))
-					float_overflow_error();
+					float_overflow_error(NULL);
 				else
-					float_underflow_error();
+					float_underflow_error(NULL);
 			}
 		}
 		else if (errno == ERANGE)
 		{
 			if (result != 0.0)
-				float_overflow_error();
+				float_overflow_error(NULL);
 			else
-				float_underflow_error();
+				float_underflow_error(NULL);
 		}
 		else
 		{
 			if (unlikely(isinf(result)))
-				float_overflow_error();
+				float_overflow_error(NULL);
 			if (unlikely(result == 0.0) && arg1 != 0.0)
-				float_underflow_error();
+				float_underflow_error(NULL);
 		}
 	}
 
@@ -1642,14 +1642,14 @@ dexp(PG_FUNCTION_ARGS)
 		if (unlikely(errno == ERANGE))
 		{
 			if (result != 0.0)
-				float_overflow_error();
+				float_overflow_error(NULL);
 			else
-				float_underflow_error();
+				float_underflow_error(NULL);
 		}
 		else if (unlikely(isinf(result)))
-			float_overflow_error();
+			float_overflow_error(NULL);
 		else if (unlikely(result == 0.0))
-			float_underflow_error();
+			float_underflow_error(NULL);
 	}
 
 	PG_RETURN_FLOAT8(result);
@@ -1680,9 +1680,9 @@ dlog1(PG_FUNCTION_ARGS)
 
 	result = log(arg1);
 	if (unlikely(isinf(result)) && !isinf(arg1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0) && arg1 != 1.0)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1713,9 +1713,9 @@ dlog10(PG_FUNCTION_ARGS)
 
 	result = log10(arg1);
 	if (unlikely(isinf(result)) && !isinf(arg1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0) && arg1 != 1.0)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1746,7 +1746,7 @@ dacos(PG_FUNCTION_ARGS)
 
 	result = acos(arg1);
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1777,7 +1777,7 @@ dasin(PG_FUNCTION_ARGS)
 
 	result = asin(arg1);
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1803,7 +1803,7 @@ datan(PG_FUNCTION_ARGS)
 	 */
 	result = atan(arg1);
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1829,7 +1829,7 @@ datan2(PG_FUNCTION_ARGS)
 	 */
 	result = atan2(arg1, arg2);
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1870,7 +1870,7 @@ dcos(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -1925,7 +1925,7 @@ dsin(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("input is out of range")));
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2105,7 +2105,7 @@ dacosd(PG_FUNCTION_ARGS)
 		result = 90.0 + asind_q1(-arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2142,7 +2142,7 @@ dasind(PG_FUNCTION_ARGS)
 		result = -asind_q1(-arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2174,7 +2174,7 @@ datand(PG_FUNCTION_ARGS)
 	result = (atan_arg1 / atan_1_0) * 45.0;
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2210,7 +2210,7 @@ datan2d(PG_FUNCTION_ARGS)
 	result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2333,7 +2333,7 @@ dcosd(PG_FUNCTION_ARGS)
 	result = sign * cosd_q1(arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2455,7 +2455,7 @@ dsind(PG_FUNCTION_ARGS)
 	result = sign * sind_q1(arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2613,7 +2613,7 @@ dcosh(PG_FUNCTION_ARGS)
 		result = get_float8_infinity();
 
 	if (unlikely(result == 0.0))
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2633,7 +2633,7 @@ dtanh(PG_FUNCTION_ARGS)
 	result = tanh(arg1);
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2905,7 +2905,7 @@ float8_combine(PG_FUNCTION_ARGS)
 		tmp = Sx1 / N1 - Sx2 / N2;
 		Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp * tmp / N;
 		if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2))
-			float_overflow_error();
+			float_overflow_error(NULL);
 	}
 
 	/*
@@ -2974,7 +2974,7 @@ float8_accum(PG_FUNCTION_ARGS)
 		if (isinf(Sx) || isinf(Sxx))
 		{
 			if (!isinf(transvalues[1]) && !isinf(newval))
-				float_overflow_error();
+				float_overflow_error(NULL);
 
 			Sxx = get_float8_nan();
 		}
@@ -3059,7 +3059,7 @@ float4_accum(PG_FUNCTION_ARGS)
 		if (isinf(Sx) || isinf(Sxx))
 		{
 			if (!isinf(transvalues[1]) && !isinf(newval))
-				float_overflow_error();
+				float_overflow_error(NULL);
 
 			Sxx = get_float8_nan();
 		}
@@ -3291,7 +3291,7 @@ float8_regr_accum(PG_FUNCTION_ARGS)
 				(isinf(Sxy) &&
 				 !isinf(transvalues[1]) && !isinf(newvalX) &&
 				 !isinf(transvalues[3]) && !isinf(newvalY)))
-				float_overflow_error();
+				float_overflow_error(NULL);
 
 			if (isinf(Sxx))
 				Sxx = get_float8_nan();
@@ -3445,15 +3445,15 @@ float8_regr_combine(PG_FUNCTION_ARGS)
 		tmp1 = Sx1 / N1 - Sx2 / N2;
 		Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp1 * tmp1 / N;
 		if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2))
-			float_overflow_error();
+			float_overflow_error(NULL);
 		Sy = float8_pl(Sy1, Sy2);
 		tmp2 = Sy1 / N1 - Sy2 / N2;
 		Syy = Syy1 + Syy2 + N1 * N2 * tmp2 * tmp2 / N;
 		if (unlikely(isinf(Syy)) && !isinf(Syy1) && !isinf(Syy2))
-			float_overflow_error();
+			float_overflow_error(NULL);
 		Sxy = Sxy1 + Sxy2 + N1 * N2 * tmp1 * tmp2 / N;
 		if (unlikely(isinf(Sxy)) && !isinf(Sxy1) && !isinf(Sxy2))
-			float_overflow_error();
+			float_overflow_error(NULL);
 	}
 
 	/*
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index cf4246214a5..480d3d4a64a 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -86,7 +86,8 @@ static inline float8 point_sl(Point *pt1, Point *pt2);
 static int	point_inside(Point *p, int npts, Point *plist);
 
 /* Routines for lines */
-static inline void line_construct(LINE *result, Point *pt, float8 m);
+static inline bool line_construct(LINE *result, Point *pt, float8 m,
+								  Node *escontext);
 static inline float8 line_sl(LINE *line);
 static inline float8 line_invsl(LINE *line);
 static bool line_interpt_line(Point *result, LINE *l1, LINE *l2);
@@ -954,15 +955,17 @@ box_diagonal(PG_FUNCTION_ARGS)
 static bool
 line_decode(char *s, const char *str, LINE *line)
 {
+	ErrorSaveContext escontext = {T_ErrorSaveContext};
+
 	/* s was already advanced over leading '{' */
-	line->A = single_decode(s, &s, "line", str, NULL);
-	if (*s++ != DELIM)
+	line->A = single_decode(s, &s, "line", str, (Node *) &escontext);
+	if (escontext.error_occurred || *s++ != DELIM)
 		return false;
-	line->B = single_decode(s, &s, "line", str, NULL);
-	if (*s++ != DELIM)
+	line->B = single_decode(s, &s, "line", str, (Node *) &escontext);
+	if (escontext.error_occurred || *s++ != DELIM)
 		return false;
-	line->C = single_decode(s, &s, "line", str, NULL);
-	if (*s++ != RDELIM_L)
+	line->C = single_decode(s, &s, "line", str, (Node *) &escontext);
+	if (escontext.error_occurred || *s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
 		s++;
@@ -975,6 +978,7 @@ Datum
 line_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
+	Node	   *escontext = fcinfo->context;
 	LINE	   *line = (LINE *) palloc(sizeof(LINE));
 	LSEG		lseg;
 	bool		isopen;
@@ -986,23 +990,27 @@ line_in(PG_FUNCTION_ARGS)
 	if (*s == LDELIM_L)
 	{
 		if (!line_decode(s + 1, str, line))
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"line", str)));
 		if (FPzero(line->A) && FPzero(line->B))
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
 	else
 	{
-		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str, NULL);
+		if (!path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str,
+						escontext))
+			PG_RETURN_NULL();
+
 		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
-		line_construct(line, &lseg.p[0], lseg_sl(&lseg));
+		if (!line_construct(line, &lseg.p[0], lseg_sl(&lseg), escontext))
+			PG_RETURN_NULL();
 	}
 
 	PG_RETURN_LINE_P(line);
@@ -1069,8 +1077,8 @@ line_send(PG_FUNCTION_ARGS)
 /*
  * Fill already-allocated LINE struct from the point and the slope
  */
-static inline void
-line_construct(LINE *result, Point *pt, float8 m)
+static inline bool
+line_construct(LINE *result, Point *pt, float8 m, Node *escontext)
 {
 	if (isinf(m))
 	{
@@ -1091,11 +1099,17 @@ line_construct(LINE *result, Point *pt, float8 m)
 		/* use "mx - y + yinter = 0" */
 		result->A = m;
 		result->B = -1.0;
-		result->C = float8_mi(pt->y, float8_mul(m, pt->x));
+		result->C = float8_mul_safe(m, pt->x, escontext);
+		if (SOFT_ERROR_OCCURRED(escontext))
+			return false;
+		result->C = float8_mi_safe(pt->y, result->C, escontext);
+		if (SOFT_ERROR_OCCURRED(escontext))
+			return false;
 		/* on some platforms, the preceding expression tends to produce -0 */
 		if (result->C == 0.0)
 			result->C = 0.0;
 	}
+	return true;
 }
 
 /* line_construct_pp()
@@ -1113,7 +1127,7 @@ line_construct_pp(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("invalid line specification: must be two distinct points")));
 
-	line_construct(result, pt1, point_sl(pt1, pt2));
+	line_construct(result, pt1, point_sl(pt1, pt2), NULL);
 
 	PG_RETURN_LINE_P(result);
 }
@@ -2323,7 +2337,7 @@ lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2)
 	Point		interpt;
 	LINE		tmp;
 
-	line_construct(&tmp, &l2->p[0], lseg_sl(l2));
+	line_construct(&tmp, &l2->p[0], lseg_sl(l2), NULL);
 	if (!lseg_interpt_line(&interpt, l1, &tmp))
 		return false;
 
@@ -2665,7 +2679,7 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
 	 * find the intersection point of two lines.  If they don't have an
 	 * intersection point, we are done.
 	 */
-	line_construct(&tmp, &lseg->p[0], lseg_sl(lseg));
+	line_construct(&tmp, &lseg->p[0], lseg_sl(lseg), NULL);
 	if (!line_interpt_line(&interpt, &tmp, line))
 		return false;
 
@@ -2714,7 +2728,7 @@ line_closept_point(Point *result, LINE *line, Point *point)
 	 * should always find it, but that can fail in the presence of NaN
 	 * coordinates, and perhaps even from simple roundoff issues.
 	 */
-	line_construct(&tmp, point, line_invsl(line));
+	line_construct(&tmp, point, line_invsl(line), NULL);
 	if (!line_interpt_line(&closept, &tmp, line))
 	{
 		if (result != NULL)
@@ -2761,7 +2775,7 @@ lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
 	 * To find the closest point, we draw a perpendicular line from the point
 	 * to the line segment.
 	 */
-	line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]));
+	line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]), NULL);
 	lseg_closept_line(&closept, lseg, &tmp);
 
 	if (result != NULL)
@@ -5536,9 +5550,9 @@ pg_hypot(float8 x, float8 y)
 	result = x * sqrt(1.0 + (yx * yx));
 
 	if (unlikely(isinf(result)))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0))
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	return result;
 }
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index f92860b4a46..d61206d8609 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -37,8 +37,8 @@ extern PGDLLIMPORT int extra_float_digits;
 /*
  * Utility functions in float.c
  */
-extern void float_overflow_error(void) pg_attribute_noreturn();
-extern void float_underflow_error(void) pg_attribute_noreturn();
+extern void float_overflow_error(Node *escontext);
+extern void float_underflow_error(Node *escontext);
 extern void float_zero_divide_error(void) pg_attribute_noreturn();
 extern int	is_infinite(float8 val);
 extern float8 float8in_internal(char *num, char **endptr_p,
@@ -146,7 +146,7 @@ float4_pl(const float4 val1, const float4 val2)
 
 	result = val1 + val2;
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	return result;
 }
@@ -158,7 +158,7 @@ float8_pl(const float8 val1, const float8 val2)
 
 	result = val1 + val2;
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	return result;
 }
@@ -170,23 +170,32 @@ float4_mi(const float4 val1, const float4 val2)
 
 	result = val1 - val2;
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+		float_overflow_error(NULL);
 
 	return result;
 }
 
 static inline float8
-float8_mi(const float8 val1, const float8 val2)
+float8_mi_safe(const float8 val1, const float8 val2, Node *escontext)
 {
 	float8		result;
 
 	result = val1 - val2;
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+	{
+		float_overflow_error(escontext);
+		return 0;
+	}
 
 	return result;
 }
 
+static inline float8
+float8_mi(const float8 val1, const float8 val2)
+{
+	return float8_mi_safe(val1, val2, NULL);
+}
+
 static inline float4
 float4_mul(const float4 val1, const float4 val2)
 {
@@ -194,27 +203,39 @@ float4_mul(const float4 val1, const float4 val2)
 
 	result = val1 * val2;
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0f) && val1 != 0.0f && val2 != 0.0f)
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	return result;
 }
 
 static inline float8
-float8_mul(const float8 val1, const float8 val2)
+float8_mul_safe(const float8 val1, const float8 val2, Node *escontext)
 {
 	float8		result;
 
 	result = val1 * val2;
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+	{
+		float_overflow_error(escontext);
+		return 0;
+	}
 	if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0)
-		float_underflow_error();
+	{
+		float_underflow_error(escontext);
+		return 0;
+	}
 
 	return result;
 }
 
+static inline float8
+float8_mul(const float8 val1, const float8 val2)
+{
+	return float8_mul_safe(val1, val2, NULL);
+}
+
 static inline float4
 float4_div(const float4 val1, const float4 val2)
 {
@@ -224,9 +245,9 @@ float4_div(const float4 val1, const float4 val2)
 		float_zero_divide_error();
 	result = val1 / val2;
 	if (unlikely(isinf(result)) && !isinf(val1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0f) && val1 != 0.0f && !isinf(val2))
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	return result;
 }
@@ -240,9 +261,9 @@ float8_div(const float8 val1, const float8 val2)
 		float_zero_divide_error();
 	result = val1 / val2;
 	if (unlikely(isinf(result)) && !isinf(val1))
-		float_overflow_error();
+		float_overflow_error(NULL);
 	if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2))
-		float_underflow_error();
+		float_underflow_error(NULL);
 
 	return result;
 }
diff --git a/src/test/regress/expected/line.out b/src/test/regress/expected/line.out
index fe106589c6a..8145b7df56c 100644
--- a/src/test/regress/expected/line.out
+++ b/src/test/regress/expected/line.out
@@ -85,3 +85,40 @@ select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
  t    | f
 (1 row)
 
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('{1, 1}', 'line');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('{1, 1}', 'line');
+            pg_input_error_message            
+----------------------------------------------
+ invalid input syntax for type line: "{1, 1}"
+(1 row)
+
+SELECT pg_input_is_valid('{0, 0, 0}', 'line');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('{0, 0, 0}', 'line');
+                 pg_input_error_message                  
+---------------------------------------------------------
+ invalid line specification: A and B cannot both be zero
+(1 row)
+
+SELECT pg_input_is_valid('{1, 1, a}', 'line');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('{1, 1, a}', 'line');
+             pg_input_error_message              
+-------------------------------------------------
+ invalid input syntax for type line: "{1, 1, a}"
+(1 row)
+
diff --git a/src/test/regress/sql/line.sql b/src/test/regress/sql/line.sql
index f589ffecc84..f34c6ae353f 100644
--- a/src/test/regress/sql/line.sql
+++ b/src/test/regress/sql/line.sql
@@ -40,3 +40,11 @@ select * from LINE_TBL;
 
 select '{nan, 1, nan}'::line = '{nan, 1, nan}'::line as true,
 	   '{nan, 1, nan}'::line = '{nan, 2, nan}'::line as false;
+
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('{1, 1}', 'line');
+SELECT pg_input_error_message('{1, 1}', 'line');
+SELECT pg_input_is_valid('{0, 0, 0}', 'line');
+SELECT pg_input_error_message('{0, 0, 0}', 'line');
+SELECT pg_input_is_valid('{1, 1, a}', 'line');
+SELECT pg_input_error_message('{1, 1, a}', 'line');
-- 
2.18.0

From 32908e516a2ea66f226bef543a81b0a22d9a1169 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 14:28:19 +0530
Subject: [PATCH v1 09/14] Change gtsvectorin to allow non-throw error
 reporting

---
 src/backend/utils/adt/tsgistidx.c         |  2 +-
 src/test/regress/expected/type_sanity.out | 12 ++++++++++++
 src/test/regress/sql/type_sanity.sql      |  3 +++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/adt/tsgistidx.c b/src/backend/utils/adt/tsgistidx.c
index cabfe4d1485..13e6fcf067b 100644
--- a/src/backend/utils/adt/tsgistidx.c
+++ b/src/backend/utils/adt/tsgistidx.c
@@ -88,7 +88,7 @@ Datum
 gtsvectorin(PG_FUNCTION_ARGS)
 {
 	/* There's no need to support input of gtsvectors */
-	ereport(ERROR,
+	ereturn(fcinfo->context, (Datum) 0,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("cannot accept a value of type %s", "gtsvector")));
 
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index 140dc6b948a..0b015b424f1 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -820,3 +820,15 @@ SELECT pg_input_error_message('1', 'pg_brin_minmax_multi_summary');
  cannot accept a value of type brin_minmax_multi_summary
 (1 row)
 
+SELECT pg_input_is_valid('1', 'gtsvector');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('1', 'gtsvector');
+         pg_input_error_message          
+-----------------------------------------
+ cannot accept a value of type gtsvector
+(1 row)
+
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index 7c1aff8a65b..d024d950b3e 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -602,3 +602,6 @@ SELECT pg_input_error_message('1', 'pg_brin_bloom_summary');
 
 SELECT pg_input_is_valid('1', 'pg_brin_minmax_multi_summary');
 SELECT pg_input_error_message('1', 'pg_brin_minmax_multi_summary');
+
+SELECT pg_input_is_valid('1', 'gtsvector');
+SELECT pg_input_error_message('1', 'gtsvector');
-- 
2.18.0

From 7b37918f53dce1cc8cafc473f9d253590a9295ba Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 16:28:30 +0530
Subject: [PATCH v1 08/14] Change circle_in to allow non-throw error reporting

---
 src/backend/utils/adt/geo_ops.c        | 30 +++++++++++++++-----------
 src/test/regress/expected/geometry.out | 25 +++++++++++++++++++++
 src/test/regress/sql/geometry.sql      |  6 ++++++
 3 files changed, 49 insertions(+), 12 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 5655f2f64cd..cf4246214a5 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -132,7 +132,8 @@ static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 
 /* Routines for encoding and decoding */
 static float8 single_decode(char *num, char **endptr_p,
-							const char *type_name, const char *orig_string);
+							const char *type_name, const char *orig_string,
+							Node *escontext);
 static void single_encode(float8 x, StringInfo str);
 static bool pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 						const char *type_name, const char *orig_string,
@@ -190,9 +191,9 @@ static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 
 static float8
 single_decode(char *num, char **endptr_p,
-			  const char *type_name, const char *orig_string)
+			  const char *type_name, const char *orig_string, Node *escontext)
 {
-	return float8in_internal(num, endptr_p, type_name, orig_string, NULL);
+	return float8in_internal(num, endptr_p, type_name, orig_string, escontext);
 }								/* single_decode() */
 
 static void
@@ -954,13 +955,13 @@ static bool
 line_decode(char *s, const char *str, LINE *line)
 {
 	/* s was already advanced over leading '{' */
-	line->A = single_decode(s, &s, "line", str);
+	line->A = single_decode(s, &s, "line", str, NULL);
 	if (*s++ != DELIM)
 		return false;
-	line->B = single_decode(s, &s, "line", str);
+	line->B = single_decode(s, &s, "line", str, NULL);
 	if (*s++ != DELIM)
 		return false;
-	line->C = single_decode(s, &s, "line", str);
+	line->C = single_decode(s, &s, "line", str, NULL);
 	if (*s++ != RDELIM_L)
 		return false;
 	while (isspace((unsigned char) *s))
@@ -4591,6 +4592,7 @@ Datum
 circle_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
+	Node	   *escontext = fcinfo->context;
 	CIRCLE	   *circle = (CIRCLE *) palloc(sizeof(CIRCLE));
 	char	   *s,
 			   *cp;
@@ -4612,16 +4614,20 @@ circle_in(PG_FUNCTION_ARGS)
 	}
 
 	/* pair_decode will consume parens around the pair, if any */
-	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str,
-				NULL);
+	if (!pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str,
+					 escontext))
+		PG_RETURN_NULL();
 
 	if (*s == DELIM)
 		s++;
 
-	circle->radius = single_decode(s, &s, "circle", str);
+	circle->radius = single_decode(s, &s, "circle", str, escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		PG_RETURN_NULL();
+
 	/* We have to accept NaN. */
 	if (circle->radius < 0.0)
-		ereport(ERROR,
+		ereturn(escontext, (Datum) 0,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
@@ -4636,14 +4642,14 @@ circle_in(PG_FUNCTION_ARGS)
 				s++;
 		}
 		else
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"circle", str)));
 	}
 
 	if (*s != '\0')
-		ereport(ERROR,
+		ereturn(escontext, (Datum) 0,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index b50103b2165..291cacdf4fb 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -5295,3 +5295,28 @@ SELECT * FROM polygon_tbl WHERE f1 @> '((1,1),(2,2),(2,1))'::polygon
  ((2,0),(2,4),(0,0))
 (1 row)
 
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('(1', 'circle');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('1,', 'circle');
+           pg_input_error_message           
+--------------------------------------------
+ invalid input syntax for type circle: "1,"
+(1 row)
+
+SELECT pg_input_is_valid('(1,2),-1', 'circle');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('(1,2),-1', 'circle');
+              pg_input_error_message              
+--------------------------------------------------
+ invalid input syntax for type circle: "(1,2),-1"
+(1 row)
+
diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql
index 8928d04aa3f..309234b76c1 100644
--- a/src/test/regress/sql/geometry.sql
+++ b/src/test/regress/sql/geometry.sql
@@ -523,3 +523,9 @@ SELECT * FROM polygon_tbl WHERE f1 @> '((1,1),(2,2),(2,1))'::polygon
     ORDER BY (poly_center(f1))[0];
 SELECT * FROM polygon_tbl WHERE f1 @> '((1,1),(2,2),(2,1))'::polygon
     ORDER BY (poly_center(f1))[0];
+
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('(1', 'circle');
+SELECT pg_input_error_message('1,', 'circle');
+SELECT pg_input_is_valid('(1,2),-1', 'circle');
+SELECT pg_input_error_message('(1,2),-1', 'circle');
-- 
2.18.0

From 5cc0f02ea41128e9c8588ab058319e1b93aef87b Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 12:19:47 +0530
Subject: [PATCH v1 07/14] Change cidr_in and inet_in to allow non-throw error
 reporting

---
 src/backend/utils/adt/network.c    | 14 +++++------
 src/test/regress/expected/inet.out | 37 ++++++++++++++++++++++++++++++
 src/test/regress/sql/inet.sql      |  9 ++++++++
 3 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index 6d580ea78f6..42a4d9d44ec 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -72,7 +72,7 @@ static inet *internal_inetpl(inet *ip, int64 addend);
  * Common INET/CIDR input routine
  */
 static inet *
-network_in(char *src, bool is_cidr)
+network_in(char *src, bool is_cidr, Node *escontext)
 {
 	int			bits;
 	inet	   *dst;
@@ -93,7 +93,7 @@ network_in(char *src, bool is_cidr)
 	bits = pg_inet_net_pton(ip_family(dst), src, ip_addr(dst),
 							is_cidr ? ip_addrsize(dst) : -1);
 	if ((bits < 0) || (bits > ip_maxbits(dst)))
-		ereport(ERROR,
+		ereturn(escontext, NULL,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 		/* translator: first %s is inet or cidr */
 				 errmsg("invalid input syntax for type %s: \"%s\"",
@@ -105,7 +105,7 @@ network_in(char *src, bool is_cidr)
 	if (is_cidr)
 	{
 		if (!addressOK(ip_addr(dst), bits, ip_family(dst)))
-			ereport(ERROR,
+			ereturn(escontext, NULL,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid cidr value: \"%s\"", src),
 					 errdetail("Value has bits set to right of mask.")));
@@ -122,7 +122,7 @@ inet_in(PG_FUNCTION_ARGS)
 {
 	char	   *src = PG_GETARG_CSTRING(0);
 
-	PG_RETURN_INET_P(network_in(src, false));
+	PG_RETURN_INET_P(network_in(src, false, fcinfo->context));
 }
 
 Datum
@@ -130,7 +130,7 @@ cidr_in(PG_FUNCTION_ARGS)
 {
 	char	   *src = PG_GETARG_CSTRING(0);
 
-	PG_RETURN_INET_P(network_in(src, true));
+	PG_RETURN_INET_P(network_in(src, true, fcinfo->context));
 }
 
 
@@ -1742,7 +1742,7 @@ inet_client_addr(PG_FUNCTION_ARGS)
 
 	clean_ipv6_addr(port->raddr.addr.ss_family, remote_host);
 
-	PG_RETURN_INET_P(network_in(remote_host, false));
+	PG_RETURN_INET_P(network_in(remote_host, false, NULL));
 }
 
 
@@ -1814,7 +1814,7 @@ inet_server_addr(PG_FUNCTION_ARGS)
 
 	clean_ipv6_addr(port->laddr.addr.ss_family, local_host);
 
-	PG_RETURN_INET_P(network_in(local_host, false));
+	PG_RETURN_INET_P(network_in(local_host, false, NULL));
 }
 
 
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index d5bf9e2aaa5..c9f466ac1d3 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -1056,3 +1056,40 @@ SELECT a FROM (VALUES
  ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
 (91 rows)
 
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('1234', 'cidr');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('1234', 'cidr');
+           pg_input_error_message           
+--------------------------------------------
+ invalid input syntax for type cidr: "1234"
+(1 row)
+
+SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('192.168.198.200/24', 'cidr');
+          pg_input_error_message          
+------------------------------------------
+ invalid cidr value: "192.168.198.200/24"
+(1 row)
+
+SELECT pg_input_is_valid('1234', 'inet');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('1234', 'inet');
+           pg_input_error_message           
+--------------------------------------------
+ invalid input syntax for type inet: "1234"
+(1 row)
+
diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql
index d2ac85bb7f0..abfcd4242f8 100644
--- a/src/test/regress/sql/inet.sql
+++ b/src/test/regress/sql/inet.sql
@@ -252,3 +252,12 @@ SELECT a FROM (VALUES
   ('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/0'::inet),
   ('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128'::inet)
 ) AS i(a) ORDER BY a;
+
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('1234', 'cidr');
+SELECT pg_input_error_message('1234', 'cidr');
+SELECT pg_input_is_valid('192.168.198.200/24', 'cidr');
+SELECT pg_input_error_message('192.168.198.200/24', 'cidr');
+
+SELECT pg_input_is_valid('1234', 'inet');
+SELECT pg_input_error_message('1234', 'inet');
-- 
2.18.0

From d17e37b36d809074955053dc96ea6680bce6a911 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 11:44:03 +0530
Subject: [PATCH v1 06/14] Change money_in to allow non-throw error reporting

---
 src/backend/utils/adt/cash.c        | 11 ++++++-----
 src/test/regress/expected/money.out | 25 +++++++++++++++++++++++++
 src/test/regress/sql/money.sql      |  6 ++++++
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c
index f7e78fa1056..32fbad2f57d 100644
--- a/src/backend/utils/adt/cash.c
+++ b/src/backend/utils/adt/cash.c
@@ -96,6 +96,7 @@ Datum
 cash_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
+	Node	   *escontext = fcinfo->context;
 	Cash		result;
 	Cash		value = 0;
 	Cash		dec = 0;
@@ -209,7 +210,7 @@ cash_in(PG_FUNCTION_ARGS)
 
 			if (pg_mul_s64_overflow(value, 10, &value) ||
 				pg_sub_s64_overflow(value, digit, &value))
-				ereport(ERROR,
+				ereturn(escontext, (Datum) 0,
 						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 						 errmsg("value \"%s\" is out of range for type %s",
 								str, "money")));
@@ -234,7 +235,7 @@ cash_in(PG_FUNCTION_ARGS)
 	{
 		/* remember we build the value in the negative */
 		if (pg_sub_s64_overflow(value, 1, &value))
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("value \"%s\" is out of range for type %s",
 							str, "money")));
@@ -244,7 +245,7 @@ cash_in(PG_FUNCTION_ARGS)
 	for (; dec < fpoint; dec++)
 	{
 		if (pg_mul_s64_overflow(value, 10, &value))
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("value \"%s\" is out of range for type %s",
 							str, "money")));
@@ -271,7 +272,7 @@ cash_in(PG_FUNCTION_ARGS)
 		else if (strncmp(s, csymbol, strlen(csymbol)) == 0)
 			s += strlen(csymbol);
 		else
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"money", str)));
@@ -284,7 +285,7 @@ cash_in(PG_FUNCTION_ARGS)
 	if (sgn > 0)
 	{
 		if (value == PG_INT64_MIN)
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("value \"%s\" is out of range for type %s",
 							str, "money")));
diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out
index fc71a72fed3..6b6f59005d2 100644
--- a/src/test/regress/expected/money.out
+++ b/src/test/regress/expected/money.out
@@ -503,3 +503,28 @@ SELECT '-92233720368547758.08'::money::numeric;
  -92233720368547758.08
 (1 row)
 
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('\x0001', 'money');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('\x0001', 'money');
+            pg_input_error_message             
+-----------------------------------------------
+ invalid input syntax for type money: "\x0001"
+(1 row)
+
+SELECT pg_input_is_valid('992233720368547758.07', 'money');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('192233720368547758.07', 'money');
+                    pg_input_error_message                    
+--------------------------------------------------------------
+ value "192233720368547758.07" is out of range for type money
+(1 row)
+
diff --git a/src/test/regress/sql/money.sql b/src/test/regress/sql/money.sql
index 5e746286c90..39886eb8266 100644
--- a/src/test/regress/sql/money.sql
+++ b/src/test/regress/sql/money.sql
@@ -129,3 +129,9 @@ SELECT '12345678901234567'::money::numeric;
 SELECT '-12345678901234567'::money::numeric;
 SELECT '92233720368547758.07'::money::numeric;
 SELECT '-92233720368547758.08'::money::numeric;
+
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('\x0001', 'money');
+SELECT pg_input_error_message('\x0001', 'money');
+SELECT pg_input_is_valid('992233720368547758.07', 'money');
+SELECT pg_input_error_message('192233720368547758.07', 'money');
-- 
2.18.0

From 139ef29a7074fa0aa2df472134f67c3793f846e4 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 10:59:32 +0530
Subject: [PATCH v1 05/14] Change brin_minmax_multi_summary_in to allow
 non-throw error reporting

---
 src/backend/access/brin/brin_minmax_multi.c |  2 +-
 src/test/regress/expected/type_sanity.out   | 12 ++++++++++++
 src/test/regress/sql/type_sanity.sql        |  3 +++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c
index 9a0bcf6698d..99ea7910c79 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -3003,7 +3003,7 @@ brin_minmax_multi_summary_in(PG_FUNCTION_ARGS)
 	 * brin_minmax_multi_summary stores the data in binary form and parsing
 	 * text input is not needed, so disallow this.
 	 */
-	ereport(ERROR,
+	ereturn(fcinfo->context, (Datum) 0,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("cannot accept a value of type %s", "brin_minmax_multi_summary")));
 
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index 95aa04e69ef..140dc6b948a 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -808,3 +808,15 @@ SELECT pg_input_error_message('1', 'pg_brin_bloom_summary');
  cannot accept a value of type pg_brin_bloom_summary
 (1 row)
 
+SELECT pg_input_is_valid('1', 'pg_brin_minmax_multi_summary');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('1', 'pg_brin_minmax_multi_summary');
+                 pg_input_error_message                  
+---------------------------------------------------------
+ cannot accept a value of type brin_minmax_multi_summary
+(1 row)
+
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index a75f6abfd27..7c1aff8a65b 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -599,3 +599,6 @@ SELECT pg_input_error_message('pg_monitor=rY', 'aclitem');
 
 SELECT pg_input_is_valid('1', 'pg_brin_bloom_summary');
 SELECT pg_input_error_message('1', 'pg_brin_bloom_summary');
+
+SELECT pg_input_is_valid('1', 'pg_brin_minmax_multi_summary');
+SELECT pg_input_error_message('1', 'pg_brin_minmax_multi_summary');
-- 
2.18.0

From 4cbdd4075c9b50820da4a954f6d2b806a2997e07 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 10:52:29 +0530
Subject: [PATCH v1 04/14] Change brin_bloom_summary_in to allow non-throw
 error reporting

---
 src/backend/access/brin/brin_bloom.c      |  2 +-
 src/test/regress/expected/type_sanity.out | 12 ++++++++++++
 src/test/regress/sql/type_sanity.sql      |  3 +++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/brin/brin_bloom.c b/src/backend/access/brin/brin_bloom.c
index 6b0af7267d5..883802cb5d9 100644
--- a/src/backend/access/brin/brin_bloom.c
+++ b/src/backend/access/brin/brin_bloom.c
@@ -745,7 +745,7 @@ brin_bloom_summary_in(PG_FUNCTION_ARGS)
 	 * brin_bloom_summary stores the data in binary form and parsing text
 	 * input is not needed, so disallow this.
 	 */
-	ereport(ERROR,
+	ereturn(fcinfo->context, (Datum) 0,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("cannot accept a value of type %s", "pg_brin_bloom_summary")));
 
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index b2bc0205a76..95aa04e69ef 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -796,3 +796,15 @@ SELECT pg_input_error_message('pg_monitor=rY', 'aclitem');
  invalid mode character: must be one of "arwdDxtXUCTcsAvz"
 (1 row)
 
+SELECT pg_input_is_valid('1', 'pg_brin_bloom_summary');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('1', 'pg_brin_bloom_summary');
+               pg_input_error_message                
+-----------------------------------------------------
+ cannot accept a value of type pg_brin_bloom_summary
+(1 row)
+
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index 080ac15b6c8..a75f6abfd27 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -596,3 +596,6 @@ SELECT pg_input_is_valid('pg_monitor=r/', 'aclitem');
 SELECT pg_input_error_message('pg_monitor=r/', 'aclitem');
 SELECT pg_input_is_valid('pg_monitor=rY', 'aclitem');
 SELECT pg_input_error_message('pg_monitor=rY', 'aclitem');
+
+SELECT pg_input_is_valid('1', 'pg_brin_bloom_summary');
+SELECT pg_input_error_message('1', 'pg_brin_bloom_summary');
-- 
2.18.0

From 92fe9e755d3f8e2ae49829f4c20f399a58652c6c Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Tue, 13 Dec 2022 16:21:32 +0530
Subject: [PATCH v1 03/14] Change box_in to allow non-throw error reporting

---
 src/backend/utils/adt/geo_ops.c   | 67 ++++++++++++++++++++-----------
 src/test/regress/expected/box.out | 25 ++++++++++++
 src/test/regress/sql/box.sql      |  6 +++
 3 files changed, 74 insertions(+), 24 deletions(-)

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 721ce6634f8..5655f2f64cd 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -31,6 +31,7 @@
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
+#include "nodes/miscnodes.h"
 #include "utils/float.h"
 #include "utils/fmgrprotos.h"
 #include "utils/geo_decls.h"
@@ -133,13 +134,15 @@ static float8 dist_ppoly_internal(Point *pt, POLYGON *poly);
 static float8 single_decode(char *num, char **endptr_p,
 							const char *type_name, const char *orig_string);
 static void single_encode(float8 x, StringInfo str);
-static void pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
-						const char *type_name, const char *orig_string);
+static bool pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
+						const char *type_name, const char *orig_string,
+						Node *escontext);
 static void pair_encode(float8 x, float8 y, StringInfo str);
 static int	pair_count(char *s, char delim);
-static void path_decode(char *str, bool opentype, int npts, Point *p,
+static bool path_decode(char *str, bool opentype, int npts, Point *p,
 						bool *isopen, char **endptr_p,
-						const char *type_name, const char *orig_string);
+						const char *type_name, const char *orig_string,
+						Node *escontext);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 
 
@@ -201,9 +204,10 @@ single_encode(float8 x, StringInfo str)
 	pfree(xstr);
 }								/* single_encode() */
 
-static void
+static bool
 pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
-			const char *type_name, const char *orig_string)
+			const char *type_name, const char *orig_string,
+			Node *escontext)
 {
 	bool		has_delim;
 
@@ -212,20 +216,24 @@ pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 	if ((has_delim = (*str == LDELIM)))
 		str++;
 
-	*x = float8in_internal(str, &str, type_name, orig_string, NULL);
+	*x = float8in_internal(str, &str, type_name, orig_string, escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return false;
 
 	if (*str++ != DELIM)
-		ereport(ERROR,
+		ereturn(escontext, false,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						type_name, orig_string)));
 
-	*y = float8in_internal(str, &str, type_name, orig_string, NULL);
+	*y = float8in_internal(str, &str, type_name, orig_string, escontext);
+	if (SOFT_ERROR_OCCURRED(escontext))
+		return false;
 
 	if (has_delim)
 	{
 		if (*str++ != RDELIM)
-			ereport(ERROR,
+			ereturn(escontext, false,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							type_name, orig_string)));
@@ -237,10 +245,11 @@ pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
 	if (endptr_p)
 		*endptr_p = str;
 	else if (*str != '\0')
-		ereport(ERROR,
+		ereturn(escontext, false,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						type_name, orig_string)));
+	return true;
 }
 
 static void
@@ -254,10 +263,11 @@ pair_encode(float8 x, float8 y, StringInfo str)
 	pfree(ystr);
 }
 
-static void
+static bool
 path_decode(char *str, bool opentype, int npts, Point *p,
 			bool *isopen, char **endptr_p,
-			const char *type_name, const char *orig_string)
+			const char *type_name, const char *orig_string,
+			Node *escontext)
 {
 	int			depth = 0;
 	char	   *cp;
@@ -269,7 +279,7 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 	{
 		/* no open delimiter allowed? */
 		if (!opentype)
-			ereport(ERROR,
+			ereturn(escontext, false,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							type_name, orig_string)));
@@ -295,7 +305,9 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 
 	for (i = 0; i < npts; i++)
 	{
-		pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
+		if (!pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string,
+						 escontext))
+			return false;
 		if (*str == DELIM)
 			str++;
 		p++;
@@ -311,7 +323,7 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 				str++;
 		}
 		else
-			ereport(ERROR,
+			ereturn(escontext, false,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							type_name, orig_string)));
@@ -321,10 +333,11 @@ path_decode(char *str, bool opentype, int npts, Point *p,
 	if (endptr_p)
 		*endptr_p = str;
 	else if (*str != '\0')
-		ereport(ERROR,
+		ereturn(escontext, false,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						type_name, orig_string)));
+	return true;
 }								/* path_decode() */
 
 static char *
@@ -413,12 +426,15 @@ Datum
 box_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
+	Node	   *escontext = fcinfo->context;
 	BOX		   *box = (BOX *) palloc(sizeof(BOX));
 	bool		isopen;
 	float8		x,
 				y;
 
-	path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
+	if (!path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str,
+					 escontext))
+		PG_RETURN_NULL();
 
 	/* reorder corners if necessary... */
 	if (float8_lt(box->high.x, box->low.x))
@@ -980,7 +996,7 @@ line_in(PG_FUNCTION_ARGS)
 	}
 	else
 	{
-		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str);
+		path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str, NULL);
 		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
@@ -1414,7 +1430,7 @@ path_in(PG_FUNCTION_ARGS)
 	SET_VARSIZE(path, size);
 	path->npts = npts;
 
-	path_decode(s, true, npts, &(path->p[0]), &isopen, &s, "path", str);
+	path_decode(s, true, npts, &(path->p[0]), &isopen, &s, "path", str, NULL);
 
 	if (depth >= 1)
 	{
@@ -1803,7 +1819,7 @@ point_in(PG_FUNCTION_ARGS)
 	char	   *str = PG_GETARG_CSTRING(0);
 	Point	   *point = (Point *) palloc(sizeof(Point));
 
-	pair_decode(str, &point->x, &point->y, NULL, "point", str);
+	pair_decode(str, &point->x, &point->y, NULL, "point", str, NULL);
 	PG_RETURN_POINT_P(point);
 }
 
@@ -2037,7 +2053,8 @@ lseg_in(PG_FUNCTION_ARGS)
 	LSEG	   *lseg = (LSEG *) palloc(sizeof(LSEG));
 	bool		isopen;
 
-	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str);
+	path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str,
+				NULL);
 	PG_RETURN_LSEG_P(lseg);
 }
 
@@ -3406,7 +3423,8 @@ poly_in(PG_FUNCTION_ARGS)
 	SET_VARSIZE(poly, size);
 	poly->npts = npts;
 
-	path_decode(str, false, npts, &(poly->p[0]), &isopen, NULL, "polygon", str);
+	path_decode(str, false, npts, &(poly->p[0]), &isopen, NULL, "polygon", str,
+				NULL);
 
 	make_bound_box(poly);
 
@@ -4594,7 +4612,8 @@ circle_in(PG_FUNCTION_ARGS)
 	}
 
 	/* pair_decode will consume parens around the pair, if any */
-	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
+	pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str,
+				NULL);
 
 	if (*s == DELIM)
 		s++;
diff --git a/src/test/regress/expected/box.out b/src/test/regress/expected/box.out
index 6bf4d0bdc6d..0d70194def5 100644
--- a/src/test/regress/expected/box.out
+++ b/src/test/regress/expected/box.out
@@ -639,3 +639,28 @@ WHERE seq.id IS NULL OR idx.id IS NULL;
 RESET enable_seqscan;
 RESET enable_indexscan;
 RESET enable_bitmapscan;
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('200', 'box');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('200', 'box');
+          pg_input_error_message          
+------------------------------------------
+ invalid input syntax for type box: "200"
+(1 row)
+
+SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('((200,300),(500, xyz))', 'box');
+                   pg_input_error_message                    
+-------------------------------------------------------------
+ invalid input syntax for type box: "((200,300),(500, xyz))"
+(1 row)
+
diff --git a/src/test/regress/sql/box.sql b/src/test/regress/sql/box.sql
index ceae58fc02f..02e100391b4 100644
--- a/src/test/regress/sql/box.sql
+++ b/src/test/regress/sql/box.sql
@@ -281,3 +281,9 @@ WHERE seq.id IS NULL OR idx.id IS NULL;
 RESET enable_seqscan;
 RESET enable_indexscan;
 RESET enable_bitmapscan;
+
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('200', 'box');
+SELECT pg_input_error_message('200', 'box');
+SELECT pg_input_is_valid('((200,300),(500, xyz))', 'box');
+SELECT pg_input_error_message('((200,300),(500, xyz))', 'box');
-- 
2.18.0

From 29c236c6552784229274e3803c2b05a20200a952 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Mon, 12 Dec 2022 12:46:54 +0530
Subject: [PATCH v1 02/14] Change bit_in to allow non-throw error reporting

---
 src/backend/utils/adt/varbit.c    |  9 ++++----
 src/test/regress/expected/bit.out | 37 +++++++++++++++++++++++++++++++
 src/test/regress/sql/bit.sql      |  8 +++++++
 3 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index 73e41e0808f..7519d6b6a35 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -152,6 +152,7 @@ bit_in(PG_FUNCTION_ARGS)
 	Oid			typelem = PG_GETARG_OID(1);
 #endif
 	int32		atttypmod = PG_GETARG_INT32(2);
+	Node	   *escontext = fcinfo->context;
 	VarBit	   *result;			/* The resulting bit string			  */
 	char	   *sp;				/* pointer into the character string  */
 	bits8	   *r;				/* pointer into the result */
@@ -193,7 +194,7 @@ bit_in(PG_FUNCTION_ARGS)
 	else
 	{
 		if (slen > VARBITMAXLEN / 4)
-			ereport(ERROR,
+			ereturn(escontext, (Datum) 0,
 					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 					 errmsg("bit string length exceeds the maximum allowed (%d)",
 							VARBITMAXLEN)));
@@ -207,7 +208,7 @@ bit_in(PG_FUNCTION_ARGS)
 	if (atttypmod <= 0)
 		atttypmod = bitlen;
 	else if (bitlen != atttypmod)
-		ereport(ERROR,
+		ereturn(escontext, (Datum) 0,
 				(errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
 				 errmsg("bit string length %d does not match type bit(%d)",
 						bitlen, atttypmod)));
@@ -229,7 +230,7 @@ bit_in(PG_FUNCTION_ARGS)
 			if (*sp == '1')
 				*r |= x;
 			else if (*sp != '0')
-				ereport(ERROR,
+				ereturn(escontext, (Datum) 0,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("\"%.*s\" is not a valid binary digit",
 								pg_mblen(sp), sp)));
@@ -254,7 +255,7 @@ bit_in(PG_FUNCTION_ARGS)
 			else if (*sp >= 'a' && *sp <= 'f')
 				x = (bits8) (*sp - 'a') + 10;
 			else
-				ereport(ERROR,
+				ereturn(escontext, (Datum) 0,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("\"%.*s\" is not a valid hexadecimal digit",
 								pg_mblen(sp), sp)));
diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out
index a5aab9c0e35..059fdf66156 100644
--- a/src/test/regress/expected/bit.out
+++ b/src/test/regress/expected/bit.out
@@ -746,3 +746,40 @@ TABLE bit_defaults;
  1001 | 0101 | 1001 | 0101
 (1 row)
 
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('01010001', 'bit(10)');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('01010001', 'bit(10)');
+             pg_input_error_message              
+-------------------------------------------------
+ bit string length 8 does not match type bit(10)
+(1 row)
+
+SELECT pg_input_is_valid('01010Z01', 'bit(8)');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('01010Z01', 'bit(8)');
+     pg_input_error_message      
+---------------------------------
+ "Z" is not a valid binary digit
+(1 row)
+
+SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('x01010Z01', 'bit(32)');
+        pg_input_error_message        
+--------------------------------------
+ "Z" is not a valid hexadecimal digit
+(1 row)
+
diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql
index 0a424e796b9..93100833c24 100644
--- a/src/test/regress/sql/bit.sql
+++ b/src/test/regress/sql/bit.sql
@@ -229,3 +229,11 @@ CREATE TABLE bit_defaults(
 \d bit_defaults
 INSERT INTO bit_defaults DEFAULT VALUES;
 TABLE bit_defaults;
+
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('01010001', 'bit(10)');
+SELECT pg_input_error_message('01010001', 'bit(10)');
+SELECT pg_input_is_valid('01010Z01', 'bit(8)');
+SELECT pg_input_error_message('01010Z01', 'bit(8)');
+SELECT pg_input_is_valid('x01010Z01', 'bit(32)');
+SELECT pg_input_error_message('x01010Z01', 'bit(32)');
-- 
2.18.0

From 0e56a01c00737bab39f3b0a192767e9f3110ecda Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Mon, 12 Dec 2022 11:18:23 +0530
Subject: [PATCH v1 01/14] Change aclitemin to allow non-throw error reporting

---
 src/backend/utils/adt/acl.c               | 23 +++++++++++++--------
 src/test/regress/expected/type_sanity.out | 25 +++++++++++++++++++++++
 src/test/regress/sql/type_sanity.sql      |  6 ++++++
 3 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index ed1b6a41cfb..8d0aa603aea 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -85,7 +85,7 @@ static const char *getid(const char *s, char *n);
 static void putid(char *p, const char *s);
 static Acl *allocacl(int n);
 static void check_acl(const Acl *acl);
-static const char *aclparse(const char *s, AclItem *aip);
+static const char *aclparse(const char *s, AclItem *aip, Node *escontext);
 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
 static int	aclitemComparator(const void *arg1, const void *arg2);
 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
@@ -238,7 +238,7 @@ putid(char *p, const char *s)
  *		  UID/GID, id type identifier and mode type values.
  */
 static const char *
-aclparse(const char *s, AclItem *aip)
+aclparse(const char *s, AclItem *aip, Node *escontext)
 {
 	AclMode		privs,
 				goption,
@@ -253,20 +253,20 @@ aclparse(const char *s, AclItem *aip)
 	{
 		/* we just read a keyword, not a name */
 		if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
-			ereport(ERROR,
+			ereturn(escontext, NULL,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("unrecognized key word: \"%s\"", name),
 					 errhint("ACL key word must be \"group\" or \"user\".")));
 		s = getid(s, name);		/* move s to the name beyond the keyword */
 		if (name[0] == '\0')
-			ereport(ERROR,
+			ereturn(escontext, NULL,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("missing name"),
 					 errhint("A name must follow the \"group\" or \"user\" key word.")));
 	}
 
 	if (*s != '=')
-		ereport(ERROR,
+		ereturn(escontext, NULL,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("missing \"=\" sign")));
 
@@ -331,7 +331,7 @@ aclparse(const char *s, AclItem *aip)
 				read = 0;
 				break;
 			default:
-				ereport(ERROR,
+				ereturn(escontext, NULL,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("invalid mode character: must be one of \"%s\"",
 								ACL_ALL_RIGHTS_STR)));
@@ -353,7 +353,7 @@ aclparse(const char *s, AclItem *aip)
 	{
 		s = getid(s + 1, name2);
 		if (name2[0] == '\0')
-			ereport(ERROR,
+			ereturn(escontext, NULL,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("a name must follow the \"/\" sign")));
 		aip->ai_grantor = get_role_oid(name2, false);
@@ -572,14 +572,19 @@ Datum
 aclitemin(PG_FUNCTION_ARGS)
 {
 	const char *s = PG_GETARG_CSTRING(0);
+	Node	   *escontext = fcinfo->context;
 	AclItem    *aip;
 
 	aip = (AclItem *) palloc(sizeof(AclItem));
-	s = aclparse(s, aip);
+
+	/* aclparse() returns NULL in case of soft-errors */
+	if ((s = aclparse(s, aip, escontext)) == NULL)
+		PG_RETURN_NULL();
+
 	while (isspace((unsigned char) *s))
 		++s;
 	if (*s)
-		ereport(ERROR,
+		ereturn(escontext, (Datum) 0,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("extra garbage at the end of the ACL specification")));
 
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index d3ac08c9ee3..b2bc0205a76 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -771,3 +771,28 @@ SELECT oid, typname, typtype, typelem, typarray
 -----+---------+---------+---------+----------
 (0 rows)
 
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('pg_monitor=r/', 'aclitem');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('pg_monitor=r/', 'aclitem');
+     pg_input_error_message      
+---------------------------------
+ a name must follow the "/" sign
+(1 row)
+
+SELECT pg_input_is_valid('pg_monitor=rY', 'aclitem');
+ pg_input_is_valid 
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('pg_monitor=rY', 'aclitem');
+                  pg_input_error_message                   
+-----------------------------------------------------------
+ invalid mode character: must be one of "arwdDxtXUCTcsAvz"
+(1 row)
+
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index 5edc1f1f6ed..080ac15b6c8 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -590,3 +590,9 @@ SELECT oid, typname, typtype, typelem, typarray
                     WHERE a.atttypid=t.oid AND
                           a.attnum > 0 AND
                           a.attrelid='tab_core_types'::regclass);
+
+-- test non-error-throwing API for some core types
+SELECT pg_input_is_valid('pg_monitor=r/', 'aclitem');
+SELECT pg_input_error_message('pg_monitor=r/', 'aclitem');
+SELECT pg_input_is_valid('pg_monitor=rY', 'aclitem');
+SELECT pg_input_error_message('pg_monitor=rY', 'aclitem');
-- 
2.18.0

Reply via email to