]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Make cast functions from jsonb error safe
authorPeter Eisentraut <peter@eisentraut.org>
Sat, 28 Mar 2026 14:44:13 +0000 (15:44 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Sat, 28 Mar 2026 14:44:13 +0000 (15:44 +0100)
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 <jian.universality@gmail.com>
Reviewed-by: Amul Sul <sulamul@gmail.com>
Reviewed-by: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/CADkLM%3Dfv1JfY4Ufa-jcwwNbjQixNViskQ8jZu3Tz_p656i_4hQ%40mail.gmail.com

src/backend/utils/adt/jsonb.c

index 1b1a8f301f24628cdb2608af90d1306604ba9903..864c5ac1c85a55cb9a3b4152638b8dfc0c1d44d5 100644 (file)
@@ -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));