mirror of
https://github.com/postgres/postgres.git
synced 2025-10-08 00:03:59 -04:00
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 d9f7f5d32f20, 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
This commit is contained in:
parent
ae45312008
commit
4246a977ba
@ -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…
x
Reference in New Issue
Block a user