From 0b566e392ed0dc6c5038d1a6dfb982a8e7c2d62c Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Fri, 1 Mar 2019 03:15:18 +0300
Subject: [PATCH 02/13] Suppression of numeric errors in jsonpath

---
 src/backend/utils/adt/float.c                |  54 +++++---
 src/backend/utils/adt/jsonpath_exec.c        |  76 +++++++----
 src/backend/utils/adt/numeric.c              | 190 +++++++++++++++++++++------
 src/include/utils/float.h                    |   2 +
 src/include/utils/numeric.h                  |   7 +
 src/test/regress/expected/jsonb_jsonpath.out |  35 ++++-
 6 files changed, 275 insertions(+), 89 deletions(-)

diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 37c202d..d338d36 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -336,6 +336,15 @@ float8in(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num));
 }
 
+#define float8in_ereport(code, msg) \
+	do { \
+		if (error) { \
+			*error = true; \
+			return (Datum) 0; \
+		} else \
+			ereport(ERROR, ((code), (msg))); \
+	} while (false) \
+
 /*
  * float8in_internal - guts of float8in()
  *
@@ -355,8 +364,8 @@ float8in(PG_FUNCTION_ARGS)
  * unreasonable amount of extra casting both here and in callers, so we don't.
  */
 double
-float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string)
+float8in_internal_error(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string, bool *error)
 {
 	double		val;
 	char	   *endptr;
@@ -370,10 +379,10 @@ float8in_internal(char *num, char **endptr_p,
 	 * strtod() on different platforms.
 	 */
 	if (*num == '\0')
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-				 errmsg("invalid input syntax for type %s: \"%s\"",
-						type_name, orig_string)));
+		float8in_ereport(
+				errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				errmsg("invalid input syntax for type %s: \"%s\"",
+						type_name, orig_string));
 
 	errno = 0;
 	val = strtod(num, &endptr);
@@ -446,17 +455,17 @@ float8in_internal(char *num, char **endptr_p,
 				char	   *errnumber = pstrdup(num);
 
 				errnumber[endptr - num] = '\0';
-				ereport(ERROR,
-						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-						 errmsg("\"%s\" is out of range for type double precision",
-								errnumber)));
+				float8in_ereport(
+						errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+						errmsg("\"%s\" is out of range for type double precision",
+								errnumber));
 			}
 		}
 		else
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-					 errmsg("invalid input syntax for type %s: \"%s\"",
-							type_name, orig_string)));
+			float8in_ereport(
+					errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+					errmsg("invalid input syntax for type %s: \"%s\"",
+							type_name, orig_string));
 	}
 #ifdef HAVE_BUGGY_SOLARIS_STRTOD
 	else
@@ -479,14 +488,23 @@ float8in_internal(char *num, char **endptr_p,
 	if (endptr_p)
 		*endptr_p = endptr;
 	else if (*endptr != '\0')
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-				 errmsg("invalid input syntax for type %s: \"%s\"",
-						type_name, orig_string)));
+		float8in_ereport(
+				errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				errmsg("invalid input syntax for type %s: \"%s\"",
+						type_name, orig_string));
 
 	return val;
 }
 
+double
+float8in_internal(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string)
+{
+	return float8in_internal_error(num, endptr_p, type_name,
+								   orig_string, NULL);
+}
+
+
 /*
  *		float8out		- converts float8 number to a string
  *						  using a standard output format
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 87f432b..c6a5073 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -179,6 +179,8 @@ typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp,
 												   JsonbValue *rarg,
 												   void *param);
 
+typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
+
 static JsonPathExecResult executeJsonPath(JsonPath *path, Jsonb *vars,
 				Jsonb *json, bool throwErrors, JsonValueList *result);
 static JsonPathExecResult recursiveExecute(JsonPathExecContext *cxt,
@@ -209,7 +211,7 @@ static JsonPathBool executePredicate(JsonPathExecContext *cxt,
 				 JsonbValue *jb, bool unwrapRightArg,
 				 JsonPathPredicateCallback exec, void *param);
 static JsonPathExecResult executeBinaryArithmExpr(JsonPathExecContext *cxt,
-						JsonPathItem *jsp, JsonbValue *jb, PGFunction func,
+						JsonPathItem *jsp, JsonbValue *jb, BinaryArithmFunc func,
 						JsonValueList *found);
 static JsonPathExecResult executeUnaryArithmExpr(JsonPathExecContext *cxt,
 					   JsonPathItem *jsp, JsonbValue *jb, PGFunction func,
@@ -826,23 +828,23 @@ recursiveExecuteUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
 
 		case jpiAdd:
 			return executeBinaryArithmExpr(cxt, jsp, jb,
-										   numeric_add, found);
+										   numeric_add_error, found);
 
 		case jpiSub:
 			return executeBinaryArithmExpr(cxt, jsp, jb,
-										   numeric_sub, found);
+										   numeric_sub_error, found);
 
 		case jpiMul:
 			return executeBinaryArithmExpr(cxt, jsp, jb,
-										   numeric_mul, found);
+										   numeric_mul_error, found);
 
 		case jpiDiv:
 			return executeBinaryArithmExpr(cxt, jsp, jb,
-										   numeric_div, found);
+										   numeric_div_error, found);
 
 		case jpiMod:
 			return executeBinaryArithmExpr(cxt, jsp, jb,
-										   numeric_mod, found);
+										   numeric_mod_error, found);
 
 		case jpiPlus:
 			return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
@@ -994,27 +996,39 @@ recursiveExecuteUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
 				{
 					char	   *tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
 																		  NumericGetDatum(jb->val.numeric)));
+					bool		error = false;
+
+					(void) float8in_internal_error(tmp,
+											NULL,
+											"double precision",
+											tmp,
+											&error);
 
-					(void) float8in_internal(tmp,
-											 NULL,
-											 "double precision",
-											 tmp);
+					if (error)
+						RETURN_ERROR(ereport(ERROR,
+											 (errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
+											  errmsg(ERRMSG_NON_NUMERIC_JSON_ITEM),
+											  errdetail("jsonpath item method .%s() is "
+														"applied to not a numeric value",
+														jspOperationName(jsp->type)))));
 
 					res = jperOk;
 				}
 				else if (jb->type == jbvString)
 				{
 					/* cast string as double */
+					bool		error = false;
 					double		val;
 					char	   *tmp = pnstrdup(jb->val.string.val,
 											   jb->val.string.len);
 
-					val = float8in_internal(tmp,
-											NULL,
-											"double precision",
-											tmp);
+					val = float8in_internal_error(tmp,
+												  NULL,
+												  "double precision",
+												  tmp,
+												  &error);
 
-					if (isinf(val))
+					if (error || isinf(val))
 						RETURN_ERROR(ereport(ERROR,
 											 (errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
 											  errmsg(ERRMSG_NON_NUMERIC_JSON_ITEM),
@@ -1482,7 +1496,7 @@ executePredicate(JsonPathExecContext *cxt, JsonPathItem *pred,
  */
 static JsonPathExecResult
 executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
-						JsonbValue *jb, PGFunction func,
+						JsonbValue *jb, BinaryArithmFunc func,
 						JsonValueList *found)
 {
 	JsonPathExecResult jper;
@@ -1491,7 +1505,7 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
 	JsonValueList rseq = {0};
 	JsonbValue *lval;
 	JsonbValue *rval;
-	Datum		res;
+	Numeric		res;
 
 	jspGetLeftArg(jsp, &elem);
 
@@ -1527,16 +1541,26 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
 										"is not a singleton numeric value",
 										jspOperationName(jsp->type)))));
 
-	res = DirectFunctionCall2(func,
-							  NumericGetDatum(lval->val.numeric),
-							  NumericGetDatum(rval->val.numeric));
+	if (jspThrowErrors(cxt))
+	{
+		res = func(lval->val.numeric, rval->val.numeric, NULL);
+	}
+	else
+	{
+		bool	error = false;
+
+		res = func(lval->val.numeric, rval->val.numeric, &error);
+
+		if (error)
+			return jperError;
+	}
 
 	if (!jspGetNext(jsp, &elem) && !found)
 		return jperOk;
 
 	lval = palloc(sizeof(*lval));
 	lval->type = jbvNumeric;
-	lval->val.numeric = DatumGetNumeric(res);
+	lval->val.numeric = res;
 
 	return recursiveExecuteNext(cxt, jsp, &elem, lval, found, false);
 }
@@ -2089,6 +2113,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
 	JsonValueList found = {0};
 	JsonPathExecResult res = recursiveExecute(cxt, jsp, jb, &found);
 	Datum		numeric_index;
+	bool		error = false;
 
 	if (jperIsError(res))
 		return res;
@@ -2105,7 +2130,14 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
 										NumericGetDatum(jbv->val.numeric),
 										Int32GetDatum(0));
 
-	*index = DatumGetInt32(DirectFunctionCall1(numeric_int4, numeric_index));
+	*index = numeric_int4_error(DatumGetNumeric(numeric_index), &error);
+
+	if (error)
+		RETURN_ERROR(ereport(ERROR,
+							 (errcode(ERRCODE_INVALID_JSON_SUBSCRIPT),
+							  errmsg(ERRMSG_INVALID_JSON_SUBSCRIPT),
+							  errdetail("jsonpath array subscript is out of "
+										"integer range"))));
 
 	return jperOk;
 }
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 1c9deeb..38c3313 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -475,10 +475,11 @@ static char *get_str_from_var(const NumericVar *var);
 static char *get_str_from_var_sci(const NumericVar *var, int rscale);
 
 static Numeric make_result(const NumericVar *var);
+static Numeric make_result_error(const NumericVar *var, bool *error);
 
 static void apply_typmod(NumericVar *var, int32 typmod);
 
-static int32 numericvar_to_int32(const NumericVar *var);
+static bool numericvar_to_int32(const NumericVar *var, int32 *result);
 static bool numericvar_to_int64(const NumericVar *var, int64 *result);
 static void int64_to_numericvar(int64 val, NumericVar *var);
 #ifdef HAVE_INT128
@@ -1558,7 +1559,10 @@ width_bucket_numeric(PG_FUNCTION_ARGS)
 	}
 
 	/* if result exceeds the range of a legal int4, we ereport here */
-	result = numericvar_to_int32(&result_var);
+	if (!numericvar_to_int32(&result_var, &result))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("integer out of range")));
 
 	free_var(&count_var);
 	free_var(&result_var);
@@ -2406,6 +2410,17 @@ numeric_add(PG_FUNCTION_ARGS)
 {
 	Numeric		num1 = PG_GETARG_NUMERIC(0);
 	Numeric		num2 = PG_GETARG_NUMERIC(1);
+	Numeric		res;
+
+	res = numeric_add_error(num1, num2, NULL);
+
+	PG_RETURN_NUMERIC(res);
+}
+
+
+Numeric
+numeric_add_error(Numeric num1, Numeric num2, bool *error)
+{
 	NumericVar	arg1;
 	NumericVar	arg2;
 	NumericVar	result;
@@ -2415,7 +2430,7 @@ numeric_add(PG_FUNCTION_ARGS)
 	 * Handle NaN
 	 */
 	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
-		PG_RETURN_NUMERIC(make_result(&const_nan));
+		return make_result(&const_nan);
 
 	/*
 	 * Unpack the values, let add_var() compute the result and return it.
@@ -2426,11 +2441,11 @@ numeric_add(PG_FUNCTION_ARGS)
 	init_var(&result);
 	add_var(&arg1, &arg2, &result);
 
-	res = make_result(&result);
+	res = make_result_error(&result, error);
 
 	free_var(&result);
 
-	PG_RETURN_NUMERIC(res);
+	return res;
 }
 
 
@@ -2444,6 +2459,17 @@ numeric_sub(PG_FUNCTION_ARGS)
 {
 	Numeric		num1 = PG_GETARG_NUMERIC(0);
 	Numeric		num2 = PG_GETARG_NUMERIC(1);
+	Numeric		res;
+
+	res = numeric_sub_error(num1, num2, NULL);
+
+	PG_RETURN_NUMERIC(res);
+}
+
+
+Numeric
+numeric_sub_error(Numeric num1, Numeric num2, bool *error)
+{
 	NumericVar	arg1;
 	NumericVar	arg2;
 	NumericVar	result;
@@ -2453,7 +2479,7 @@ numeric_sub(PG_FUNCTION_ARGS)
 	 * Handle NaN
 	 */
 	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
-		PG_RETURN_NUMERIC(make_result(&const_nan));
+		return make_result(&const_nan);
 
 	/*
 	 * Unpack the values, let sub_var() compute the result and return it.
@@ -2464,11 +2490,11 @@ numeric_sub(PG_FUNCTION_ARGS)
 	init_var(&result);
 	sub_var(&arg1, &arg2, &result);
 
-	res = make_result(&result);
+	res = make_result_error(&result, error);
 
 	free_var(&result);
 
-	PG_RETURN_NUMERIC(res);
+	return res;
 }
 
 
@@ -2482,6 +2508,17 @@ numeric_mul(PG_FUNCTION_ARGS)
 {
 	Numeric		num1 = PG_GETARG_NUMERIC(0);
 	Numeric		num2 = PG_GETARG_NUMERIC(1);
+	Numeric		res;
+
+	res = numeric_mul_error(num1, num2, NULL);
+
+	PG_RETURN_NUMERIC(res);
+}
+
+
+Numeric
+numeric_mul_error(Numeric num1, Numeric num2, bool *error)
+{
 	NumericVar	arg1;
 	NumericVar	arg2;
 	NumericVar	result;
@@ -2491,7 +2528,7 @@ numeric_mul(PG_FUNCTION_ARGS)
 	 * Handle NaN
 	 */
 	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
-		PG_RETURN_NUMERIC(make_result(&const_nan));
+		return make_result(&const_nan);
 
 	/*
 	 * Unpack the values, let mul_var() compute the result and return it.
@@ -2506,11 +2543,11 @@ numeric_mul(PG_FUNCTION_ARGS)
 	init_var(&result);
 	mul_var(&arg1, &arg2, &result, arg1.dscale + arg2.dscale);
 
-	res = make_result(&result);
+	res = make_result_error(&result, error);
 
 	free_var(&result);
 
-	PG_RETURN_NUMERIC(res);
+	return res;
 }
 
 
@@ -2524,6 +2561,17 @@ numeric_div(PG_FUNCTION_ARGS)
 {
 	Numeric		num1 = PG_GETARG_NUMERIC(0);
 	Numeric		num2 = PG_GETARG_NUMERIC(1);
+	Numeric		res;
+
+	res = numeric_div_error(num1, num2, NULL);
+
+	PG_RETURN_NUMERIC(res);
+}
+
+
+Numeric
+numeric_div_error(Numeric num1, Numeric num2, bool *error)
+{
 	NumericVar	arg1;
 	NumericVar	arg2;
 	NumericVar	result;
@@ -2534,7 +2582,7 @@ numeric_div(PG_FUNCTION_ARGS)
 	 * Handle NaN
 	 */
 	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
-		PG_RETURN_NUMERIC(make_result(&const_nan));
+		return make_result(&const_nan);
 
 	/*
 	 * Unpack the arguments
@@ -2552,13 +2600,19 @@ numeric_div(PG_FUNCTION_ARGS)
 	/*
 	 * Do the divide and return the result
 	 */
+	if (error && (arg2.ndigits == 0 || arg2.digits[0] == 0))
+	{
+		*error = true;
+		return NULL;
+	}
+
 	div_var(&arg1, &arg2, &result, rscale, true);
 
-	res = make_result(&result);
+	res = make_result_error(&result, error);
 
 	free_var(&result);
 
-	PG_RETURN_NUMERIC(res);
+	return res;
 }
 
 
@@ -2615,25 +2669,42 @@ numeric_mod(PG_FUNCTION_ARGS)
 	Numeric		num1 = PG_GETARG_NUMERIC(0);
 	Numeric		num2 = PG_GETARG_NUMERIC(1);
 	Numeric		res;
+
+	res = numeric_mod_error(num1, num2, NULL);
+
+	PG_RETURN_NUMERIC(res);
+}
+
+
+Numeric
+numeric_mod_error(Numeric num1, Numeric num2, bool *error)
+{
+	Numeric		res;
 	NumericVar	arg1;
 	NumericVar	arg2;
 	NumericVar	result;
 
 	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
-		PG_RETURN_NUMERIC(make_result(&const_nan));
+		return make_result(&const_nan);
 
 	init_var_from_num(num1, &arg1);
 	init_var_from_num(num2, &arg2);
 
 	init_var(&result);
 
+	if (error && (arg2.ndigits == 0 || arg2.digits[0] == 0))
+	{
+		*error = true;
+		return NULL;
+	}
+
 	mod_var(&arg1, &arg2, &result);
 
-	res = make_result(&result);
+	res = make_result_error(&result, NULL);
 
 	free_var(&result);
 
-	PG_RETURN_NUMERIC(res);
+	return res;
 }
 
 
@@ -3090,52 +3161,71 @@ int4_numeric(PG_FUNCTION_ARGS)
 	PG_RETURN_NUMERIC(res);
 }
 
-
-Datum
-numeric_int4(PG_FUNCTION_ARGS)
+int32
+numeric_int4_error(Numeric num, bool *error)
 {
-	Numeric		num = PG_GETARG_NUMERIC(0);
 	NumericVar	x;
 	int32		result;
 
 	/* XXX would it be better to return NULL? */
 	if (NUMERIC_IS_NAN(num))
+	{
+		if (error)
+		{
+			*error = true;
+			return 0;
+		}
+
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot convert NaN to integer")));
+	}
 
 	/* Convert to variable format, then convert to int4 */
 	init_var_from_num(num, &x);
-	result = numericvar_to_int32(&x);
-	PG_RETURN_INT32(result);
+
+	if (!numericvar_to_int32(&x, &result))
+	{
+		if (error)
+		{
+			*error = true;
+			return 0;
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("integer out of range")));
+	}
+
+	return result;
+}
+
+Datum
+numeric_int4(PG_FUNCTION_ARGS)
+{
+	Numeric		num = PG_GETARG_NUMERIC(0);
+
+	PG_RETURN_INT32(numeric_int4_error(num, NULL));
 }
 
 /*
  * Given a NumericVar, convert it to an int32. If the NumericVar
- * exceeds the range of an int32, raise the appropriate error via
- * ereport(). The input NumericVar is *not* free'd.
+ * exceeds the range of an int32, false is returned, otherwise true is returned.
+ * The input NumericVar is *not* free'd.
  */
-static int32
-numericvar_to_int32(const NumericVar *var)
+static bool
+numericvar_to_int32(const NumericVar *var, int32 *result)
 {
-	int32		result;
 	int64		val;
 
 	if (!numericvar_to_int64(var, &val))
-		ereport(ERROR,
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-				 errmsg("integer out of range")));
+		return false;
 
 	/* Down-convert to int4 */
-	result = (int32) val;
+	*result = (int32) val;
 
 	/* Test for overflow by reverse-conversion. */
-	if ((int64) result != val)
-		ereport(ERROR,
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-				 errmsg("integer out of range")));
-
-	return result;
+	return ((int64) *result == val);
 }
 
 Datum
@@ -6097,6 +6187,12 @@ get_str_from_var_sci(const NumericVar *var, int rscale)
 }
 
 
+static Numeric
+make_result(const NumericVar *var)
+{
+	return make_result_error(var, NULL);
+}
+
 /*
  * make_result() -
  *
@@ -6104,7 +6200,7 @@ get_str_from_var_sci(const NumericVar *var, int rscale)
  *	a variable.
  */
 static Numeric
-make_result(const NumericVar *var)
+make_result_error(const NumericVar *var, bool *error)
 {
 	Numeric		result;
 	NumericDigit *digits = var->digits;
@@ -6175,9 +6271,19 @@ make_result(const NumericVar *var)
 	/* Check for overflow of int16 fields */
 	if (NUMERIC_WEIGHT(result) != weight ||
 		NUMERIC_DSCALE(result) != var->dscale)
-		ereport(ERROR,
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-				 errmsg("value overflows numeric format")));
+	{
+		if (error)
+		{
+			*error = true;
+			return NULL;
+		}
+		else
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+					 errmsg("value overflows numeric format")));
+		}
+	}
 
 	dump_numeric("make_result()", result);
 	return result;
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index 0f82a25..b4599e8 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -40,6 +40,8 @@ extern PGDLLIMPORT int extra_float_digits;
 extern int	is_infinite(float8 val);
 extern float8 float8in_internal(char *num, char **endptr_p,
 				  const char *type_name, const char *orig_string);
+extern float8 float8in_internal_error(char *num, char **endptr_p,
+				  const char *type_name, const char *orig_string, bool *error);
 extern char *float8out_internal(float8 num);
 extern int	float4_cmp_internal(float4 a, float4 b);
 extern int	float8_cmp_internal(float8 a, float8 b);
diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h
index 9109cff..199f202 100644
--- a/src/include/utils/numeric.h
+++ b/src/include/utils/numeric.h
@@ -61,4 +61,11 @@ int32		numeric_maximum_size(int32 typmod);
 extern char *numeric_out_sci(Numeric num, int scale);
 extern char *numeric_normalize(Numeric num);
 
+extern Numeric numeric_add_error(Numeric num1, Numeric num2, bool *error);
+extern Numeric numeric_sub_error(Numeric num1, Numeric num2, bool *error);
+extern Numeric numeric_mul_error(Numeric num1, Numeric num2, bool *error);
+extern Numeric numeric_div_error(Numeric num1, Numeric num2, bool *error);
+extern Numeric numeric_mod_error(Numeric num1, Numeric num2, bool *error);
+extern int32 numeric_int4_error(Numeric num, bool *error);
+
 #endif							/* _PG_NUMERIC_H_ */
diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out
index f295b92..2202ffa 100644
--- a/src/test/regress/expected/jsonb_jsonpath.out
+++ b/src/test/regress/expected/jsonb_jsonpath.out
@@ -122,13 +122,23 @@ select jsonb_path_query('[1]', 'strict $[1]');
 ERROR:  invalid SQL/JSON subscript
 DETAIL:  jsonpath array subscript is out of bounds
 select jsonb '[1]' @? 'lax $[10000000000000000]';
-ERROR:  integer out of range
+ ?column? 
+----------
+ 
+(1 row)
+
 select jsonb '[1]' @? 'strict $[10000000000000000]';
-ERROR:  integer out of range
+ ?column? 
+----------
+ 
+(1 row)
+
 select jsonb_path_query('[1]', 'lax $[10000000000000000]');
-ERROR:  integer out of range
+ERROR:  invalid SQL/JSON subscript
+DETAIL:  jsonpath array subscript is out of integer range
 select jsonb_path_query('[1]', 'strict $[10000000000000000]');
-ERROR:  integer out of range
+ERROR:  invalid SQL/JSON subscript
+DETAIL:  jsonpath array subscript is out of integer range
 select jsonb '[1]' @? '$[0]';
  ?column? 
 ----------
@@ -956,9 +966,19 @@ select jsonb '1' @? '$ ? ($ > 0)';
 
 -- arithmetic errors
 select jsonb_path_query('[1,2,0,3]', '$[*] ? (2 / @ > 0)');
-ERROR:  division by zero
+ jsonb_path_query 
+------------------
+ 1
+ 2
+ 3
+(3 rows)
+
 select jsonb_path_query('[1,2,0,3]', '$[*] ? ((2 / @ > 0) is unknown)');
-ERROR:  division by zero
+ jsonb_path_query 
+------------------
+ 0
+(1 row)
+
 select jsonb_path_query('0', '1 / $');
 ERROR:  division by zero
 select jsonb_path_query('0', '1 / $ + 2');
@@ -1341,7 +1361,8 @@ select jsonb_path_query('"1.23"', '$.double()');
 (1 row)
 
 select jsonb_path_query('"1.23aaa"', '$.double()');
-ERROR:  invalid input syntax for type double precision: "1.23aaa"
+ERROR:  non-numeric SQL/JSON item
+DETAIL:  jsonpath item method .double() is applied to not a numeric value
 select jsonb_path_query('"nan"', '$.double()');
  jsonb_path_query 
 ------------------
-- 
2.7.4

