From 74824f1cc949041c0b5e0a35a668ab73ce08a23d Mon Sep 17 00:00:00 2001 From: Nikita Glukhov Date: Tue, 8 Jul 2025 22:18:07 -0700 Subject: [PATCH v14 1/7] Allow transformation of only a sublist of subscripts This is a preparation step for allowing subscripting containers to transform only a prefix of an indirection list and modify the list in-place by removing the processed elements. Currently, all elements are consumed, and the list is set to NIL after transformation. In the following commit, subscripting containers will gain the flexibility to stop transformation when encountering an unsupported indirection and return the remaining indirections to the caller. Reviewed-by: Alexandra Wang Reviewed-by: Andrew Dunstan Reviewed-by: Matheus Alcantara Reviewed-by: Jian He --- contrib/hstore/hstore_subs.c | 10 ++++++---- src/backend/parser/parse_expr.c | 9 ++++----- src/backend/parser/parse_node.c | 4 ++-- src/backend/parser/parse_target.c | 2 +- src/backend/utils/adt/arraysubs.c | 6 ++++-- src/backend/utils/adt/jsonbsubs.c | 6 ++++-- src/include/nodes/subscripting.h | 7 ++++++- src/include/parser/parse_node.h | 2 +- 8 files changed, 28 insertions(+), 18 deletions(-) diff --git a/contrib/hstore/hstore_subs.c b/contrib/hstore/hstore_subs.c index 3d03f66fa0d..1b29543ab67 100644 --- a/contrib/hstore/hstore_subs.c +++ b/contrib/hstore/hstore_subs.c @@ -40,7 +40,7 @@ */ static void hstore_subscript_transform(SubscriptingRef *sbsref, - List *indirection, + List **indirection, ParseState *pstate, bool isSlice, bool isAssignment) @@ -49,15 +49,15 @@ hstore_subscript_transform(SubscriptingRef *sbsref, Node *subexpr; /* We support only single-subscript, non-slice cases */ - if (isSlice || list_length(indirection) != 1) + if (isSlice || list_length(*indirection) != 1) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("hstore allows only one subscript"), parser_errposition(pstate, - exprLocation((Node *) indirection)))); + exprLocation((Node *) *indirection)))); /* Transform the subscript expression to type text */ - ai = linitial_node(A_Indices, indirection); + ai = linitial_node(A_Indices, *indirection); Assert(ai->uidx != NULL && ai->lidx == NULL && !ai->is_slice); subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind); @@ -81,6 +81,8 @@ hstore_subscript_transform(SubscriptingRef *sbsref, /* Determine the result type of the subscripting operation; always text */ sbsref->refrestype = TEXTOID; sbsref->reftypmod = -1; + + *indirection = NIL; } /* diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index d66276801c6..e1565e11d09 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -466,14 +466,13 @@ transformIndirection(ParseState *pstate, A_Indirection *ind) Assert(IsA(n, String)); /* process subscripts before this field selection */ - if (subscripts) + while (subscripts) result = (Node *) transformContainerSubscripts(pstate, result, exprType(result), exprTypmod(result), - subscripts, + &subscripts, false); - subscripts = NIL; newresult = ParseFuncOrColumn(pstate, list_make1(n), @@ -488,12 +487,12 @@ transformIndirection(ParseState *pstate, A_Indirection *ind) } } /* process trailing subscripts, if any */ - if (subscripts) + while (subscripts) result = (Node *) transformContainerSubscripts(pstate, result, exprType(result), exprTypmod(result), - subscripts, + &subscripts, false); return result; diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 203b7a32178..f05baa50a15 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -244,7 +244,7 @@ transformContainerSubscripts(ParseState *pstate, Node *containerBase, Oid containerType, int32 containerTypMod, - List *indirection, + List **indirection, bool isAssignment) { SubscriptingRef *sbsref; @@ -280,7 +280,7 @@ transformContainerSubscripts(ParseState *pstate, * element. If any of the items are slice specifiers (lower:upper), then * the subscript expression means a container slice operation. */ - foreach(idx, indirection) + foreach(idx, *indirection) { A_Indices *ai = lfirst_node(A_Indices, idx); diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 4aba0d9d4d5..4675a523045 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -936,7 +936,7 @@ transformAssignmentSubscripts(ParseState *pstate, basenode, containerType, containerTypMod, - subscripts, + &subscripts, true); typeNeeded = sbsref->refrestype; diff --git a/src/backend/utils/adt/arraysubs.c b/src/backend/utils/adt/arraysubs.c index 2940fb8e8d7..234c2c278c1 100644 --- a/src/backend/utils/adt/arraysubs.c +++ b/src/backend/utils/adt/arraysubs.c @@ -54,7 +54,7 @@ typedef struct ArraySubWorkspace */ static void array_subscript_transform(SubscriptingRef *sbsref, - List *indirection, + List **indirection, ParseState *pstate, bool isSlice, bool isAssignment) @@ -71,7 +71,7 @@ array_subscript_transform(SubscriptingRef *sbsref, * indirection items to slices by treating the single subscript as the * upper bound and supplying an assumed lower bound of 1. */ - foreach(idx, indirection) + foreach(idx, *indirection) { A_Indices *ai = lfirst_node(A_Indices, idx); Node *subexpr; @@ -152,6 +152,8 @@ array_subscript_transform(SubscriptingRef *sbsref, list_length(upperIndexpr), MAXDIM))); /* We need not check lowerIndexpr separately */ + *indirection = NIL; + /* * Determine the result type of the subscripting operation. It's the same * as the array type if we're slicing, else it's the element type. In diff --git a/src/backend/utils/adt/jsonbsubs.c b/src/backend/utils/adt/jsonbsubs.c index de64d498512..8ad6aa1ad4f 100644 --- a/src/backend/utils/adt/jsonbsubs.c +++ b/src/backend/utils/adt/jsonbsubs.c @@ -41,7 +41,7 @@ typedef struct JsonbSubWorkspace */ static void jsonb_subscript_transform(SubscriptingRef *sbsref, - List *indirection, + List **indirection, ParseState *pstate, bool isSlice, bool isAssignment) @@ -53,7 +53,7 @@ jsonb_subscript_transform(SubscriptingRef *sbsref, * Transform and convert the subscript expressions. Jsonb subscripting * does not support slices, look only and the upper index. */ - foreach(idx, indirection) + foreach(idx, *indirection) { A_Indices *ai = lfirst_node(A_Indices, idx); Node *subExpr; @@ -159,6 +159,8 @@ jsonb_subscript_transform(SubscriptingRef *sbsref, /* Determine the result type of the subscripting operation; always jsonb */ sbsref->refrestype = JSONBOID; sbsref->reftypmod = -1; + + *indirection = NIL; } /* diff --git a/src/include/nodes/subscripting.h b/src/include/nodes/subscripting.h index 234e8ad8012..5d576af346f 100644 --- a/src/include/nodes/subscripting.h +++ b/src/include/nodes/subscripting.h @@ -71,6 +71,11 @@ struct SubscriptExecSteps; * does not care to support slicing, it can just throw an error if isSlice.) * See array_subscript_transform() for sample code. * + * The transform method receives a pointer to a list of raw indirections. + * This allows the method to parse a sublist of the indirections (typically + * the prefix) and modify the original list in place, enabling the caller to + * either process the remaining indirections differently or raise an error. + * * The transform method is also responsible for identifying the result type * of the subscripting operation. At call, refcontainertype and reftypmod * describe the container type (this will be a base type not a domain), and @@ -93,7 +98,7 @@ struct SubscriptExecSteps; * assignment must return. */ typedef void (*SubscriptTransform) (SubscriptingRef *sbsref, - List *indirection, + List **indirection, struct ParseState *pstate, bool isSlice, bool isAssignment); diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index f7d07c84542..58a4b9df157 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -361,7 +361,7 @@ extern SubscriptingRef *transformContainerSubscripts(ParseState *pstate, Node *containerBase, Oid containerType, int32 containerTypMod, - List *indirection, + List **indirection, bool isAssignment); extern Const *make_const(ParseState *pstate, A_Const *aconst); -- 2.39.5 (Apple Git-154)