v6-0005-error-safe-for-casting-numeric-to-other-types-per-pg_cast.patch
text/x-patch
Filename: v6-0005-error-safe-for-casting-numeric-to-other-types-per-pg_cast.patch
Type: text/x-patch
Part: 13
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 v6-0005
Subject: error safe for casting numeric to other types per pg_cast
| File | + | − |
|---|---|---|
| src/backend/utils/adt/numeric.c | 56 | 13 |
From 3738b36237e21a9341abea8a599e7ed7fa899307 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Sat, 9 Aug 2025 21:33:56 +0800
Subject: [PATCH v6 05/18] error safe for casting numeric to other types per
pg_cast
select castsource::regtype, casttarget::regtype, castfunc,
castcontext,castmethod, pp.prosrc, pp.proname from pg_cast pc join pg_proc pp on
pp.oid = pc.castfunc and pc.castfunc > 0
and castsource::regtype = 'numeric'::regtype
order by castsource::regtype;
castsource | casttarget | castfunc | castcontext | castmethod | prosrc | proname
------------+------------------+----------+-------------+------------+----------------+---------
numeric | bigint | 1779 | a | f | numeric_int8 | int8
numeric | smallint | 1783 | a | f | numeric_int2 | int2
numeric | integer | 1744 | a | f | numeric_int4 | int4
numeric | real | 1745 | i | f | numeric_float4 | float4
numeric | double precision | 1746 | i | f | numeric_float8 | float8
numeric | money | 3824 | a | f | numeric_cash | money
numeric | numeric | 1703 | i | f | numeric | numeric
(7 rows)
current safe cast for money data type is not supported, so no realted function
refactoring.
---
src/backend/utils/adt/numeric.c | 69 ++++++++++++++++++++++++++-------
1 file changed, 56 insertions(+), 13 deletions(-)
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 122f2efab8b..2ab26d59e41 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -1259,7 +1259,8 @@ numeric (PG_FUNCTION_ARGS)
*/
if (NUMERIC_IS_SPECIAL(num))
{
- (void) apply_typmod_special(num, typmod, NULL);
+ if (!apply_typmod_special(num, typmod, fcinfo->context))
+ PG_RETURN_NULL();
PG_RETURN_NUMERIC(duplicate_numeric(num));
}
@@ -1310,7 +1311,8 @@ numeric (PG_FUNCTION_ARGS)
init_var(&var);
set_var_from_num(num, &var);
- (void) apply_typmod(&var, typmod, NULL);
+ if (!apply_typmod(&var, typmod, fcinfo->context))
+ PG_RETURN_NULL();
new = make_result(&var);
free_var(&var);
@@ -4550,7 +4552,22 @@ numeric_int4(PG_FUNCTION_ARGS)
{
Numeric num = PG_GETARG_NUMERIC(0);
- PG_RETURN_INT32(numeric_int4_opt_error(num, NULL));
+ if (likely(!fcinfo->context))
+ PG_RETURN_INT32(numeric_int4_opt_error(num, NULL));
+ else
+ {
+ bool has_error;
+ int32 result;
+ Node *escontext = fcinfo->context;
+
+ result = numeric_int4_opt_error(num, &has_error);
+ if (has_error)
+ ereturn(escontext, (Datum) 0,
+ errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("integer out of range"));
+
+ PG_RETURN_INT32(result);
+ }
}
/*
@@ -4638,7 +4655,22 @@ numeric_int8(PG_FUNCTION_ARGS)
{
Numeric num = PG_GETARG_NUMERIC(0);
- PG_RETURN_INT64(numeric_int8_opt_error(num, NULL));
+ if (likely(!fcinfo->context))
+ PG_RETURN_INT64(numeric_int8_opt_error(num, NULL));
+ else
+ {
+ bool has_error;
+ int64 result;
+ Node *escontext = fcinfo->context;
+
+ result = numeric_int8_opt_error(num, &has_error);
+ if (has_error)
+ ereturn(escontext, (Datum) 0,
+ errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("bigint out of range"));
+
+ PG_RETURN_INT64(result);
+ }
}
@@ -4662,11 +4694,11 @@ numeric_int2(PG_FUNCTION_ARGS)
if (NUMERIC_IS_SPECIAL(num))
{
if (NUMERIC_IS_NAN(num))
- ereport(ERROR,
+ ereturn(fcinfo->context, (Datum) 0,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert NaN to %s", "smallint")));
else
- ereport(ERROR,
+ ereturn(fcinfo->context, (Datum) 0,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert infinity to %s", "smallint")));
}
@@ -4675,12 +4707,12 @@ numeric_int2(PG_FUNCTION_ARGS)
init_var_from_num(num, &x);
if (!numericvar_to_int64(&x, &val))
- ereport(ERROR,
+ ereturn(fcinfo->context, (Datum) 0,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
if (unlikely(val < PG_INT16_MIN) || unlikely(val > PG_INT16_MAX))
- ereport(ERROR,
+ ereturn(fcinfo->context, (Datum) 0,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
@@ -4745,10 +4777,14 @@ numeric_float8(PG_FUNCTION_ARGS)
tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(num)));
-
- result = DirectFunctionCall1(float8in, CStringGetDatum(tmp));
-
- pfree(tmp);
+ if (!DirectInputFunctionCallSafe(float8in, tmp,
+ InvalidOid, -1,
+ (Node *) fcinfo->context,
+ &result))
+ {
+ pfree(tmp);
+ PG_RETURN_NULL();
+ }
PG_RETURN_DATUM(result);
}
@@ -4840,7 +4876,14 @@ numeric_float4(PG_FUNCTION_ARGS)
tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(num)));
- result = DirectFunctionCall1(float4in, CStringGetDatum(tmp));
+ if (!DirectInputFunctionCallSafe(float4in, tmp,
+ InvalidOid, -1,
+ (Node *) fcinfo->context,
+ &result))
+ {
+ pfree(tmp);
+ PG_RETURN_NULL();
+ }
pfree(tmp);
--
2.34.1