From: Peter Eisentraut Date: Sat, 28 Mar 2026 14:44:13 +0000 (+0100) Subject: Make cast functions from jsonb error safe X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=10e4d8aaf46fb46b8b78e026560b68af84a6495b;p=thirdparty%2Fpostgresql.git Make cast functions from jsonb error safe This adjusts cast functions from jsonb to other types to support soft errors. This just involves some refactoring of the underlying helper functions to use ereturn. This is in preparation for a future feature where conversion errors in casts can be caught. Author: jian he Reviewed-by: Amul Sul Reviewed-by: Corey Huinker Discussion: https://www.postgresql.org/message-id/flat/CADkLM%3Dfv1JfY4Ufa-jcwwNbjQixNViskQ8jZu3Tz_p656i_4hQ%40mail.gmail.com --- diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index 1b1a8f301f2..864c5ac1c85 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -1785,8 +1785,8 @@ JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res) /* * Emit correct, translatable cast error message */ -static void -cannotCastJsonbValue(enum jbvType type, const char *sqltype) +static Datum +cannotCastJsonbValue(enum jbvType type, const char *sqltype, Node *escontext) { static const struct { @@ -1807,12 +1807,13 @@ cannotCastJsonbValue(enum jbvType type, const char *sqltype) for (i = 0; i < lengthof(messages); i++) if (messages[i].type == type) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg(messages[i].msg, sqltype))); /* should be unreachable */ elog(ERROR, "unknown jsonb type: %d", (int) type); + return (Datum) 0; } Datum @@ -1822,7 +1823,7 @@ jsonb_bool(PG_FUNCTION_ARGS) JsonbValue v; if (!JsonbExtractScalar(&in->root, &v)) - cannotCastJsonbValue(v.type, "boolean"); + return cannotCastJsonbValue(v.type, "boolean", fcinfo->context); if (v.type == jbvNull) { @@ -1831,7 +1832,7 @@ jsonb_bool(PG_FUNCTION_ARGS) } if (v.type != jbvBool) - cannotCastJsonbValue(v.type, "boolean"); + return cannotCastJsonbValue(v.type, "boolean", fcinfo->context); PG_FREE_IF_COPY(in, 0); @@ -1846,7 +1847,7 @@ jsonb_numeric(PG_FUNCTION_ARGS) Numeric retValue; if (!JsonbExtractScalar(&in->root, &v)) - cannotCastJsonbValue(v.type, "numeric"); + return cannotCastJsonbValue(v.type, "numeric", fcinfo->context); if (v.type == jbvNull) { @@ -1855,7 +1856,7 @@ jsonb_numeric(PG_FUNCTION_ARGS) } if (v.type != jbvNumeric) - cannotCastJsonbValue(v.type, "numeric"); + return cannotCastJsonbValue(v.type, "numeric", fcinfo->context); /* * v.val.numeric points into jsonb body, so we need to make a copy to @@ -1876,7 +1877,7 @@ jsonb_int2(PG_FUNCTION_ARGS) Datum retValue; if (!JsonbExtractScalar(&in->root, &v)) - cannotCastJsonbValue(v.type, "smallint"); + return cannotCastJsonbValue(v.type, "smallint", fcinfo->context); if (v.type == jbvNull) { @@ -1885,7 +1886,7 @@ jsonb_int2(PG_FUNCTION_ARGS) } if (v.type != jbvNumeric) - cannotCastJsonbValue(v.type, "smallint"); + return cannotCastJsonbValue(v.type, "smallint", fcinfo->context); retValue = DirectFunctionCall1(numeric_int2, NumericGetDatum(v.val.numeric)); @@ -1903,7 +1904,7 @@ jsonb_int4(PG_FUNCTION_ARGS) Datum retValue; if (!JsonbExtractScalar(&in->root, &v)) - cannotCastJsonbValue(v.type, "integer"); + return cannotCastJsonbValue(v.type, "integer", fcinfo->context); if (v.type == jbvNull) { @@ -1912,7 +1913,7 @@ jsonb_int4(PG_FUNCTION_ARGS) } if (v.type != jbvNumeric) - cannotCastJsonbValue(v.type, "integer"); + return cannotCastJsonbValue(v.type, "integer", fcinfo->context); retValue = DirectFunctionCall1(numeric_int4, NumericGetDatum(v.val.numeric)); @@ -1930,7 +1931,7 @@ jsonb_int8(PG_FUNCTION_ARGS) Datum retValue; if (!JsonbExtractScalar(&in->root, &v)) - cannotCastJsonbValue(v.type, "bigint"); + return cannotCastJsonbValue(v.type, "bigint", fcinfo->context); if (v.type == jbvNull) { @@ -1939,7 +1940,7 @@ jsonb_int8(PG_FUNCTION_ARGS) } if (v.type != jbvNumeric) - cannotCastJsonbValue(v.type, "bigint"); + return cannotCastJsonbValue(v.type, "bigint", fcinfo->context); retValue = DirectFunctionCall1(numeric_int8, NumericGetDatum(v.val.numeric)); @@ -1957,7 +1958,7 @@ jsonb_float4(PG_FUNCTION_ARGS) Datum retValue; if (!JsonbExtractScalar(&in->root, &v)) - cannotCastJsonbValue(v.type, "real"); + return cannotCastJsonbValue(v.type, "real", fcinfo->context); if (v.type == jbvNull) { @@ -1966,7 +1967,7 @@ jsonb_float4(PG_FUNCTION_ARGS) } if (v.type != jbvNumeric) - cannotCastJsonbValue(v.type, "real"); + return cannotCastJsonbValue(v.type, "real", fcinfo->context); retValue = DirectFunctionCall1(numeric_float4, NumericGetDatum(v.val.numeric)); @@ -1984,7 +1985,7 @@ jsonb_float8(PG_FUNCTION_ARGS) Datum retValue; if (!JsonbExtractScalar(&in->root, &v)) - cannotCastJsonbValue(v.type, "double precision"); + return cannotCastJsonbValue(v.type, "double precision", fcinfo->context); if (v.type == jbvNull) { @@ -1993,7 +1994,7 @@ jsonb_float8(PG_FUNCTION_ARGS) } if (v.type != jbvNumeric) - cannotCastJsonbValue(v.type, "double precision"); + return cannotCastJsonbValue(v.type, "double precision", fcinfo->context); retValue = DirectFunctionCall1(numeric_float8, NumericGetDatum(v.val.numeric));