From 0a5cae19edb99c102f0bcc35f046177901f459db Mon Sep 17 00:00:00 2001 From: Colm Date: Wed, 27 Aug 2025 12:00:27 +0100 Subject: [PATCH] In UPDATE deparse, check for a subscript before processing the targets. (#8155) DESCRIPTION: Checking first for the presence of subscript ops avoids a shallow copy of the target list for target lists where there are no array or json subscripts. Commit 0c1b31c fixed a bug in UPDATE statements with array or json subscripting in the target list. This commit modifies that to first check that the target list has a subscript and avoid a shallow copy of the target list for UPDATE statements with no array/json subscripting. --- .../distributed/deparser/citus_ruleutils.c | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/backend/distributed/deparser/citus_ruleutils.c b/src/backend/distributed/deparser/citus_ruleutils.c index a25cdf5bb..ebdb78cc9 100644 --- a/src/backend/distributed/deparser/citus_ruleutils.c +++ b/src/backend/distributed/deparser/citus_ruleutils.c @@ -1837,6 +1837,62 @@ ensure_update_targetlist_in_param_order(List *targetList) } +/* + * isSubsRef checks if a given node is a SubscriptingRef or can be + * reached through an implicit coercion. + */ +static +bool +isSubsRef(Node *node) +{ + if (node == NULL) + { + return false; + } + + if (IsA(node, CoerceToDomain)) + { + CoerceToDomain *coerceToDomain = (CoerceToDomain *) node; + if (coerceToDomain->coercionformat != COERCE_IMPLICIT_CAST) + { + /* not an implicit coercion, cannot reach to a SubscriptingRef */ + return false; + } + + node = (Node *) coerceToDomain->arg; + } + + return (IsA(node, SubscriptingRef)); +} + + +/* + * checkTlistForSubsRef - checks if any target entry in the list contains a + * SubscriptingRef or can be reached through an implicit coercion. Used by + * ExpandMergedSubscriptingRefEntries() to identify if any target entries + * need to be expanded - if not the original target list is preserved. + */ +static +bool +checkTlistForSubsRef(List *targetEntryList) +{ + ListCell *tgtCell = NULL; + + foreach(tgtCell, targetEntryList) + { + TargetEntry *targetEntry = (TargetEntry *) lfirst(tgtCell); + Expr *expr = targetEntry->expr; + + if (isSubsRef((Node *) expr)) + { + return true; + } + } + + return false; +} + + /* * ExpandMergedSubscriptingRefEntries takes a list of target entries and expands * each one that references a SubscriptingRef node that indicates multiple (field) @@ -1848,6 +1904,12 @@ ExpandMergedSubscriptingRefEntries(List *targetEntryList) List *newTargetEntryList = NIL; ListCell *tgtCell = NULL; + if (!checkTlistForSubsRef(targetEntryList)) + { + /* No subscripting refs found, return original list */ + return targetEntryList; + } + foreach(tgtCell, targetEntryList) { TargetEntry *targetEntry = (TargetEntry *) lfirst(tgtCell);