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

