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

