diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 6d6ef1c376..a181aad830 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -2325,8 +2325,6 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) /* If not supplied by input plans, evaluate the contained expr */ return fix_join_expr_mutator((Node *) phv->phexpr, context); } - if (IsA(node, Param)) - return fix_param_node(context->root, (Param *) node); /* Try matching more complex expressions too, if tlists have any */ if (context->outer_itlist && context->outer_itlist->has_non_vars) { @@ -2344,6 +2342,9 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) if (newvar) return (Node *) newvar; } + /* Special cases (apply only AFTER failing to match to lower tlist) */ + if (IsA(node, Param)) + return fix_param_node(context->root, (Param *) node); fix_expr_common(context->root, node); return expression_tree_mutator(node, fix_join_expr_mutator, @@ -2431,6 +2432,16 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) /* If not supplied by input plan, evaluate the contained expr */ return fix_upper_expr_mutator((Node *) phv->phexpr, context); } + /* Try matching more complex expressions too, if tlist has any */ + if (context->subplan_itlist->has_non_vars) + { + newvar = search_indexed_tlist_for_non_var((Expr *) node, + context->subplan_itlist, + context->newvarno); + if (newvar) + return (Node *) newvar; + } + /* Special cases (apply only AFTER failing to match to lower tlist) */ if (IsA(node, Param)) return fix_param_node(context->root, (Param *) node); if (IsA(node, Aggref)) @@ -2455,15 +2466,6 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) } /* If no match, just fall through to process it normally */ } - /* Try matching more complex expressions too, if tlist has any */ - if (context->subplan_itlist->has_non_vars) - { - newvar = search_indexed_tlist_for_non_var((Expr *) node, - context->subplan_itlist, - context->newvarno); - if (newvar) - return (Node *) newvar; - } fix_expr_common(context->root, node); return expression_tree_mutator(node, fix_upper_expr_mutator, diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index d09326c182..2083345c8e 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -167,6 +167,37 @@ SELECT a, b, char_length(c) FROM update_test; 42 | 12 | 10000 (4 rows) +-- Check multi-assignment with a Result node to handle a one-time filter. +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE update_test t + SET (a, b) = (SELECT b, a FROM update_test s WHERE s.a = t.a) + WHERE CURRENT_USER = SESSION_USER; + QUERY PLAN +------------------------------------------------------------------ + Update on public.update_test t + -> Result + Output: $1, $2, t.c, (SubPlan 1 (returns $1,$2)), t.ctid + One-Time Filter: (CURRENT_USER = SESSION_USER) + -> Seq Scan on public.update_test t + Output: t.c, t.a, t.ctid + SubPlan 1 (returns $1,$2) + -> Seq Scan on public.update_test s + Output: s.b, s.a + Filter: (s.a = t.a) +(10 rows) + +UPDATE update_test t + SET (a, b) = (SELECT b, a FROM update_test s WHERE s.a = t.a) + WHERE CURRENT_USER = SESSION_USER; +SELECT a, b, char_length(c) FROM update_test; + a | b | char_length +-----+----+------------- + | | + 100 | 21 | + 12 | 41 | 10000 + 12 | 42 | 10000 +(4 rows) + -- Test ON CONFLICT DO UPDATE INSERT INTO upsert_test VALUES(1, 'Boo'); -- uncorrelated sub-select: diff --git a/src/test/regress/sql/update.sql b/src/test/regress/sql/update.sql index c9bb3b53d3..8754ccb7b0 100644 --- a/src/test/regress/sql/update.sql +++ b/src/test/regress/sql/update.sql @@ -89,6 +89,16 @@ UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a = 10; UPDATE update_test SET c = repeat('x', 10000) WHERE c = 'car'; SELECT a, b, char_length(c) FROM update_test; +-- Check multi-assignment with a Result node to handle a one-time filter. +EXPLAIN (VERBOSE, COSTS OFF) +UPDATE update_test t + SET (a, b) = (SELECT b, a FROM update_test s WHERE s.a = t.a) + WHERE CURRENT_USER = SESSION_USER; +UPDATE update_test t + SET (a, b) = (SELECT b, a FROM update_test s WHERE s.a = t.a) + WHERE CURRENT_USER = SESSION_USER; +SELECT a, b, char_length(c) FROM update_test; + -- Test ON CONFLICT DO UPDATE INSERT INTO upsert_test VALUES(1, 'Boo'); -- uncorrelated sub-select: