From fd5e1ccffe2c1aa1c619fb0f31389f35fe554e5b Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Fri, 22 Apr 2022 06:17:51 -0400
Subject: [PATCH v2 5/5] Call numeric arithmetic functions directly

---
 contrib/btree_gist/btree_numeric.c          | 17 +++------
 src/backend/access/brin/brin_minmax_multi.c | 14 ++++----
 src/backend/utils/adt/cash.c                | 15 ++++----
 src/backend/utils/adt/dbsize.c              | 33 +++++++++--------
 src/backend/utils/adt/formatting.c          | 15 ++++----
 src/backend/utils/adt/jsonb.c               |  7 ++--
 src/backend/utils/adt/numeric.c             | 39 +++++++++++----------
 src/backend/utils/adt/pg_lsn.c              | 16 ++++-----
 src/backend/utils/adt/rangetypes.c          | 10 +++---
 9 files changed, 80 insertions(+), 86 deletions(-)

diff --git a/contrib/btree_gist/btree_numeric.c b/contrib/btree_gist/btree_numeric.c
index 35e466cdd94..6c50cfa41f2 100644
--- a/contrib/btree_gist/btree_numeric.c
+++ b/contrib/btree_gist/btree_numeric.c
@@ -174,17 +174,10 @@ gbt_numeric_penalty(PG_FUNCTION_ARGS)
 	ok = gbt_var_key_readable(org);
 	uk = gbt_var_key_readable((GBT_VARKEY *) DatumGetPointer(uni));
 
-	us = DatumGetNumeric(DirectFunctionCall2(numeric_sub,
-											 PointerGetDatum(uk.upper),
-											 PointerGetDatum(uk.lower)));
+	us = numeric_sub_opt_error((Numeric) uk.upper, (Numeric) uk.lower, NULL);
+	os = numeric_sub_opt_error((Numeric) ok.upper, (Numeric) ok.lower, NULL);
 
-	os = DatumGetNumeric(DirectFunctionCall2(numeric_sub,
-											 PointerGetDatum(ok.upper),
-											 PointerGetDatum(ok.lower)));
-
-	ds = DatumGetNumeric(DirectFunctionCall2(numeric_sub,
-											 NumericGetDatum(us),
-											 NumericGetDatum(os)));
+	ds = numeric_sub_opt_error(us, os, NULL);
 
 	if (numeric_is_nan(us))
 	{
@@ -202,9 +195,7 @@ gbt_numeric_penalty(PG_FUNCTION_ARGS)
 		if (DirectFunctionCall2(numeric_gt, NumericGetDatum(ds), NumericGetDatum(nul)))
 		{
 			*result += FLT_MIN;
-			os = DatumGetNumeric(DirectFunctionCall2(numeric_div,
-													 NumericGetDatum(ds),
-													 NumericGetDatum(us)));
+			os = numeric_div_opt_error(ds, us, NULL);
 			*result += (float4) DatumGetFloat8(DirectFunctionCall1(numeric_float8_no_overflow, NumericGetDatum(os)));
 		}
 	}
diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c
index 764efa381f2..c84a70d1ad9 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -2008,19 +2008,21 @@ brin_minmax_multi_distance_tid(PG_FUNCTION_ARGS)
 Datum
 brin_minmax_multi_distance_numeric(PG_FUNCTION_ARGS)
 {
-	Datum		d;
-	Datum		a1 = PG_GETARG_DATUM(0);
-	Datum		a2 = PG_GETARG_DATUM(1);
+	Numeric		res;
+	Numeric		a1 = PG_GETARG_NUMERIC(0);
+	Numeric		a2 = PG_GETARG_NUMERIC(1);
 
 	/*
 	 * We know the values are range boundaries, but the range may be collapsed
 	 * (i.e. single points), with equal values.
 	 */
-	Assert(DatumGetBool(DirectFunctionCall2(numeric_le, a1, a2)));
+	Assert(DatumGetBool(DirectFunctionCall2(numeric_le,
+											NumericGetDatum(a1),
+											NumericGetDatum(a2))));
 
-	d = DirectFunctionCall2(numeric_sub, a2, a1);	/* a2 - a1 */
+	res = numeric_sub_opt_error(a2, a1, NULL);	/* a2 - a1 */
 
-	PG_RETURN_FLOAT8(numeric_to_float8(DatumGetNumeric(d)));
+	PG_RETURN_FLOAT8(numeric_to_float8(res));
 }
 
 /*
diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c
index d05335dbd47..81f4eceee9c 100644
--- a/src/backend/utils/adt/cash.c
+++ b/src/backend/utils/adt/cash.c
@@ -1069,7 +1069,10 @@ cash_numeric(PG_FUNCTION_ARGS)
 											Int32GetDatum(fpoint));
 
 		/* Now we can safely divide ... */
-		quotient = DirectFunctionCall2(numeric_div, result, numeric_scale);
+		quotient =
+			NumericGetDatum(numeric_div_opt_error(DatumGetNumeric(result),
+												  DatumGetNumeric(numeric_scale),
+												  NULL));
 
 		/* ... and forcibly round to exactly the intended number of digits */
 		result = DirectFunctionCall2(numeric_round,
@@ -1086,12 +1089,12 @@ cash_numeric(PG_FUNCTION_ARGS)
 Datum
 numeric_cash(PG_FUNCTION_ARGS)
 {
-	Datum		amount = PG_GETARG_DATUM(0);
+	Numeric		amount = PG_GETARG_NUMERIC(0);
 	Cash		result;
 	int			fpoint;
 	int64		scale;
 	int			i;
-	Datum		numeric_scale;
+	Numeric		numeric_scale;
 	struct lconv *lconvert = PGLC_localeconv();
 
 	/* see comments about frac_digits in cash_in() */
@@ -1105,11 +1108,11 @@ numeric_cash(PG_FUNCTION_ARGS)
 		scale *= 10;
 
 	/* multiply the input amount by scale factor */
-	numeric_scale = NumericGetDatum(int64_to_numeric(scale));
-	amount = DirectFunctionCall2(numeric_mul, amount, numeric_scale);
+	numeric_scale = int64_to_numeric(scale);
+	amount = numeric_mul_opt_error(amount, numeric_scale, NULL);
 
 	/* note that numeric_to_int64 will round to nearest integer for us */
-	result = numeric_to_int64_type(DatumGetNumeric(amount), "money");
+	result = numeric_to_int64_type(amount, "money");
 
 	PG_RETURN_CASH(result);
 }
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index afd6a7ab623..10675d19bcb 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -620,22 +620,29 @@ numeric_absolute(Numeric n)
 static Numeric
 numeric_half_rounded(Numeric n)
 {
-	Datum		d = NumericGetDatum(n);
-	Datum		zero;
-	Datum		one;
-	Datum		two;
+	Numeric		d;
+	Numeric		zero;
+	Numeric		one;
+	Numeric		two;
 	Datum		result;
+	bool		gt;
+
+	zero = int64_to_numeric(0);
+	one = int64_to_numeric(1);
+	two = int64_to_numeric(2);
 
-	zero = NumericGetDatum(int64_to_numeric(0));
-	one = NumericGetDatum(int64_to_numeric(1));
-	two = NumericGetDatum(int64_to_numeric(2));
+	gt = DatumGetBool(DirectFunctionCall2(numeric_ge,
+										  NumericGetDatum(n),
+										  NumericGetDatum(zero)));
 
-	if (DatumGetBool(DirectFunctionCall2(numeric_ge, d, zero)))
-		d = DirectFunctionCall2(numeric_add, d, one);
+	if (gt)
+		d = numeric_add_opt_error(n, one, NULL);
 	else
-		d = DirectFunctionCall2(numeric_sub, d, one);
+		d = numeric_sub_opt_error(n, one, NULL);
 
-	result = DirectFunctionCall2(numeric_div_trunc, d, two);
+	result = DirectFunctionCall2(numeric_div_trunc,
+								 NumericGetDatum(d),
+								 NumericGetDatum(two));
 	return DatumGetNumeric(result);
 }
 
@@ -819,9 +826,7 @@ pg_size_bytes(PG_FUNCTION_ARGS)
 
 			mul_num = int64_to_numeric(multiplier);
 
-			num = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
-													  NumericGetDatum(mul_num),
-													  NumericGetDatum(num)));
+			num = numeric_mul_opt_error(mul_num, num, NULL);
 		}
 	}
 
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 97a4544ffc6..f19f94b8e5f 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -6178,9 +6178,9 @@ numeric_to_number(PG_FUNCTION_ARGS)
 		x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
 												NumericGetDatum(a),
 												NumericGetDatum(b)));
-		result = DirectFunctionCall2(numeric_mul,
-									 result,
-									 NumericGetDatum(x));
+		result = NumericGetDatum(numeric_mul_opt_error(DatumGetNumeric(result),
+													   x,
+													   NULL));
 	}
 
 	pfree(numstr);
@@ -6217,9 +6217,7 @@ numeric_to_char(PG_FUNCTION_ARGS)
 		x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
 												NumericGetDatum(value),
 												Int32GetDatum(0)));
-		numstr =
-			int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
-														   NumericGetDatum(x))));
+		numstr = int_to_roman(numeric_int4_opt_error(x, NULL));
 	}
 	else if (IS_EEEE(&Num))
 	{
@@ -6268,9 +6266,8 @@ numeric_to_char(PG_FUNCTION_ARGS)
 			x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
 													NumericGetDatum(a),
 													NumericGetDatum(b)));
-			val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
-													  NumericGetDatum(value),
-													  NumericGetDatum(x)));
+			val = numeric_mul_opt_error(value, x, NULL);
+
 			Num.pre += Num.multi;
 		}
 
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index 7b295c199d8..d595d99a03c 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -2156,17 +2156,16 @@ jsonb_int4(PG_FUNCTION_ARGS)
 {
 	Jsonb	   *in = PG_GETARG_JSONB_P(0);
 	JsonbValue	v;
-	Datum		retValue;
+	int32		retValue;
 
 	if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
 		cannotCastJsonbValue(v.type, "integer");
 
-	retValue = DirectFunctionCall1(numeric_int4,
-								   NumericGetDatum(v.val.numeric));
+	retValue = numeric_int4_opt_error(v.val.numeric, NULL);
 
 	PG_FREE_IF_COPY(in, 0);
 
-	PG_RETURN_DATUM(retValue);
+	PG_RETURN_INT32(retValue);
 }
 
 Datum
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index d83fe5a326d..c42e72c3193 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -5960,8 +5960,8 @@ numeric_poly_avg(PG_FUNCTION_ARGS)
 #ifdef HAVE_INT128
 	PolyNumAggState *state;
 	NumericVar	result;
-	Datum		countd,
-				sumd;
+	Numeric		count,
+				sum;
 
 	state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
 
@@ -5973,12 +5973,12 @@ numeric_poly_avg(PG_FUNCTION_ARGS)
 
 	int128_to_numericvar(state->sumX, &result);
 
-	countd = NumericGetDatum(int64_to_numeric(state->N));
-	sumd = NumericGetDatum(make_result(&result));
+	count = int64_to_numeric(state->N);
+	sum = make_result(&result);
 
 	free_var(&result);
 
-	PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+	PG_RETURN_NUMERIC(numeric_div_opt_error(sum, count, NULL));
 #else
 	return numeric_avg(fcinfo);
 #endif
@@ -5988,8 +5988,7 @@ Datum
 numeric_avg(PG_FUNCTION_ARGS)
 {
 	NumericAggState *state;
-	Datum		N_datum;
-	Datum		sumX_datum;
+	Numeric		sumX;
 	NumericVar	sumX_var;
 
 	state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -6009,14 +6008,14 @@ numeric_avg(PG_FUNCTION_ARGS)
 	if (state->nInfcount > 0)
 		PG_RETURN_NUMERIC(make_result(&const_ninf));
 
-	N_datum = NumericGetDatum(int64_to_numeric(state->N));
-
 	init_var(&sumX_var);
 	accum_sum_final(&state->sumX, &sumX_var);
-	sumX_datum = NumericGetDatum(make_result(&sumX_var));
+	sumX = make_result(&sumX_var);
 	free_var(&sumX_var);
 
-	PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumX_datum, N_datum));
+	PG_RETURN_NUMERIC(numeric_div_opt_error(sumX,
+											int64_to_numeric(state->N),
+											NULL));
 }
 
 Datum
@@ -6469,6 +6468,7 @@ Datum
 int8_sum(PG_FUNCTION_ARGS)
 {
 	Numeric		oldsum;
+	Numeric		result;
 
 	if (PG_ARGISNULL(0))
 	{
@@ -6492,9 +6492,10 @@ int8_sum(PG_FUNCTION_ARGS)
 		PG_RETURN_NUMERIC(oldsum);
 
 	/* OK to do the addition. */
-	PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,
-										NumericGetDatum(oldsum),
-										NumericGetDatum(int64_to_numeric(PG_GETARG_INT64(1)))));
+	result = numeric_add_opt_error(oldsum,
+								   int64_to_numeric(PG_GETARG_INT64(1)),
+								   NULL);
+	PG_RETURN_NUMERIC(result);
 }
 
 
@@ -6661,8 +6662,8 @@ int8_avg(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	Int8TransTypeData *transdata;
-	Datum		countd,
-				sumd;
+	Numeric		count,
+				sum;
 
 	if (ARR_HASNULL(transarray) ||
 		ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
@@ -6673,10 +6674,10 @@ int8_avg(PG_FUNCTION_ARGS)
 	if (transdata->count == 0)
 		PG_RETURN_NULL();
 
-	countd = NumericGetDatum(int64_to_numeric(transdata->count));
-	sumd = NumericGetDatum(int64_to_numeric(transdata->sum));
+	count = int64_to_numeric(transdata->count);
+	sum = int64_to_numeric(transdata->sum);
 
-	PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+	PG_RETURN_NUMERIC(numeric_div_opt_error(sum, count, NULL));
 }
 
 /*
diff --git a/src/backend/utils/adt/pg_lsn.c b/src/backend/utils/adt/pg_lsn.c
index e0991d4d2f6..9ee31859d07 100644
--- a/src/backend/utils/adt/pg_lsn.c
+++ b/src/backend/utils/adt/pg_lsn.c
@@ -270,7 +270,7 @@ pg_lsn_pli(PG_FUNCTION_ARGS)
 	XLogRecPtr	lsn = PG_GETARG_LSN(0);
 	Numeric		nbytes = PG_GETARG_NUMERIC(1);
 	Datum		num;
-	Datum		res;
+	Numeric		res;
 	char		buf[32];
 
 	if (numeric_is_nan(nbytes))
@@ -286,12 +286,10 @@ pg_lsn_pli(PG_FUNCTION_ARGS)
 							  Int32GetDatum(-1));
 
 	/* Add two numerics */
-	res = DirectFunctionCall2(numeric_add,
-							  NumericGetDatum(num),
-							  NumericGetDatum(nbytes));
+	res = numeric_add_opt_error(DatumGetNumeric(num), nbytes, NULL);
 
 	/* Convert to pg_lsn */
-	PG_RETURN_LSN(numeric_to_pg_lsn(DatumGetNumeric(res)));
+	PG_RETURN_LSN(numeric_to_pg_lsn(res));
 }
 
 /*
@@ -304,7 +302,7 @@ pg_lsn_mii(PG_FUNCTION_ARGS)
 	XLogRecPtr	lsn = PG_GETARG_LSN(0);
 	Numeric		nbytes = PG_GETARG_NUMERIC(1);
 	Datum		num;
-	Datum		res;
+	Numeric		res;
 	char		buf[32];
 
 	if (numeric_is_nan(nbytes))
@@ -320,10 +318,8 @@ pg_lsn_mii(PG_FUNCTION_ARGS)
 							  Int32GetDatum(-1));
 
 	/* Subtract two numerics */
-	res = DirectFunctionCall2(numeric_sub,
-							  NumericGetDatum(num),
-							  NumericGetDatum(nbytes));
+	res = numeric_sub_opt_error(DatumGetNumeric(num), nbytes, NULL);
 
 	/* Convert to pg_lsn */
-	PG_RETURN_LSN(numeric_to_pg_lsn(DatumGetNumeric(res)));
+	PG_RETURN_LSN(numeric_to_pg_lsn(res));
 }
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c
index 8fb67387cc5..e0b339ab1f7 100644
--- a/src/backend/utils/adt/rangetypes.c
+++ b/src/backend/utils/adt/rangetypes.c
@@ -1571,14 +1571,14 @@ int8range_subdiff(PG_FUNCTION_ARGS)
 Datum
 numrange_subdiff(PG_FUNCTION_ARGS)
 {
-	Datum		v1 = PG_GETARG_DATUM(0);
-	Datum		v2 = PG_GETARG_DATUM(1);
-	Datum		numresult;
+	Numeric		v1 = PG_GETARG_NUMERIC(0);
+	Numeric		v2 = PG_GETARG_NUMERIC(1);
+	Numeric		numresult;
 	float8		floatresult;
 
-	numresult = DirectFunctionCall2(numeric_sub, v1, v2);
+	numresult = numeric_sub_opt_error(v1, v2, NULL);
 
-	floatresult = numeric_to_float8(DatumGetNumeric(numresult));
+	floatresult = numeric_to_float8(numresult);
 
 	PG_RETURN_FLOAT8(floatresult);
 }
-- 
2.18.0

