v9-0010-error-safe-for-casting-numeric-to-other-types-per-pg_cast.patch
text/x-patch
Filename: v9-0010-error-safe-for-casting-numeric-to-other-types-per-pg_cast.patch
Type: text/x-patch
Part: 9
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 v9-0010
Subject: error safe for casting numeric to other types per pg_cast
| File | + | − |
|---|---|---|
| src/backend/utils/adt/numeric.c | 53 | 15 |
From 8229b22d674b51e4e42c9de0abb59ba123857595 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Thu, 9 Oct 2025 21:57:31 +0800
Subject: [PATCH v9 10/19] 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)
discussion: https://postgr.es/m/CACJufxHCMzrHOW=wRe8L30rMhB3sjwAv1LE928Fa7sxMu1Tx-g@mail.gmail.com
---
src/backend/utils/adt/numeric.c | 68 +++++++++++++++++++++++++--------
1 file changed, 53 insertions(+), 15 deletions(-)
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 2501007d981..ce5f71109e7 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -1244,7 +1244,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));
}
@@ -1295,8 +1296,9 @@ numeric (PG_FUNCTION_ARGS)
init_var(&var);
set_var_from_num(num, &var);
- (void) apply_typmod(&var, typmod, NULL);
- new = make_result(&var);
+ if (!apply_typmod(&var, typmod, fcinfo->context))
+ PG_RETURN_NULL();
+ new = make_result_safe(&var, fcinfo->context);
free_var(&var);
@@ -3019,7 +3021,10 @@ numeric_mul(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
- res = numeric_mul_safe(num1, num2, NULL);
+ res = numeric_mul_safe(num1, num2, fcinfo->context);
+
+ if (unlikely(SOFT_ERROR_OCCURRED(fcinfo->context)))
+ PG_RETURN_NULL();
PG_RETURN_NUMERIC(res);
}
@@ -4393,9 +4398,15 @@ numeric_int4_safe(Numeric num, Node *escontext)
Datum
numeric_int4(PG_FUNCTION_ARGS)
{
+ int32 result;
Numeric num = PG_GETARG_NUMERIC(0);
- PG_RETURN_INT32(numeric_int4_safe(num, NULL));
+ result = numeric_int4_safe(num, fcinfo->context);
+
+ if (unlikely(SOFT_ERROR_OCCURRED(fcinfo->context)))
+ PG_RETURN_NULL();
+
+ PG_RETURN_INT32(result);
}
/*
@@ -4463,9 +4474,15 @@ numeric_int8_safe(Numeric num, Node *escontext)
Datum
numeric_int8(PG_FUNCTION_ARGS)
{
+ int64 result;
Numeric num = PG_GETARG_NUMERIC(0);
- PG_RETURN_INT64(numeric_int8_safe(num, NULL));
+ result = numeric_int8_safe(num, fcinfo->context);
+
+ if (unlikely(SOFT_ERROR_OCCURRED(fcinfo->context)))
+ PG_RETURN_NULL();
+
+ PG_RETURN_INT64(result);
}
@@ -4489,28 +4506,38 @@ numeric_int2(PG_FUNCTION_ARGS)
if (NUMERIC_IS_SPECIAL(num))
{
if (NUMERIC_IS_NAN(num))
- ereport(ERROR,
+ errsave(fcinfo->context,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert NaN to %s", "smallint")));
else
- ereport(ERROR,
+ errsave(fcinfo->context,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert infinity to %s", "smallint")));
+
+ PG_RETURN_NULL();
}
/* Convert to variable format and thence to int8 */
init_var_from_num(num, &x);
if (!numericvar_to_int64(&x, &val))
- ereport(ERROR,
+ {
+ errsave(fcinfo->context,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
+ PG_RETURN_NULL();
+ }
+
if (unlikely(val < PG_INT16_MIN) || unlikely(val > PG_INT16_MAX))
- ereport(ERROR,
+ {
+ errsave(fcinfo->context,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
+ PG_RETURN_NULL();
+ }
+
/* Down-convert to int2 */
result = (int16) val;
@@ -4572,10 +4599,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);
}
@@ -4667,7 +4698,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