Switch some numeric-related functions to use soft error reporting

This commit changes some functions related to the data type numeric to
use the soft error reporting rather than a custom boolean flag (called
"have_error") that callers of these functions could rely on to bypass
the generation of ERROR reports, letting the callers do their own error
handling (timestamp, jsonpath and numeric_to_char() require them).

This results in the removal of some boilerplate code that was required
to handle both the ereport() and the "have_error" code paths bypassing
ereport(), unifying everything under the soft error reporting facility.

While on it, some duplicated error messages are removed.  The function
upgraded in this commit were suffixed with "_opt_error" in their names.
They are renamed to "_safe" instead.

This change relies on d9f7f5d32f, that has introduced the soft error
reporting infrastructure.

Author: Amul Sul <sulamul@gmail.com>
Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Discussion: https://postgr.es/m/CAAJ_b96No5h5tRuR+KhcC44YcYUCw8WAHuLoqqyyop8_k3+JDQ@mail.gmail.com
master
Michael Paquier 6 days ago
parent ae45312008
commit 4246a977ba
  1. 6
      src/backend/utils/adt/formatting.c
  2. 62
      src/backend/utils/adt/jsonpath_exec.c
  3. 266
      src/backend/utils/adt/numeric.c
  4. 46
      src/backend/utils/adt/timestamp.c
  5. 22
      src/include/utils/numeric.h

@ -6389,12 +6389,12 @@ numeric_to_char(PG_FUNCTION_ARGS)
if (IS_ROMAN(&Num))
{
int32 intvalue;
bool err;
ErrorSaveContext escontext = {T_ErrorSaveContext};
/* Round and convert to int */
intvalue = numeric_int4_opt_error(value, &err);
intvalue = numeric_int4_safe(value, (Node *) &escontext);
/* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
if (err)
if (escontext.error_occurred)
intvalue = PG_INT32_MAX;
numstr = int_to_roman(intvalue);
}

@ -252,7 +252,8 @@ typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp,
JsonbValue *larg,
JsonbValue *rarg,
void *param);
typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2,
Node *escontext);
static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars,
JsonPathGetVarCallback getVar,
@ -808,23 +809,23 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
case jpiAdd:
return executeBinaryArithmExpr(cxt, jsp, jb,
numeric_add_opt_error, found);
numeric_add_safe, found);
case jpiSub:
return executeBinaryArithmExpr(cxt, jsp, jb,
numeric_sub_opt_error, found);
numeric_sub_safe, found);
case jpiMul:
return executeBinaryArithmExpr(cxt, jsp, jb,
numeric_mul_opt_error, found);
numeric_mul_safe, found);
case jpiDiv:
return executeBinaryArithmExpr(cxt, jsp, jb,
numeric_div_opt_error, found);
numeric_div_safe, found);
case jpiMod:
return executeBinaryArithmExpr(cxt, jsp, jb,
numeric_mod_opt_error, found);
numeric_mod_safe, found);
case jpiPlus:
return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
@ -1269,11 +1270,12 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
if (jb->type == jbvNumeric)
{
bool have_error;
ErrorSaveContext escontext = {T_ErrorSaveContext};
int64 val;
val = numeric_int8_opt_error(jb->val.numeric, &have_error);
if (have_error)
val = numeric_int8_safe(jb->val.numeric,
(Node *) &escontext);
if (escontext.error_occurred)
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
@ -1466,7 +1468,6 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
Datum dtypmod;
int32 precision;
int32 scale = 0;
bool have_error;
bool noerr;
ArrayType *arrtypmod;
Datum datums[2];
@ -1478,9 +1479,9 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
if (elem.type != jpiNumeric)
elog(ERROR, "invalid jsonpath item type for .decimal() precision");
precision = numeric_int4_opt_error(jspGetNumeric(&elem),
&have_error);
if (have_error)
precision = numeric_int4_safe(jspGetNumeric(&elem),
(Node *) &escontext);
if (escontext.error_occurred)
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
errmsg("precision of jsonpath item method .%s() is out of range for type integer",
@ -1492,9 +1493,9 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
if (elem.type != jpiNumeric)
elog(ERROR, "invalid jsonpath item type for .decimal() scale");
scale = numeric_int4_opt_error(jspGetNumeric(&elem),
&have_error);
if (have_error)
scale = numeric_int4_safe(jspGetNumeric(&elem),
(Node *) &escontext);
if (escontext.error_occurred)
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
errmsg("scale of jsonpath item method .%s() is out of range for type integer",
@ -1550,11 +1551,12 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
if (jb->type == jbvNumeric)
{
bool have_error;
int32 val;
ErrorSaveContext escontext = {T_ErrorSaveContext};
val = numeric_int4_opt_error(jb->val.numeric, &have_error);
if (have_error)
val = numeric_int4_safe(jb->val.numeric,
(Node *) &escontext);
if (escontext.error_occurred)
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
@ -2149,11 +2151,11 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
}
else
{
bool error = false;
ErrorSaveContext escontext = {T_ErrorSaveContext};
res = func(lval->val.numeric, rval->val.numeric, &error);
res = func(lval->val.numeric, rval->val.numeric, (Node *) &escontext);
if (error)
if (escontext.error_occurred)
return jperError;
}
@ -2433,7 +2435,7 @@ executeDateTimeMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
if (jsp->type != jpiDatetime && jsp->type != jpiDate &&
jsp->content.arg)
{
bool have_error;
ErrorSaveContext escontext = {T_ErrorSaveContext};
jspGetArg(jsp, &elem);
@ -2441,9 +2443,9 @@ executeDateTimeMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
elog(ERROR, "invalid jsonpath item type for %s argument",
jspOperationName(jsp->type));
time_precision = numeric_int4_opt_error(jspGetNumeric(&elem),
&have_error);
if (have_error)
time_precision = numeric_int4_safe(jspGetNumeric(&elem),
(Node *) &escontext);
if (escontext.error_occurred)
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
errmsg("time precision of jsonpath item method .%s() is out of range for type integer",
@ -3462,7 +3464,7 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
JsonValueList found = {0};
JsonPathExecResult res = executeItem(cxt, jsp, jb, &found);
Datum numeric_index;
bool have_error = false;
ErrorSaveContext escontext = {T_ErrorSaveContext};
if (jperIsError(res))
return res;
@ -3477,10 +3479,10 @@ getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
NumericGetDatum(jbv->val.numeric),
Int32GetDatum(0));
*index = numeric_int4_opt_error(DatumGetNumeric(numeric_index),
&have_error);
*index = numeric_int4_safe(DatumGetNumeric(numeric_index),
(Node *) &escontext);
if (have_error)
if (escontext.error_occurred)
RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
errmsg("jsonpath array subscript is out of integer range"))));

@ -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);
}

@ -5629,11 +5629,11 @@ timestamp_part_common(PG_FUNCTION_ARGS, bool retnumeric)
case DTK_JULIAN:
if (retnumeric)
PG_RETURN_NUMERIC(numeric_add_opt_error(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
numeric_div_opt_error(int64_to_numeric(((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) * INT64CONST(1000000) + fsec),
int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
NULL),
NULL));
PG_RETURN_NUMERIC(numeric_add_safe(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
numeric_div_safe(int64_to_numeric(((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) * INT64CONST(1000000) + fsec),
int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
NULL),
NULL));
else
PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
@ -5685,11 +5685,11 @@ timestamp_part_common(PG_FUNCTION_ARGS, bool retnumeric)
result = int64_div_fast_to_numeric(timestamp - epoch, 6);
else
{
result = numeric_div_opt_error(numeric_sub_opt_error(int64_to_numeric(timestamp),
int64_to_numeric(epoch),
NULL),
int64_to_numeric(1000000),
NULL);
result = numeric_div_safe(numeric_sub_safe(int64_to_numeric(timestamp),
int64_to_numeric(epoch),
NULL),
int64_to_numeric(1000000),
NULL);
result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
NumericGetDatum(result),
Int32GetDatum(6)));
@ -5903,11 +5903,11 @@ timestamptz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
case DTK_JULIAN:
if (retnumeric)
PG_RETURN_NUMERIC(numeric_add_opt_error(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
numeric_div_opt_error(int64_to_numeric(((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) * INT64CONST(1000000) + fsec),
int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
NULL),
NULL));
PG_RETURN_NUMERIC(numeric_add_safe(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
numeric_div_safe(int64_to_numeric(((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) * INT64CONST(1000000) + fsec),
int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
NULL),
NULL));
else
PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
@ -5956,11 +5956,11 @@ timestamptz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
result = int64_div_fast_to_numeric(timestamp - epoch, 6);
else
{
result = numeric_div_opt_error(numeric_sub_opt_error(int64_to_numeric(timestamp),
int64_to_numeric(epoch),
NULL),
int64_to_numeric(1000000),
NULL);
result = numeric_div_safe(numeric_sub_safe(int64_to_numeric(timestamp),
int64_to_numeric(epoch),
NULL),
int64_to_numeric(1000000),
NULL);
result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
NumericGetDatum(result),
Int32GetDatum(6)));
@ -6247,9 +6247,9 @@ interval_part_common(PG_FUNCTION_ARGS, bool retnumeric)
result = int64_div_fast_to_numeric(val, 6);
else
result =
numeric_add_opt_error(int64_div_fast_to_numeric(interval->time, 6),
int64_to_numeric(secs_from_day_month),
NULL);
numeric_add_safe(int64_div_fast_to_numeric(interval->time, 6),
int64_to_numeric(secs_from_day_month),
NULL);
PG_RETURN_NUMERIC(result);
}

@ -17,6 +17,9 @@
#include "common/pg_prng.h"
#include "fmgr.h"
/* forward declaration to avoid node.h include */
typedef struct Node Node;
/*
* Limits on the precision and scale specifiable in a NUMERIC typmod. The
* precision is strictly positive, but the scale may be positive or negative.
@ -91,18 +94,13 @@ extern char *numeric_normalize(Numeric num);
extern Numeric int64_to_numeric(int64 val);
extern Numeric int64_div_fast_to_numeric(int64 val1, int log10val2);
extern Numeric numeric_add_opt_error(Numeric num1, Numeric num2,
bool *have_error);
extern Numeric numeric_sub_opt_error(Numeric num1, Numeric num2,
bool *have_error);
extern Numeric numeric_mul_opt_error(Numeric num1, Numeric num2,
bool *have_error);
extern Numeric numeric_div_opt_error(Numeric num1, Numeric num2,
bool *have_error);
extern Numeric numeric_mod_opt_error(Numeric num1, Numeric num2,
bool *have_error);
extern int32 numeric_int4_opt_error(Numeric num, bool *have_error);
extern int64 numeric_int8_opt_error(Numeric num, bool *have_error);
extern Numeric numeric_add_safe(Numeric num1, Numeric num2, Node *escontext);
extern Numeric numeric_sub_safe(Numeric num1, Numeric num2, Node *escontext);
extern Numeric numeric_mul_safe(Numeric num1, Numeric num2, Node *escontext);
extern Numeric numeric_div_safe(Numeric num1, Numeric num2, Node *escontext);
extern Numeric numeric_mod_safe(Numeric num1, Numeric num2, Node *escontext);
extern int32 numeric_int4_safe(Numeric num, Node *escontext);
extern int64 numeric_int8_safe(Numeric num, Node *escontext);
extern Numeric random_numeric(pg_prng_state *state,
Numeric rmin, Numeric rmax);

Loading…
Cancel
Save