v2-0001-Change-_opt_error-to-soft-error-reporting.patch
application/x-patch
Filename: v2-0001-Change-_opt_error-to-soft-error-reporting.patch
Type: application/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v2-0001
Subject: Change *_opt_error to soft error reporting.
| File | + | − |
|---|---|---|
| src/backend/access/transam/xlogrecovery.c | 3 | 3 |
| src/backend/utils/adt/formatting.c | 3 | 3 |
| src/backend/utils/adt/jsonpath_exec.c | 32 | 30 |
| src/backend/utils/adt/numeric.c | 78 | 170 |
| src/backend/utils/adt/pg_lsn.c | 14 | 19 |
| src/backend/utils/adt/timestamp.c | 23 | 23 |
| src/include/utils/numeric.h | 10 | 12 |
| src/include/utils/pg_lsn.h | 4 | 1 |
From fbb92d00bcec35466d61501d0fa8e800deae82e7 Mon Sep 17 00:00:00 2001
From: Amul Sul <sulamul@gmail.com>
Date: Tue, 2 Sep 2025 14:31:37 +0530
Subject: [PATCH v2] Change *_opt_error to soft error reporting.
The existing *_opt_error functions take a boolean argument to set an
error flag instead of throwing an error if that passed, which allows
the caller to handle it. However, the commit d9f7f5d32f20 added "soft"
error-reporting infrastructure that can be used here instead.
Similarly, change the pg_lsn_in_internal function to use soft error
reporting and rename it to pg_lsn_in_safe.
---
src/backend/access/transam/xlogrecovery.c | 6 +-
src/backend/utils/adt/formatting.c | 6 +-
src/backend/utils/adt/jsonpath_exec.c | 62 +++---
src/backend/utils/adt/numeric.c | 248 +++++++---------------
src/backend/utils/adt/pg_lsn.c | 33 ++-
src/backend/utils/adt/timestamp.c | 46 ++--
src/include/utils/numeric.h | 22 +-
src/include/utils/pg_lsn.h | 5 +-
8 files changed, 167 insertions(+), 261 deletions(-)
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index f23ec8969c2..346319338a0 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -4834,10 +4834,10 @@ check_recovery_target_lsn(char **newval, void **extra, GucSource source)
{
XLogRecPtr lsn;
XLogRecPtr *myextra;
- bool have_error = false;
+ ErrorSaveContext escontext = {T_ErrorSaveContext};
- lsn = pg_lsn_in_internal(*newval, &have_error);
- if (have_error)
+ lsn = pg_lsn_in_safe(*newval, (Node *) &escontext);
+ if (escontext.error_occurred)
return false;
myextra = (XLogRecPtr *) guc_malloc(LOG, sizeof(XLogRecPtr));
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 7ad453314c3..78e19ac39ac 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -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);
}
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 5a562535223..8156695e97e 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -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"))));
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index b6287f5d973..fd246575788 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() supports "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() supports "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() supports "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() supports "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,12 +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,
+ ereturn(escontext, NULL,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
break;
@@ -3212,12 +3190,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,
+ ereturn(escontext, NULL,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
break;
@@ -3252,20 +3225,19 @@ 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 "escontext" is provided, raise division by zero soft error here
*/
- if (have_error && (arg2.ndigits == 0 || arg2.digits[0] == 0))
- {
- *have_error = true;
- return NULL;
- }
+ if (escontext && (arg2.ndigits == 0 || arg2.digits[0] == 0))
+ ereturn(escontext, NULL,
+ errcode(ERRCODE_DIVISION_BY_ZERO),
+ errmsg("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);
@@ -3374,30 +3346,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() supports "soft" error reporting.
*/
Numeric
-numeric_mod_opt_error(Numeric num1, Numeric num2, bool *have_error)
+numeric_mod_safe(Numeric num1, Numeric num2, Node *econtext)
{
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,17 +3377,11 @@ 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,
+ ereturn(econtext, NULL,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
- }
/* Inf % any nonzero = NaN */
+
return make_result(&const_nan);
}
/* num2 must be [-]Inf; result is num1 regardless of sign of num2 */
@@ -3433,17 +3394,16 @@ 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 "econtext" is provided, raise division by zero soft error here
*/
- if (have_error && (arg2.ndigits == 0 || arg2.digits[0] == 0))
- {
- *have_error = true;
- return NULL;
- }
+ if (econtext && (arg2.ndigits == 0 || arg2.digits[0] == 0))
+ ereturn(econtext, NULL,
+ errcode(ERRCODE_DIVISION_BY_ZERO),
+ errmsg("division by zero"));
mod_var(&arg1, &arg2, &result);
- res = make_result_opt_error(&result, NULL);
+ res = make_result_safe(&result, NULL);
free_var(&result);
@@ -4404,52 +4364,34 @@ int4_numeric(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(int64_to_numeric(val));
}
+/*
+ * Internal version of int4_numeric() supports "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 +4401,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 +4434,34 @@ int8_numeric(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(int64_to_numeric(val));
}
+/*
+ * Internal version of int8_numeric() supports "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 +4471,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 +7507,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 +7522,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 +7594,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 +7606,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);
}
diff --git a/src/backend/utils/adt/pg_lsn.c b/src/backend/utils/adt/pg_lsn.c
index 12de2446f5b..16001ff3ace 100644
--- a/src/backend/utils/adt/pg_lsn.c
+++ b/src/backend/utils/adt/pg_lsn.c
@@ -25,8 +25,11 @@
* Formatting and conversion routines.
*---------------------------------------------------------*/
+/*
+ * Internal version of pg_lsn_in() supports "soft" error reporting.
+ */
XLogRecPtr
-pg_lsn_in_internal(const char *str, bool *have_error)
+pg_lsn_in_safe(const char *str, Node *escontext)
{
int len1,
len2;
@@ -34,22 +37,20 @@ pg_lsn_in_internal(const char *str, bool *have_error)
off;
XLogRecPtr result;
- Assert(have_error != NULL);
- *have_error = false;
-
/* Sanity check input format. */
len1 = strspn(str, "0123456789abcdefABCDEF");
if (len1 < 1 || len1 > MAXPG_LSNCOMPONENT || str[len1] != '/')
- {
- *have_error = true;
- return InvalidXLogRecPtr;
- }
+ ereturn(escontext, InvalidXLogRecPtr,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for type %s: \"%s\"",
+ "pg_lsn", str)));
+
len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF");
if (len2 < 1 || len2 > MAXPG_LSNCOMPONENT || str[len1 + 1 + len2] != '\0')
- {
- *have_error = true;
- return InvalidXLogRecPtr;
- }
+ ereturn(escontext, InvalidXLogRecPtr,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for type %s: \"%s\"",
+ "pg_lsn", str)));
/* Decode result. */
id = (uint32) strtoul(str, NULL, 16);
@@ -64,14 +65,8 @@ pg_lsn_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
XLogRecPtr result;
- bool have_error = false;
- result = pg_lsn_in_internal(str, &have_error);
- if (have_error)
- ereturn(fcinfo->context, (Datum) 0,
- (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input syntax for type %s: \"%s\"",
- "pg_lsn", str)));
+ result = pg_lsn_in_safe(str, fcinfo->context);
PG_RETURN_LSN(result);
}
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 3e5f9dc1458..156a4830ffd 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -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);
}
diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h
index 9e79fc376cb..215f1ea4f53 100644
--- a/src/include/utils/numeric.h
+++ b/src/include/utils/numeric.h
@@ -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);
diff --git a/src/include/utils/pg_lsn.h b/src/include/utils/pg_lsn.h
index ae198af7450..461a4fdcba9 100644
--- a/src/include/utils/pg_lsn.h
+++ b/src/include/utils/pg_lsn.h
@@ -18,6 +18,9 @@
#include "access/xlogdefs.h"
#include "fmgr.h"
+/* forward declaration to avoid node.h include */
+typedef struct Node Node;
+
static inline XLogRecPtr
DatumGetLSN(Datum X)
{
@@ -33,6 +36,6 @@ LSNGetDatum(XLogRecPtr X)
#define PG_GETARG_LSN(n) DatumGetLSN(PG_GETARG_DATUM(n))
#define PG_RETURN_LSN(x) return LSNGetDatum(x)
-extern XLogRecPtr pg_lsn_in_internal(const char *str, bool *have_error);
+extern XLogRecPtr pg_lsn_in_safe(const char *str, Node *escontext);
#endif /* PG_LSN_H */
--
2.47.1