Skip to content

Commit c0bcf7e

Browse files
committed
Extract coerce_jsonpath_subscript()
1 parent 246256a commit c0bcf7e

File tree

1 file changed

+78
-64
lines changed

1 file changed

+78
-64
lines changed

src/backend/utils/adt/jsonbsubs.c

Lines changed: 78 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,83 @@ typedef struct JsonbSubWorkspace
3232
Datum *index; /* Subscript values in Datum format */
3333
} JsonbSubWorkspace;
3434

35+
static Oid
36+
jsonb_subscript_type(Node *expr)
37+
{
38+
if (expr && IsA(expr, String))
39+
return TEXTOID;
40+
41+
return exprType(expr);
42+
}
43+
44+
static Node *
45+
coerce_jsonpath_subscript(ParseState *pstate, Node *subExpr, Oid numtype)
46+
{
47+
Oid subExprType = jsonb_subscript_type(subExpr);
48+
Oid targetType = UNKNOWNOID;
49+
50+
if (subExprType != UNKNOWNOID)
51+
{
52+
Oid targets[2] = {numtype, TEXTOID};
53+
54+
/*
55+
* Jsonb can handle multiple subscript types, but cases when a
56+
* subscript could be coerced to multiple target types must be
57+
* avoided, similar to overloaded functions. It could be possibly
58+
* extend with jsonpath in the future.
59+
*/
60+
for (int i = 0; i < 2; i++)
61+
{
62+
if (can_coerce_type(1, &subExprType, &targets[i], COERCION_IMPLICIT))
63+
{
64+
/*
65+
* One type has already succeeded, it means there are two
66+
* coercion targets possible, failure.
67+
*/
68+
if (targetType != UNKNOWNOID)
69+
ereport(ERROR,
70+
(errcode(ERRCODE_DATATYPE_MISMATCH),
71+
errmsg("subscript type %s is not supported", format_type_be(subExprType)),
72+
errhint("jsonb subscript must be coercible to only one type, integer or text."),
73+
parser_errposition(pstate, exprLocation(subExpr))));
74+
75+
targetType = targets[i];
76+
}
77+
}
78+
79+
/*
80+
* No suitable types were found, failure.
81+
*/
82+
if (targetType == UNKNOWNOID)
83+
ereport(ERROR,
84+
(errcode(ERRCODE_DATATYPE_MISMATCH),
85+
errmsg("subscript type %s is not supported", format_type_be(subExprType)),
86+
errhint("jsonb subscript must be coercible to either integer or text."),
87+
parser_errposition(pstate, exprLocation(subExpr))));
88+
}
89+
else
90+
targetType = TEXTOID;
91+
92+
/*
93+
* We known from can_coerce_type that coercion will succeed, so
94+
* coerce_type could be used. Note the implicit coercion context, which is
95+
* required to handle subscripts of different types, similar to overloaded
96+
* functions.
97+
*/
98+
subExpr = coerce_type(pstate,
99+
subExpr, subExprType,
100+
targetType, -1,
101+
COERCION_IMPLICIT,
102+
COERCE_IMPLICIT_CAST,
103+
-1);
104+
if (subExpr == NULL)
105+
ereport(ERROR,
106+
(errcode(ERRCODE_DATATYPE_MISMATCH),
107+
errmsg("jsonb subscript must have text type"),
108+
parser_errposition(pstate, exprLocation(subExpr))));
109+
110+
return subExpr;
111+
}
35112

36113
/*
37114
* Finish parse analysis of a SubscriptingRef expression for a jsonb.
@@ -75,71 +152,8 @@ jsonb_subscript_transform(SubscriptingRef *sbsref,
75152

76153
if (ai->uidx)
77154
{
78-
Oid subExprType = InvalidOid,
79-
targetType = UNKNOWNOID;
80-
81155
subExpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
82-
subExprType = exprType(subExpr);
83-
84-
if (subExprType != UNKNOWNOID)
85-
{
86-
Oid targets[2] = {INT4OID, TEXTOID};
87-
88-
/*
89-
* Jsonb can handle multiple subscript types, but cases when a
90-
* subscript could be coerced to multiple target types must be
91-
* avoided, similar to overloaded functions. It could be
92-
* possibly extend with jsonpath in the future.
93-
*/
94-
for (int i = 0; i < 2; i++)
95-
{
96-
if (can_coerce_type(1, &subExprType, &targets[i], COERCION_IMPLICIT))
97-
{
98-
/*
99-
* One type has already succeeded, it means there are
100-
* two coercion targets possible, failure.
101-
*/
102-
if (targetType != UNKNOWNOID)
103-
ereport(ERROR,
104-
(errcode(ERRCODE_DATATYPE_MISMATCH),
105-
errmsg("subscript type %s is not supported", format_type_be(subExprType)),
106-
errhint("jsonb subscript must be coercible to only one type, integer or text."),
107-
parser_errposition(pstate, exprLocation(subExpr))));
108-
109-
targetType = targets[i];
110-
}
111-
}
112-
113-
/*
114-
* No suitable types were found, failure.
115-
*/
116-
if (targetType == UNKNOWNOID)
117-
ereport(ERROR,
118-
(errcode(ERRCODE_DATATYPE_MISMATCH),
119-
errmsg("subscript type %s is not supported", format_type_be(subExprType)),
120-
errhint("jsonb subscript must be coercible to either integer or text."),
121-
parser_errposition(pstate, exprLocation(subExpr))));
122-
}
123-
else
124-
targetType = TEXTOID;
125-
126-
/*
127-
* We known from can_coerce_type that coercion will succeed, so
128-
* coerce_type could be used. Note the implicit coercion context,
129-
* which is required to handle subscripts of different types,
130-
* similar to overloaded functions.
131-
*/
132-
subExpr = coerce_type(pstate,
133-
subExpr, subExprType,
134-
targetType, -1,
135-
COERCION_IMPLICIT,
136-
COERCE_IMPLICIT_CAST,
137-
-1);
138-
if (subExpr == NULL)
139-
ereport(ERROR,
140-
(errcode(ERRCODE_DATATYPE_MISMATCH),
141-
errmsg("jsonb subscript must have text type"),
142-
parser_errposition(pstate, exprLocation(subExpr))));
156+
subExpr = coerce_jsonpath_subscript(pstate, subExpr, INT4OID);
143157
}
144158
else
145159
{

0 commit comments

Comments
 (0)