summaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/numeric.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/numeric.c')
-rw-r--r--src/backend/utils/adt/numeric.c266
1 files changed, 84 insertions, 182 deletions
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index b6287f5d973..76269918593 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -517,7 +517,7 @@ static void numericvar_deserialize(StringInfo buf, NumericVar *var);
static Numeric duplicate_numeric(Numeric num);
static Numeric make_result(const NumericVar *var);
-static Numeric make_result_opt_error(const NumericVar *var, bool *have_error);
+static Numeric make_result_safe(const NumericVar *var, Node *escontext);
static bool apply_typmod(NumericVar *var, int32 typmod, Node *escontext);
static bool apply_typmod_special(Numeric num, int32 typmod, Node *escontext);
@@ -717,7 +717,6 @@ numeric_in(PG_FUNCTION_ARGS)
*/
NumericVar value;
int base;
- bool have_error;
init_var(&value);
@@ -776,12 +775,7 @@ numeric_in(PG_FUNCTION_ARGS)
if (!apply_typmod(&value, typmod, escontext))
PG_RETURN_NULL();
- res = make_result_opt_error(&value, &have_error);
-
- if (have_error)
- ereturn(escontext, (Datum) 0,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("value overflows numeric format")));
+ res = make_result_safe(&value, escontext);
free_var(&value);
}
@@ -2874,20 +2868,18 @@ numeric_add(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
- res = numeric_add_opt_error(num1, num2, NULL);
+ res = numeric_add_safe(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
/*
- * numeric_add_opt_error() -
+ * numeric_add_safe() -
*
- * Internal version of numeric_add(). If "*have_error" flag is provided,
- * on error it's set to true, NULL returned. This is helpful when caller
- * need to handle errors by itself.
+ * Internal version of numeric_add() with support for soft error reporting.
*/
Numeric
-numeric_add_opt_error(Numeric num1, Numeric num2, bool *have_error)
+numeric_add_safe(Numeric num1, Numeric num2, Node *escontext)
{
NumericVar arg1;
NumericVar arg2;
@@ -2931,7 +2923,7 @@ numeric_add_opt_error(Numeric num1, Numeric num2, bool *have_error)
init_var(&result);
add_var(&arg1, &arg2, &result);
- res = make_result_opt_error(&result, have_error);
+ res = make_result_safe(&result, escontext);
free_var(&result);
@@ -2951,21 +2943,19 @@ numeric_sub(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
- res = numeric_sub_opt_error(num1, num2, NULL);
+ res = numeric_sub_safe(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
/*
- * numeric_sub_opt_error() -
+ * numeric_sub_safe() -
*
- * Internal version of numeric_sub(). If "*have_error" flag is provided,
- * on error it's set to true, NULL returned. This is helpful when caller
- * need to handle errors by itself.
+ * Internal version of numeric_sub() with support for soft error reporting.
*/
Numeric
-numeric_sub_opt_error(Numeric num1, Numeric num2, bool *have_error)
+numeric_sub_safe(Numeric num1, Numeric num2, Node *escontext)
{
NumericVar arg1;
NumericVar arg2;
@@ -3009,7 +2999,7 @@ numeric_sub_opt_error(Numeric num1, Numeric num2, bool *have_error)
init_var(&result);
sub_var(&arg1, &arg2, &result);
- res = make_result_opt_error(&result, have_error);
+ res = make_result_safe(&result, escontext);
free_var(&result);
@@ -3029,21 +3019,19 @@ numeric_mul(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
- res = numeric_mul_opt_error(num1, num2, NULL);
+ res = numeric_mul_safe(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
/*
- * numeric_mul_opt_error() -
+ * numeric_mul_safe() -
*
- * Internal version of numeric_mul(). If "*have_error" flag is provided,
- * on error it's set to true, NULL returned. This is helpful when caller
- * need to handle errors by itself.
+ * Internal version of numeric_mul() with support for soft error reporting.
*/
Numeric
-numeric_mul_opt_error(Numeric num1, Numeric num2, bool *have_error)
+numeric_mul_safe(Numeric num1, Numeric num2, Node *escontext)
{
NumericVar arg1;
NumericVar arg2;
@@ -3130,7 +3118,7 @@ numeric_mul_opt_error(Numeric num1, Numeric num2, bool *have_error)
if (result.dscale > NUMERIC_DSCALE_MAX)
round_var(&result, NUMERIC_DSCALE_MAX);
- res = make_result_opt_error(&result, have_error);
+ res = make_result_safe(&result, escontext);
free_var(&result);
@@ -3150,21 +3138,19 @@ numeric_div(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
- res = numeric_div_opt_error(num1, num2, NULL);
+ res = numeric_div_safe(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
/*
- * numeric_div_opt_error() -
+ * numeric_div_safe() -
*
- * Internal version of numeric_div(). If "*have_error" flag is provided,
- * on error it's set to true, NULL returned. This is helpful when caller
- * need to handle errors by itself.
+ * Internal version of numeric_div() with support for soft error reporting.
*/
Numeric
-numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
+numeric_div_safe(Numeric num1, Numeric num2, Node *escontext)
{
NumericVar arg1;
NumericVar arg2;
@@ -3172,9 +3158,6 @@ numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
Numeric res;
int rscale;
- if (have_error)
- *have_error = false;
-
/*
* Handle NaN and infinities
*/
@@ -3189,15 +3172,7 @@ numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
switch (numeric_sign_internal(num2))
{
case 0:
- if (have_error)
- {
- *have_error = true;
- return NULL;
- }
- ereport(ERROR,
- (errcode(ERRCODE_DIVISION_BY_ZERO),
- errmsg("division by zero")));
- break;
+ goto division_by_zero;
case 1:
return make_result(&const_pinf);
case -1:
@@ -3212,15 +3187,7 @@ numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
switch (numeric_sign_internal(num2))
{
case 0:
- if (have_error)
- {
- *have_error = true;
- return NULL;
- }
- ereport(ERROR,
- (errcode(ERRCODE_DIVISION_BY_ZERO),
- errmsg("division by zero")));
- break;
+ goto division_by_zero;
case 1:
return make_result(&const_ninf);
case -1:
@@ -3251,25 +3218,25 @@ numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
*/
rscale = select_div_scale(&arg1, &arg2);
- /*
- * If "have_error" is provided, check for division by zero here
- */
- if (have_error && (arg2.ndigits == 0 || arg2.digits[0] == 0))
- {
- *have_error = true;
- return NULL;
- }
+ /* Check for division by zero */
+ if (arg2.ndigits == 0 || arg2.digits[0] == 0)
+ goto division_by_zero;
/*
* Do the divide and return the result
*/
div_var(&arg1, &arg2, &result, rscale, true, true);
- res = make_result_opt_error(&result, have_error);
+ res = make_result_safe(&result, escontext);
free_var(&result);
return res;
+
+division_by_zero:
+ ereturn(escontext, NULL,
+ errcode(ERRCODE_DIVISION_BY_ZERO),
+ errmsg("division by zero"));
}
@@ -3374,30 +3341,25 @@ numeric_mod(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
- res = numeric_mod_opt_error(num1, num2, NULL);
+ res = numeric_mod_safe(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
/*
- * numeric_mod_opt_error() -
+ * numeric_mod_safe() -
*
- * Internal version of numeric_mod(). If "*have_error" flag is provided,
- * on error it's set to true, NULL returned. This is helpful when caller
- * need to handle errors by itself.
+ * Internal version of numeric_mod() with support for soft error reporting.
*/
Numeric
-numeric_mod_opt_error(Numeric num1, Numeric num2, bool *have_error)
+numeric_mod_safe(Numeric num1, Numeric num2, Node *escontext)
{
Numeric res;
NumericVar arg1;
NumericVar arg2;
NumericVar result;
- if (have_error)
- *have_error = false;
-
/*
* Handle NaN and infinities. We follow POSIX fmod() on this, except that
* POSIX treats x-is-infinite and y-is-zero identically, raising EDOM and
@@ -3410,16 +3372,8 @@ numeric_mod_opt_error(Numeric num1, Numeric num2, bool *have_error)
if (NUMERIC_IS_INF(num1))
{
if (numeric_sign_internal(num2) == 0)
- {
- if (have_error)
- {
- *have_error = true;
- return NULL;
- }
- ereport(ERROR,
- (errcode(ERRCODE_DIVISION_BY_ZERO),
- errmsg("division by zero")));
- }
+ goto division_by_zero;
+
/* Inf % any nonzero = NaN */
return make_result(&const_nan);
}
@@ -3432,22 +3386,22 @@ numeric_mod_opt_error(Numeric num1, Numeric num2, bool *have_error)
init_var(&result);
- /*
- * If "have_error" is provided, check for division by zero here
- */
- if (have_error && (arg2.ndigits == 0 || arg2.digits[0] == 0))
- {
- *have_error = true;
- return NULL;
- }
+ /* Check for division by zero */
+ if (arg2.ndigits == 0 || arg2.digits[0] == 0)
+ goto division_by_zero;
mod_var(&arg1, &arg2, &result);
- res = make_result_opt_error(&result, NULL);
+ res = make_result_safe(&result, escontext);
free_var(&result);
return res;
+
+division_by_zero:
+ ereturn(escontext, NULL,
+ errcode(ERRCODE_DIVISION_BY_ZERO),
+ errmsg("division by zero"));
}
@@ -4404,52 +4358,34 @@ int4_numeric(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(int64_to_numeric(val));
}
+/*
+ * Internal version of int4_numeric() with support for soft error reporting.
+ */
int32
-numeric_int4_opt_error(Numeric num, bool *have_error)
+numeric_int4_safe(Numeric num, Node *escontext)
{
NumericVar x;
int32 result;
- if (have_error)
- *have_error = false;
-
if (NUMERIC_IS_SPECIAL(num))
{
- if (have_error)
- {
- *have_error = true;
- return 0;
- }
+ if (NUMERIC_IS_NAN(num))
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot convert NaN to %s", "integer")));
else
- {
- if (NUMERIC_IS_NAN(num))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot convert NaN to %s", "integer")));
- else
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot convert infinity to %s", "integer")));
- }
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot convert infinity to %s", "integer")));
}
/* Convert to variable format, then convert to int4 */
init_var_from_num(num, &x);
if (!numericvar_to_int32(&x, &result))
- {
- if (have_error)
- {
- *have_error = true;
- return 0;
- }
- else
- {
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("integer out of range")));
- }
- }
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range")));
return result;
}
@@ -4459,7 +4395,7 @@ numeric_int4(PG_FUNCTION_ARGS)
{
Numeric num = PG_GETARG_NUMERIC(0);
- PG_RETURN_INT32(numeric_int4_opt_error(num, NULL));
+ PG_RETURN_INT32(numeric_int4_safe(num, NULL));
}
/*
@@ -4492,52 +4428,34 @@ int8_numeric(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(int64_to_numeric(val));
}
+/*
+ * Internal version of int8_numeric() with support for soft error reporting.
+ */
int64
-numeric_int8_opt_error(Numeric num, bool *have_error)
+numeric_int8_safe(Numeric num, Node *escontext)
{
NumericVar x;
int64 result;
- if (have_error)
- *have_error = false;
-
if (NUMERIC_IS_SPECIAL(num))
{
- if (have_error)
- {
- *have_error = true;
- return 0;
- }
+ if (NUMERIC_IS_NAN(num))
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot convert NaN to %s", "bigint")));
else
- {
- if (NUMERIC_IS_NAN(num))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot convert NaN to %s", "bigint")));
- else
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot convert infinity to %s", "bigint")));
- }
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot convert infinity to %s", "bigint")));
}
/* Convert to variable format, then convert to int8 */
init_var_from_num(num, &x);
if (!numericvar_to_int64(&x, &result))
- {
- if (have_error)
- {
- *have_error = true;
- return 0;
- }
- else
- {
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("bigint out of range")));
- }
- }
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range")));
return result;
}
@@ -4547,7 +4465,7 @@ numeric_int8(PG_FUNCTION_ARGS)
{
Numeric num = PG_GETARG_NUMERIC(0);
- PG_RETURN_INT64(numeric_int8_opt_error(num, NULL));
+ PG_RETURN_INT64(numeric_int8_safe(num, NULL));
}
@@ -7583,16 +7501,13 @@ duplicate_numeric(Numeric num)
}
/*
- * make_result_opt_error() -
+ * make_result_safe() -
*
* Create the packed db numeric format in palloc()'d memory from
* a variable. This will handle NaN and Infinity cases.
- *
- * If "have_error" isn't NULL, on overflow *have_error is set to true and
- * NULL is returned. This is helpful when caller needs to handle errors.
*/
static Numeric
-make_result_opt_error(const NumericVar *var, bool *have_error)
+make_result_safe(const NumericVar *var, Node *escontext)
{
Numeric result;
NumericDigit *digits = var->digits;
@@ -7601,9 +7516,6 @@ make_result_opt_error(const NumericVar *var, bool *have_error)
int n;
Size len;
- if (have_error)
- *have_error = false;
-
if ((sign & NUMERIC_SIGN_MASK) == NUMERIC_SPECIAL)
{
/*
@@ -7676,19 +7588,9 @@ make_result_opt_error(const NumericVar *var, bool *have_error)
/* Check for overflow of int16 fields */
if (NUMERIC_WEIGHT(result) != weight ||
NUMERIC_DSCALE(result) != var->dscale)
- {
- if (have_error)
- {
- *have_error = true;
- return NULL;
- }
- else
- {
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("value overflows numeric format")));
- }
- }
+ ereturn(escontext, NULL,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value overflows numeric format")));
dump_numeric("make_result()", result);
return result;
@@ -7698,12 +7600,12 @@ make_result_opt_error(const NumericVar *var, bool *have_error)
/*
* make_result() -
*
- * An interface to make_result_opt_error() without "have_error" argument.
+ * An interface to make_result_safe() without "escontext" argument.
*/
static Numeric
make_result(const NumericVar *var)
{
- return make_result_opt_error(var, NULL);
+ return make_result_safe(var, NULL);
}