From 864e870271d033ab61f08238f3a60f8a60aebb8e Mon Sep 17 00:00:00 2001 From: Alexandra Wang Date: Tue, 8 Jul 2025 22:18:07 -0700 Subject: [PATCH v18 4/7] Extract coerce_jsonpath_subscript() This is a preparation step for a future commit that will reuse the aforementioned function. Co-authored-by: Nikita Glukhov Co-authored-by: Alexandra Wang Reviewed-by: Andrew Dunstan Reviewed-by: Matheus Alcantara Reviewed-by: Jian He Reviewed-by: Chao Li --- src/backend/utils/adt/jsonbsubs.c | 128 +++++++++++++++--------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/backend/utils/adt/jsonbsubs.c b/src/backend/utils/adt/jsonbsubs.c index 2aa410f605b..8852c27a198 100644 --- a/src/backend/utils/adt/jsonbsubs.c +++ b/src/backend/utils/adt/jsonbsubs.c @@ -32,6 +32,69 @@ typedef struct JsonbSubWorkspace Datum *index; /* Subscript values in Datum format */ } JsonbSubWorkspace; +static Node * +coerce_jsonpath_subscript_to_int4_or_text(ParseState *pstate, Node *subExpr) +{ + Oid subExprType = exprType(subExpr); + Oid targetType = InvalidOid; + + if (subExprType != UNKNOWNOID) + { + const Oid targets[] = {INT4OID, TEXTOID}; + + /* + * Jsonb can handle multiple subscript types, but cases when a + * subscript could be coerced to multiple target types must be + * avoided, similar to overloaded functions. It could be possibly + * extend with jsonpath in the future. + */ + for (int i = 0; i < lengthof(targets); i++) + { + if (can_coerce_type(1, &subExprType, &targets[i], COERCION_IMPLICIT)) + { + /* + * One type has already succeeded, it means there are two + * coercion targets possible, failure. + */ + if (OidIsValid(targetType)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("subscript type %s is not supported", format_type_be(subExprType)), + errhint("jsonb subscript must be coercible to only one type, integer or text."), + parser_errposition(pstate, exprLocation(subExpr)))); + + targetType = targets[i]; + } + } + + /* + * No suitable types were found, failure. + */ + if (!OidIsValid(targetType)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("subscript type %s is not supported", format_type_be(subExprType)), + errhint("jsonb subscript must be coercible to either integer or text."), + parser_errposition(pstate, exprLocation(subExpr)))); + } + else + targetType = TEXTOID; + + /* + * We known from can_coerce_type that coercion will succeed, so + * coerce_type could be used. Note the implicit coercion context, which is + * required to handle subscripts of different types, similar to overloaded + * functions. + */ + subExpr = coerce_type(pstate, + subExpr, subExprType, + targetType, -1, + COERCION_IMPLICIT, + COERCE_IMPLICIT_CAST, + -1); + + return subExpr; +} /* * Finish parse analysis of a SubscriptingRef expression for a jsonb. @@ -74,71 +137,8 @@ jsonb_subscript_transform(SubscriptingRef *sbsref, if (ai->uidx) { - Oid subExprType = InvalidOid, - targetType = UNKNOWNOID; - subExpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind); - subExprType = exprType(subExpr); - - if (subExprType != UNKNOWNOID) - { - Oid targets[2] = {INT4OID, TEXTOID}; - - /* - * Jsonb can handle multiple subscript types, but cases when a - * subscript could be coerced to multiple target types must be - * avoided, similar to overloaded functions. It could be - * possibly extend with jsonpath in the future. - */ - for (int i = 0; i < 2; i++) - { - if (can_coerce_type(1, &subExprType, &targets[i], COERCION_IMPLICIT)) - { - /* - * One type has already succeeded, it means there are - * two coercion targets possible, failure. - */ - if (targetType != UNKNOWNOID) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("subscript type %s is not supported", format_type_be(subExprType)), - errhint("jsonb subscript must be coercible to only one type, integer or text."), - parser_errposition(pstate, exprLocation(subExpr)))); - - targetType = targets[i]; - } - } - - /* - * No suitable types were found, failure. - */ - if (targetType == UNKNOWNOID) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("subscript type %s is not supported", format_type_be(subExprType)), - errhint("jsonb subscript must be coercible to either integer or text."), - parser_errposition(pstate, exprLocation(subExpr)))); - } - else - targetType = TEXTOID; - - /* - * We known from can_coerce_type that coercion will succeed, so - * coerce_type could be used. Note the implicit coercion context, - * which is required to handle subscripts of different types, - * similar to overloaded functions. - */ - subExpr = coerce_type(pstate, - subExpr, subExprType, - targetType, -1, - COERCION_IMPLICIT, - COERCE_IMPLICIT_CAST, - -1); - if (subExpr == NULL) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("jsonb subscript must have text type"), - parser_errposition(pstate, exprLocation(subExpr)))); + subExpr = coerce_jsonpath_subscript_to_int4_or_text(pstate, subExpr); } else { -- 2.39.5 (Apple Git-154)