aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/optimizer/plan/setrefs.c24
-rw-r--r--src/test/regress/expected/update.out31
-rw-r--r--src/test/regress/sql/update.sql10
3 files changed, 54 insertions, 11 deletions
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 6d6ef1c3769..a181aad8309 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 d09326c1824..2083345c8ee 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 c9bb3b53d35..8754ccb7b01 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: