#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
+#include "optimizer/var.h"
#include "parser/analyze.h"
#include "parser/parse_coerce.h"
#include "parser/parse_relation.h"
Query *sub_action;
Query **sub_action_ptr;
acquireLocksOnSubLinks_context context;
+ ListCell *lc;
context.for_execute = true;
ChangeVarNodes(rule_qual,
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
*/
if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
{
- ListCell *lc;
-
foreach(lc, parsetree->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
*/
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
RETURNING trgt.f1,
trgt.f2
+--
+-- Test implicit LATERAL references to old/new in rules
+--
+CREATE TABLE rule_t1(a int, b text DEFAULT 'xxx', c int);
+CREATE VIEW rule_v1 AS SELECT * FROM rule_t1;
+CREATE RULE v1_ins AS ON INSERT TO rule_v1
+ DO ALSO INSERT INTO rule_t1
+ SELECT * FROM (SELECT a + 10 FROM rule_t1 WHERE a = NEW.a) tt;
+CREATE RULE v1_upd AS ON UPDATE TO rule_v1
+ DO ALSO UPDATE rule_t1 t
+ SET c = tt.a * 10
+ FROM (SELECT a FROM rule_t1 WHERE a = OLD.a) tt WHERE t.a = tt.a;
+INSERT INTO rule_v1 VALUES (1, 'a'), (2, 'b');
+UPDATE rule_v1 SET b = upper(b);
+SELECT * FROM rule_t1;
+ a | b | c
+----+-----+-----
+ 1 | A | 10
+ 2 | B | 20
+ 11 | XXX | 110
+ 12 | XXX | 120
+(4 rows)
+
+DROP TABLE rule_t1 CASCADE;
+NOTICE: drop cascades to view rule_v1
--
-- check alter rename rule
--
-- check display of all rules added above
\d+ rules_src
+--
+-- Test implicit LATERAL references to old/new in rules
+--
+CREATE TABLE rule_t1(a int, b text DEFAULT 'xxx', c int);
+CREATE VIEW rule_v1 AS SELECT * FROM rule_t1;
+CREATE RULE v1_ins AS ON INSERT TO rule_v1
+ DO ALSO INSERT INTO rule_t1
+ SELECT * FROM (SELECT a + 10 FROM rule_t1 WHERE a = NEW.a) tt;
+CREATE RULE v1_upd AS ON UPDATE TO rule_v1
+ DO ALSO UPDATE rule_t1 t
+ SET c = tt.a * 10
+ FROM (SELECT a FROM rule_t1 WHERE a = OLD.a) tt WHERE t.a = tt.a;
+INSERT INTO rule_v1 VALUES (1, 'a'), (2, 'b');
+UPDATE rule_v1 SET b = upper(b);
+SELECT * FROM rule_t1;
+DROP TABLE rule_t1 CASCADE;
+
--
-- check alter rename rule
--