diff --git a/src/backend/utils/adt/bool.c b/src/backend/utils/adt/bool.c
index cd7335287f..d78f862421 100644
--- a/src/backend/utils/adt/bool.c
+++ b/src/backend/utils/adt/bool.c
@@ -148,12 +148,12 @@ boolin(PG_FUNCTION_ARGS)
 	if (parse_bool_with_len(str, len, &result))
 		PG_RETURN_BOOL(result);
 
-	ereport(ERROR,
+	ereturn(fcinfo->context,
 			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 			 errmsg("invalid input syntax for type %s: \"%s\"",
 					"boolean", in_str)));
 
-	/* not reached */
+	/* dummy result */
 	PG_RETURN_BOOL(false);
 }
 
diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index 42ddae99ef..e1837bee71 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -291,7 +291,7 @@ int4in(PG_FUNCTION_ARGS)
 {
 	char	   *num = PG_GETARG_CSTRING(0);
 
-	PG_RETURN_INT32(pg_strtoint32(num));
+	PG_RETURN_INT32(pg_strtoint32_safe(num, fcinfo->context));
 }
 
 /*
diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c
index 834ec0b588..7050d5825d 100644
--- a/src/backend/utils/adt/numutils.c
+++ b/src/backend/utils/adt/numutils.c
@@ -164,8 +164,11 @@ invalid_syntax:
 /*
  * Convert input string to a signed 32 bit integer.
  *
- * Allows any number of leading or trailing whitespace characters. Will throw
- * ereport() upon bad input format or overflow.
+ * Allows any number of leading or trailing whitespace characters.
+ *
+ * pg_strtoint32() will throw ereport() upon bad input format or overflow;
+ * while pg_strtoint32_safe() instead returns such complaints in *ercontext,
+ * if it's an ErrorReturnContext.
  *
  * NB: Accumulate input as a negative number, to deal with two's complement
  * representation of the most negative number, which can't be represented as a
@@ -173,6 +176,12 @@ invalid_syntax:
  */
 int32
 pg_strtoint32(const char *s)
+{
+	return pg_strtoint32_safe(s, NULL);
+}
+
+int32
+pg_strtoint32_safe(const char *s, Node *ercontext)
 {
 	const char *ptr = s;
 	int32		tmp = 0;
@@ -223,18 +232,18 @@ pg_strtoint32(const char *s)
 	return tmp;
 
 out_of_range:
-	ereport(ERROR,
+	ereturn(ercontext,
 			(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 			 errmsg("value \"%s\" is out of range for type %s",
 					s, "integer")));
+	return 0;					/* dummy result */
 
 invalid_syntax:
-	ereport(ERROR,
+	ereturn(ercontext,
 			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 			 errmsg("invalid input syntax for type %s: \"%s\"",
 					"integer", s)));
-
-	return 0;					/* keep compiler quiet */
+	return 0;					/* dummy result */
 }
 
 /*
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 81631f1645..894e3d8ba9 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -45,6 +45,7 @@ extern int	namestrcmp(Name name, const char *str);
 /* numutils.c */
 extern int16 pg_strtoint16(const char *s);
 extern int32 pg_strtoint32(const char *s);
+extern int32 pg_strtoint32_safe(const char *s, Node *ercontext);
 extern int64 pg_strtoint64(const char *s);
 extern int	pg_itoa(int16 i, char *a);
 extern int	pg_ultoa_n(uint32 value, char *a);
