Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 224fa64

Browse files
Nikita GlukhovCommitfest Bot
Nikita Glukhov
authored and
Commitfest Bot
committed
Allow Generic Type Subscripting to Accept Dot Notation (.) as Input
This change extends generic type subscripting to recognize dot notation (.) in addition to bracket notation ([]). While this does not yet provide full support for dot notation, it enables subscripting containers to process it in the future. For now, container-specific transform functions only handle subscripting indices and stop processing when encountering dot notation. It is up to individual containers to decide how to transform dot notation in subsequent updates.
1 parent 256af2b commit 224fa64

File tree

6 files changed

+105
-32
lines changed

6 files changed

+105
-32
lines changed

src/backend/parser/parse_expr.c

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -442,8 +442,9 @@ transformIndirection(ParseState *pstate, A_Indirection *ind)
442442
ListCell *i;
443443

444444
/*
445-
* We have to split any field-selection operations apart from
446-
* subscripting. Adjacent A_Indices nodes have to be treated as a single
445+
* Combine field names and subscripts into a single indirection list, as
446+
* some subscripting containers, such as jsonb, support field access using
447+
* dot notation. Adjacent A_Indices nodes have to be treated as a single
447448
* multidimensional subscript operation.
448449
*/
449450
foreach(i, ind->indirection)
@@ -461,39 +462,60 @@ transformIndirection(ParseState *pstate, A_Indirection *ind)
461462
}
462463
else
463464
{
464-
Node *newresult;
465-
466465
Assert(IsA(n, String));
466+
subscripts = lappend(subscripts, n);
467+
}
468+
}
469+
470+
while (subscripts)
471+
{
472+
/* try processing container subscripts first */
473+
Node *newresult = (Node *)
474+
transformContainerSubscripts(pstate,
475+
result,
476+
exprType(result),
477+
exprTypmod(result),
478+
&subscripts,
479+
false,
480+
true);
481+
482+
if (!newresult)
483+
{
484+
/*
485+
* generic subscripting failed; falling back to function call or
486+
* field selection for a composite type.
487+
*/
488+
Node *n;
489+
490+
Assert(subscripts);
467491

468-
/* process subscripts before this field selection */
469-
while (subscripts)
470-
result = (Node *) transformContainerSubscripts(pstate,
471-
result,
472-
exprType(result),
473-
exprTypmod(result),
474-
&subscripts,
475-
false);
492+
n = linitial(subscripts);
493+
494+
if (!IsA(n, String))
495+
ereport(ERROR,
496+
(errcode(ERRCODE_DATATYPE_MISMATCH),
497+
errmsg("cannot subscript type %s because it does not support subscripting",
498+
format_type_be(exprType(result))),
499+
parser_errposition(pstate, exprLocation(result))));
476500

501+
/* try to find function for field selection */
477502
newresult = ParseFuncOrColumn(pstate,
478503
list_make1(n),
479504
list_make1(result),
480505
last_srf,
481506
NULL,
482507
false,
483508
location);
484-
if (newresult == NULL)
509+
510+
if (!newresult)
485511
unknown_attribute(pstate, result, strVal(n), location);
486-
result = newresult;
512+
513+
/* consume field select */
514+
subscripts = list_delete_first(subscripts);
487515
}
516+
517+
result = newresult;
488518
}
489-
/* process trailing subscripts, if any */
490-
while (subscripts)
491-
result = (Node *) transformContainerSubscripts(pstate,
492-
result,
493-
exprType(result),
494-
exprTypmod(result),
495-
&subscripts,
496-
false);
497519

498520
return result;
499521
}

src/backend/parser/parse_node.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,20 +238,24 @@ transformContainerType(Oid *containerType, int32 *containerTypmod)
238238
* containerTypMod typmod for the container
239239
* indirection Untransformed list of subscripts (must not be NIL)
240240
* isAssignment True if this will become a container assignment.
241+
* noError True for return NULL with no error, if the container type
242+
* is not subscriptable.
241243
*/
242244
SubscriptingRef *
243245
transformContainerSubscripts(ParseState *pstate,
244246
Node *containerBase,
245247
Oid containerType,
246248
int32 containerTypMod,
247249
List **indirection,
248-
bool isAssignment)
250+
bool isAssignment,
251+
bool noError)
249252
{
250253
SubscriptingRef *sbsref;
251254
const SubscriptRoutines *sbsroutines;
252255
Oid elementType;
253256
bool isSlice = false;
254257
ListCell *idx;
258+
int indirection_length = list_length(*indirection);
255259

256260
/*
257261
* Determine the actual container type, smashing any domain. In the
@@ -267,11 +271,16 @@ transformContainerSubscripts(ParseState *pstate,
267271
*/
268272
sbsroutines = getSubscriptingRoutines(containerType, &elementType);
269273
if (!sbsroutines)
274+
{
275+
if (noError)
276+
return NULL;
277+
270278
ereport(ERROR,
271279
(errcode(ERRCODE_DATATYPE_MISMATCH),
272280
errmsg("cannot subscript type %s because it does not support subscripting",
273281
format_type_be(containerType)),
274282
parser_errposition(pstate, exprLocation(containerBase))));
283+
}
275284

276285
/*
277286
* Detect whether any of the indirection items are slice specifiers.
@@ -282,9 +291,9 @@ transformContainerSubscripts(ParseState *pstate,
282291
*/
283292
foreach(idx, *indirection)
284293
{
285-
A_Indices *ai = lfirst_node(A_Indices, idx);
294+
Node *ai = lfirst(idx);
286295

287-
if (ai->is_slice)
296+
if (IsA(ai, A_Indices) && castNode(A_Indices, ai)->is_slice)
288297
{
289298
isSlice = true;
290299
break;
@@ -312,6 +321,32 @@ transformContainerSubscripts(ParseState *pstate,
312321
sbsroutines->transform(sbsref, indirection, pstate,
313322
isSlice, isAssignment);
314323

324+
/*
325+
* Error out, if datatype failed to consume any indirection elements.
326+
*/
327+
if (list_length(*indirection) == indirection_length)
328+
{
329+
Node *ind = linitial(*indirection);
330+
331+
if (noError)
332+
return NULL;
333+
334+
if (IsA(ind, String))
335+
ereport(ERROR,
336+
(errcode(ERRCODE_DATATYPE_MISMATCH),
337+
errmsg("type %s does not support dot notation",
338+
format_type_be(containerType)),
339+
parser_errposition(pstate, exprLocation(containerBase))));
340+
else if (IsA(ind, A_Indices))
341+
ereport(ERROR,
342+
(errcode(ERRCODE_DATATYPE_MISMATCH),
343+
errmsg("type %s does not support array subscripting",
344+
format_type_be(containerType)),
345+
parser_errposition(pstate, exprLocation(containerBase))));
346+
else
347+
elog(ERROR, "invalid indirection operation: %d", nodeTag(ind));
348+
}
349+
315350
/*
316351
* Verify we got a valid type (this defends, for example, against someone
317352
* using array_subscript_handler as typsubscript without setting typelem).

src/backend/parser/parse_target.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,8 @@ transformAssignmentSubscripts(ParseState *pstate,
937937
containerType,
938938
containerTypMod,
939939
&subscripts,
940-
true);
940+
true,
941+
false);
941942

942943
typeNeeded = sbsref->refrestype;
943944
typmodNeeded = sbsref->reftypmod;

src/backend/utils/adt/arraysubs.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ array_subscript_transform(SubscriptingRef *sbsref,
6262
List *upperIndexpr = NIL;
6363
List *lowerIndexpr = NIL;
6464
ListCell *idx;
65+
int ndim;
6566

6667
/*
6768
* Transform the subscript expressions, and separate upper and lower
@@ -73,9 +74,14 @@ array_subscript_transform(SubscriptingRef *sbsref,
7374
*/
7475
foreach(idx, *indirection)
7576
{
76-
A_Indices *ai = lfirst_node(A_Indices, idx);
77+
A_Indices *ai;
7778
Node *subexpr;
7879

80+
if (!IsA(lfirst(idx), A_Indices))
81+
break;
82+
83+
ai = lfirst_node(A_Indices, idx);
84+
7985
if (isSlice)
8086
{
8187
if (ai->lidx)
@@ -145,14 +151,15 @@ array_subscript_transform(SubscriptingRef *sbsref,
145151
sbsref->reflowerindexpr = lowerIndexpr;
146152

147153
/* Verify subscript list lengths are within implementation limit */
148-
if (list_length(upperIndexpr) > MAXDIM)
154+
ndim = list_length(upperIndexpr);
155+
if (ndim > MAXDIM)
149156
ereport(ERROR,
150157
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
151158
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
152159
list_length(upperIndexpr), MAXDIM)));
153160
/* We need not check lowerIndexpr separately */
154161

155-
*indirection = NIL;
162+
*indirection = list_delete_first_n(*indirection, ndim);
156163

157164
/*
158165
* Determine the result type of the subscripting operation. It's the same

src/backend/utils/adt/jsonbsubs.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,14 @@ jsonb_subscript_transform(SubscriptingRef *sbsref,
5555
*/
5656
foreach(idx, *indirection)
5757
{
58-
A_Indices *ai = lfirst_node(A_Indices, idx);
58+
A_Indices *ai;
5959
Node *subExpr;
6060

61+
if (!IsA(lfirst(idx), A_Indices))
62+
break;
63+
64+
ai = lfirst_node(A_Indices, idx);
65+
6166
if (isSlice)
6267
{
6368
Node *expr = ai->uidx ? ai->uidx : ai->lidx;
@@ -160,7 +165,9 @@ jsonb_subscript_transform(SubscriptingRef *sbsref,
160165
sbsref->refrestype = JSONBOID;
161166
sbsref->reftypmod = -1;
162167

163-
*indirection = NIL;
168+
/* Remove processed elements */
169+
if (upperIndexpr)
170+
*indirection = list_delete_first_n(*indirection, list_length(upperIndexpr));
164171
}
165172

166173
/*

src/include/parser/parse_node.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,8 @@ extern SubscriptingRef *transformContainerSubscripts(ParseState *pstate,
378378
Oid containerType,
379379
int32 containerTypMod,
380380
List **indirection,
381-
bool isAssignment);
381+
bool isAssignment,
382+
bool noError);
382383
extern Const *make_const(ParseState *pstate, A_Const *aconst);
383384

384385
#endif /* PARSE_NODE_H */

0 commit comments

Comments
 (0)