aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorDean Rasheed <dean.a.rasheed@gmail.com>2023-02-25 14:41:12 +0000
committerDean Rasheed <dean.a.rasheed@gmail.com>2023-02-25 14:41:12 +0000
commita7d71c41dbd691ac86cc47114dab9db4b31f27ad (patch)
tree4c7c2b47a7ab4ab87e3387c0e86f1905e3500ce2 /src/backend
parent05fc551796e82c451a6f2bc39d1eafb3be3d2657 (diff)
downloadpostgresql-a7d71c41dbd691ac86cc47114dab9db4b31f27ad.tar.gz
postgresql-a7d71c41dbd691ac86cc47114dab9db4b31f27ad.zip
Fix mishandling of OLD/NEW references in subqueries in rule actions.
If a rule action contains a subquery that refers to columns from OLD or NEW, then those are really lateral references, and the planner will complain if it sees such things in a subquery that isn't marked as lateral. However, at rule-definition time, the user isn't required to mark the subquery with LATERAL, and so it can fail when the rule is used. Fix this by marking such subqueries as lateral in the rewriter, at the point where they're used. Dean Rasheed and Tom Lane, per report from Alexander Lakhin. Back-patch to all supported branches. Discussion: https://postgr.es/m/5e09da43-aaba-7ea7-0a51-a2eb981b058b%40gmail.com
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/rewrite/rewriteHandler.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index b6452e9b36c..a614e3f5bd0 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -353,6 +353,7 @@ rewriteRuleAction(Query *parsetree,
Query *sub_action;
Query **sub_action_ptr;
acquireLocksOnSubLinks_context context;
+ ListCell *lc;
context.for_execute = true;
@@ -392,6 +393,23 @@ rewriteRuleAction(Query *parsetree,
PRS2_OLD_VARNO + rt_length, rt_index, 0);
/*
+ * Mark any subquery RTEs in the rule action as LATERAL if they contain
+ * Vars referring to the current query level (references to NEW/OLD).
+ * Those really are lateral references, but we've historically not
+ * required users to mark such subqueries with LATERAL explicitly. But
+ * the planner will complain if such Vars exist in a non-LATERAL subquery,
+ * so we have to fix things up here.
+ */
+ foreach(lc, sub_action->rtable)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
+
+ if (rte->rtekind == RTE_SUBQUERY && !rte->lateral &&
+ contain_vars_of_level((Node *) rte->subquery, 1))
+ rte->lateral = true;
+ }
+
+ /*
* Generate expanded rtable consisting of main parsetree's rtable plus
* rule action's rtable; this becomes the complete rtable for the rule
* action. Some of the entries may be unused after we finish rewriting,
@@ -439,8 +457,6 @@ rewriteRuleAction(Query *parsetree,
*/
if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
{
- ListCell *lc;
-
foreach(lc, parsetree->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
@@ -538,8 +554,6 @@ rewriteRuleAction(Query *parsetree,
*/
if (parsetree->cteList != NIL && sub_action->commandType != CMD_UTILITY)
{
- ListCell *lc;
-
/*
* Annoying implementation restriction: because CTEs are identified by
* name within a cteList, we can't merge a CTE from the original query