From 140b45ed86bc7a4e9498194a777250ec4643fd06 Mon Sep 17 00:00:00 2001 From: Nikita Glukhov Date: Tue, 8 Jul 2025 22:18:07 -0700 Subject: [PATCH v18 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 Reviewed-by: Chao Li --- 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 e1979a80c19..6e8fd42c612 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -465,14 +465,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), @@ -487,12 +486,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 905c975d83b..a097736229a 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -935,7 +935,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 e8626d3b4fc..5ead693a3b2 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 at 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..df988a85fad 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. + * It may parse a sublist (typically the prefix) of these indirections and + * modify the original list in place, allowing the caller to handle any + * remaining indirections differently or to raise an error as needed. + * * 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)