Commit 6f9bd50e authored by Stephen Frost's avatar Stephen Frost

Add locking clause for SB views for update/delete

In expand_security_qual(), we were handling locking correctly when a
PlanRowMark existed, but not when we were working with the target
relation (which doesn't have any PlanRowMarks, but the subquery created
for the security barrier quals still needs to lock the rows under it).

Noted by Etsuro Fujita when working with the Postgres FDW, which wasn't
properly issuing a SELECT ... FOR UPDATE to the remote side under a
DELETE.

Back-patch to 9.4 where updatable security barrier views were
introduced.

Per discussion with Etsuro and Dean Rasheed.
parent 77903ede
...@@ -37,7 +37,7 @@ typedef struct ...@@ -37,7 +37,7 @@ typedef struct
} security_barrier_replace_vars_context; } security_barrier_replace_vars_context;
static void expand_security_qual(PlannerInfo *root, List *tlist, int rt_index, static void expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
RangeTblEntry *rte, Node *qual); RangeTblEntry *rte, Node *qual, bool targetRelation);
static void security_barrier_replace_vars(Node *node, static void security_barrier_replace_vars(Node *node,
security_barrier_replace_vars_context *context); security_barrier_replace_vars_context *context);
...@@ -63,6 +63,7 @@ expand_security_quals(PlannerInfo *root, List *tlist) ...@@ -63,6 +63,7 @@ expand_security_quals(PlannerInfo *root, List *tlist)
Query *parse = root->parse; Query *parse = root->parse;
int rt_index; int rt_index;
ListCell *cell; ListCell *cell;
bool targetRelation = false;
/* /*
* Process each RTE in the rtable list. * Process each RTE in the rtable list.
...@@ -98,6 +99,15 @@ expand_security_quals(PlannerInfo *root, List *tlist) ...@@ -98,6 +99,15 @@ expand_security_quals(PlannerInfo *root, List *tlist)
{ {
RangeTblEntry *newrte = copyObject(rte); RangeTblEntry *newrte = copyObject(rte);
/*
* We need to let expand_security_qual know if this is the target
* relation, as it has additional work to do in that case.
*
* Capture that information here as we're about to replace
* parse->resultRelation.
*/
targetRelation = true;
parse->rtable = lappend(parse->rtable, newrte); parse->rtable = lappend(parse->rtable, newrte);
parse->resultRelation = list_length(parse->rtable); parse->resultRelation = list_length(parse->rtable);
...@@ -147,7 +157,8 @@ expand_security_quals(PlannerInfo *root, List *tlist) ...@@ -147,7 +157,8 @@ expand_security_quals(PlannerInfo *root, List *tlist)
rte->securityQuals = list_delete_first(rte->securityQuals); rte->securityQuals = list_delete_first(rte->securityQuals);
ChangeVarNodes(qual, rt_index, 1, 0); ChangeVarNodes(qual, rt_index, 1, 0);
expand_security_qual(root, tlist, rt_index, rte, qual); expand_security_qual(root, tlist, rt_index, rte, qual,
targetRelation);
} }
} }
} }
...@@ -160,7 +171,7 @@ expand_security_quals(PlannerInfo *root, List *tlist) ...@@ -160,7 +171,7 @@ expand_security_quals(PlannerInfo *root, List *tlist)
*/ */
static void static void
expand_security_qual(PlannerInfo *root, List *tlist, int rt_index, expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
RangeTblEntry *rte, Node *qual) RangeTblEntry *rte, Node *qual, bool targetRelation)
{ {
Query *parse = root->parse; Query *parse = root->parse;
Oid relid = rte->relid; Oid relid = rte->relid;
...@@ -219,10 +230,11 @@ expand_security_qual(PlannerInfo *root, List *tlist, int rt_index, ...@@ -219,10 +230,11 @@ expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
* Now deal with any PlanRowMark on this RTE by requesting a lock * Now deal with any PlanRowMark on this RTE by requesting a lock
* of the same strength on the RTE copied down to the subquery. * of the same strength on the RTE copied down to the subquery.
* *
* Note that we can't push the user-defined quals down since they * Note that we can only push down user-defined quals if they are
* may included untrusted functions and that means that we will * only using leakproof (and therefore trusted) functions and
* end up locking all rows which pass the securityQuals, even if * operators. As a result, we may end up locking more rows than
* those rows don't pass the user-defined quals. This is * strictly necessary (and, in the worst case, we could end up
* locking all rows which pass the securityQuals). This is
* currently documented behavior, but it'd be nice to come up with * currently documented behavior, but it'd be nice to come up with
* a better solution some day. * a better solution some day.
*/ */
...@@ -255,6 +267,15 @@ expand_security_qual(PlannerInfo *root, List *tlist, int rt_index, ...@@ -255,6 +267,15 @@ expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
root->rowMarks = list_delete(root->rowMarks, rc); root->rowMarks = list_delete(root->rowMarks, rc);
} }
/*
* When we are replacing the target relation with a subquery, we
* need to make sure to add a locking clause explicitly to the
* generated subquery since there won't be any row marks against
* the target relation itself.
*/
if (targetRelation)
applyLockingClause(subquery, 1, LCS_FORUPDATE,
LockWaitBlock, false);
/* /*
* Replace any variables in the outer query that refer to the * Replace any variables in the outer query that refer to the
* original relation RTE with references to columns that we will * original relation RTE with references to columns that we will
......
...@@ -1034,22 +1034,25 @@ EXPLAIN (COSTS OFF) EXECUTE p2(2); ...@@ -1034,22 +1034,25 @@ EXPLAIN (COSTS OFF) EXECUTE p2(2);
-- --
SET SESSION AUTHORIZATION rls_regress_user1; SET SESSION AUTHORIZATION rls_regress_user1;
EXPLAIN (COSTS OFF) UPDATE t1 SET b = b || b WHERE f_leak(b); EXPLAIN (COSTS OFF) UPDATE t1 SET b = b || b WHERE f_leak(b);
QUERY PLAN QUERY PLAN
------------------------------------- -------------------------------------------
Update on t1 t1_3 Update on t1 t1_3
-> Subquery Scan on t1 -> Subquery Scan on t1
Filter: f_leak(t1.b) Filter: f_leak(t1.b)
-> Seq Scan on t1 t1_4 -> LockRows
Filter: ((a % 2) = 0) -> Seq Scan on t1 t1_4
Filter: ((a % 2) = 0)
-> Subquery Scan on t1_1 -> Subquery Scan on t1_1
Filter: f_leak(t1_1.b) Filter: f_leak(t1_1.b)
-> Seq Scan on t2 -> LockRows
Filter: ((a % 2) = 0) -> Seq Scan on t2
Filter: ((a % 2) = 0)
-> Subquery Scan on t1_2 -> Subquery Scan on t1_2
Filter: f_leak(t1_2.b) Filter: f_leak(t1_2.b)
-> Seq Scan on t3 -> LockRows
Filter: ((a % 2) = 0) -> Seq Scan on t3
(13 rows) Filter: ((a % 2) = 0)
(16 rows)
UPDATE t1 SET b = b || b WHERE f_leak(b); UPDATE t1 SET b = b || b WHERE f_leak(b);
NOTICE: f_leak => bbb NOTICE: f_leak => bbb
...@@ -1058,14 +1061,15 @@ NOTICE: f_leak => bcd ...@@ -1058,14 +1061,15 @@ NOTICE: f_leak => bcd
NOTICE: f_leak => def NOTICE: f_leak => def
NOTICE: f_leak => yyy NOTICE: f_leak => yyy
EXPLAIN (COSTS OFF) UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b); EXPLAIN (COSTS OFF) UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b);
QUERY PLAN QUERY PLAN
------------------------------------- -------------------------------------------
Update on t1 t1_1 Update on t1 t1_1
-> Subquery Scan on t1 -> Subquery Scan on t1
Filter: f_leak(t1.b) Filter: f_leak(t1.b)
-> Seq Scan on t1 t1_2 -> LockRows
Filter: ((a % 2) = 0) -> Seq Scan on t1 t1_2
(5 rows) Filter: ((a % 2) = 0)
(6 rows)
UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b); UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b);
NOTICE: f_leak => bbbbbb NOTICE: f_leak => bbbbbb
...@@ -1131,32 +1135,36 @@ SELECT * FROM t1; ...@@ -1131,32 +1135,36 @@ SELECT * FROM t1;
SET SESSION AUTHORIZATION rls_regress_user1; SET SESSION AUTHORIZATION rls_regress_user1;
SET row_security TO ON; SET row_security TO ON;
EXPLAIN (COSTS OFF) DELETE FROM only t1 WHERE f_leak(b); EXPLAIN (COSTS OFF) DELETE FROM only t1 WHERE f_leak(b);
QUERY PLAN QUERY PLAN
------------------------------------- -------------------------------------------
Delete on t1 t1_1 Delete on t1 t1_1
-> Subquery Scan on t1 -> Subquery Scan on t1
Filter: f_leak(t1.b) Filter: f_leak(t1.b)
-> Seq Scan on t1 t1_2 -> LockRows
Filter: ((a % 2) = 0) -> Seq Scan on t1 t1_2
(5 rows) Filter: ((a % 2) = 0)
(6 rows)
EXPLAIN (COSTS OFF) DELETE FROM t1 WHERE f_leak(b); EXPLAIN (COSTS OFF) DELETE FROM t1 WHERE f_leak(b);
QUERY PLAN QUERY PLAN
------------------------------------- -------------------------------------------
Delete on t1 t1_3 Delete on t1 t1_3
-> Subquery Scan on t1 -> Subquery Scan on t1
Filter: f_leak(t1.b) Filter: f_leak(t1.b)
-> Seq Scan on t1 t1_4 -> LockRows
Filter: ((a % 2) = 0) -> Seq Scan on t1 t1_4
Filter: ((a % 2) = 0)
-> Subquery Scan on t1_1 -> Subquery Scan on t1_1
Filter: f_leak(t1_1.b) Filter: f_leak(t1_1.b)
-> Seq Scan on t2 -> LockRows
Filter: ((a % 2) = 0) -> Seq Scan on t2
Filter: ((a % 2) = 0)
-> Subquery Scan on t1_2 -> Subquery Scan on t1_2
Filter: f_leak(t1_2.b) Filter: f_leak(t1_2.b)
-> Seq Scan on t3 -> LockRows
Filter: ((a % 2) = 0) -> Seq Scan on t3
(13 rows) Filter: ((a % 2) = 0)
(16 rows)
DELETE FROM only t1 WHERE f_leak(b) RETURNING oid, *, t1; DELETE FROM only t1 WHERE f_leak(b) RETURNING oid, *, t1;
NOTICE: f_leak => bbbbbb_updt NOTICE: f_leak => bbbbbb_updt
......
...@@ -1842,24 +1842,26 @@ EXPLAIN (costs off) SELECT * FROM rw_view1 WHERE snoop(person); ...@@ -1842,24 +1842,26 @@ EXPLAIN (costs off) SELECT * FROM rw_view1 WHERE snoop(person);
(4 rows) (4 rows)
EXPLAIN (costs off) UPDATE rw_view1 SET person=person WHERE snoop(person); EXPLAIN (costs off) UPDATE rw_view1 SET person=person WHERE snoop(person);
QUERY PLAN QUERY PLAN
----------------------------------------------------- -----------------------------------------------------------
Update on base_tbl base_tbl_1 Update on base_tbl base_tbl_1
-> Subquery Scan on base_tbl -> Subquery Scan on base_tbl
Filter: snoop(base_tbl.person) Filter: snoop(base_tbl.person)
-> Seq Scan on base_tbl base_tbl_2 -> LockRows
Filter: (visibility = 'public'::text) -> Seq Scan on base_tbl base_tbl_2
(5 rows) Filter: (visibility = 'public'::text)
(6 rows)
EXPLAIN (costs off) DELETE FROM rw_view1 WHERE NOT snoop(person); EXPLAIN (costs off) DELETE FROM rw_view1 WHERE NOT snoop(person);
QUERY PLAN QUERY PLAN
----------------------------------------------------- -----------------------------------------------------------
Delete on base_tbl base_tbl_1 Delete on base_tbl base_tbl_1
-> Subquery Scan on base_tbl -> Subquery Scan on base_tbl
Filter: (NOT snoop(base_tbl.person)) Filter: (NOT snoop(base_tbl.person))
-> Seq Scan on base_tbl base_tbl_2 -> LockRows
Filter: (visibility = 'public'::text) -> Seq Scan on base_tbl base_tbl_2
(5 rows) Filter: (visibility = 'public'::text)
(6 rows)
-- security barrier view on top of security barrier view -- security barrier view on top of security barrier view
CREATE VIEW rw_view2 WITH (security_barrier = true) AS CREATE VIEW rw_view2 WITH (security_barrier = true) AS
...@@ -1922,28 +1924,30 @@ EXPLAIN (costs off) SELECT * FROM rw_view2 WHERE snoop(person); ...@@ -1922,28 +1924,30 @@ EXPLAIN (costs off) SELECT * FROM rw_view2 WHERE snoop(person);
(6 rows) (6 rows)
EXPLAIN (costs off) UPDATE rw_view2 SET person=person WHERE snoop(person); EXPLAIN (costs off) UPDATE rw_view2 SET person=person WHERE snoop(person);
QUERY PLAN QUERY PLAN
----------------------------------------------------------- -----------------------------------------------------------------
Update on base_tbl base_tbl_1 Update on base_tbl base_tbl_1
-> Subquery Scan on base_tbl -> Subquery Scan on base_tbl
Filter: snoop(base_tbl.person) Filter: snoop(base_tbl.person)
-> Subquery Scan on base_tbl_2 -> Subquery Scan on base_tbl_2
Filter: snoop(base_tbl_2.person) Filter: snoop(base_tbl_2.person)
-> Seq Scan on base_tbl base_tbl_3 -> LockRows
Filter: (visibility = 'public'::text) -> Seq Scan on base_tbl base_tbl_3
(7 rows) Filter: (visibility = 'public'::text)
(8 rows)
EXPLAIN (costs off) DELETE FROM rw_view2 WHERE NOT snoop(person); EXPLAIN (costs off) DELETE FROM rw_view2 WHERE NOT snoop(person);
QUERY PLAN QUERY PLAN
----------------------------------------------------------- -----------------------------------------------------------------
Delete on base_tbl base_tbl_1 Delete on base_tbl base_tbl_1
-> Subquery Scan on base_tbl -> Subquery Scan on base_tbl
Filter: (NOT snoop(base_tbl.person)) Filter: (NOT snoop(base_tbl.person))
-> Subquery Scan on base_tbl_2 -> Subquery Scan on base_tbl_2
Filter: snoop(base_tbl_2.person) Filter: snoop(base_tbl_2.person)
-> Seq Scan on base_tbl base_tbl_3 -> LockRows
Filter: (visibility = 'public'::text) -> Seq Scan on base_tbl base_tbl_3
(7 rows) Filter: (visibility = 'public'::text)
(8 rows)
DROP TABLE base_tbl CASCADE; DROP TABLE base_tbl CASCADE;
NOTICE: drop cascades to 2 other objects NOTICE: drop cascades to 2 other objects
...@@ -2057,70 +2061,78 @@ SELECT * FROM v1 WHERE a=8; ...@@ -2057,70 +2061,78 @@ SELECT * FROM v1 WHERE a=8;
EXPLAIN (VERBOSE, COSTS OFF) EXPLAIN (VERBOSE, COSTS OFF)
UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3;
QUERY PLAN QUERY PLAN
------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------
Update on public.t1 t1_4 Update on public.t1 t1_4
-> Subquery Scan on t1 -> Subquery Scan on t1
Output: 100, t1.b, t1.c, t1.ctid Output: 100, t1.b, t1.c, t1.ctid
Filter: snoop(t1.a) Filter: snoop(t1.a)
-> Nested Loop Semi Join -> LockRows
Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid
-> Seq Scan on public.t1 t1_5 -> Nested Loop Semi Join
Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid
Filter: ((t1_5.a > 5) AND (t1_5.a = 3) AND leakproof(t1_5.a)) -> Seq Scan on public.t1 t1_5
-> Append Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c
-> Seq Scan on public.t12 Filter: ((t1_5.a > 5) AND (t1_5.a = 3) AND leakproof(t1_5.a))
Output: t12.a -> Append
Filter: (t12.a = 3) -> Seq Scan on public.t12
-> Seq Scan on public.t111 Output: t12.ctid, t12.tableoid, t12.a
Output: t111.a Filter: (t12.a = 3)
Filter: (t111.a = 3) -> Seq Scan on public.t111
Output: t111.ctid, t111.tableoid, t111.a
Filter: (t111.a = 3)
-> Subquery Scan on t1_1 -> Subquery Scan on t1_1
Output: 100, t1_1.b, t1_1.c, t1_1.d, t1_1.ctid Output: 100, t1_1.b, t1_1.c, t1_1.d, t1_1.ctid
Filter: snoop(t1_1.a) Filter: snoop(t1_1.a)
-> Nested Loop Semi Join -> LockRows
Output: t11.ctid, t11.a, t11.b, t11.c, t11.d Output: t11.ctid, t11.a, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid
-> Seq Scan on public.t11 -> Nested Loop Semi Join
Output: t11.ctid, t11.a, t11.b, t11.c, t11.d Output: t11.ctid, t11.a, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid
Filter: ((t11.a > 5) AND (t11.a = 3) AND leakproof(t11.a)) -> Seq Scan on public.t11
-> Append Output: t11.ctid, t11.a, t11.b, t11.c, t11.d
-> Seq Scan on public.t12 t12_1 Filter: ((t11.a > 5) AND (t11.a = 3) AND leakproof(t11.a))
Output: t12_1.a -> Append
Filter: (t12_1.a = 3) -> Seq Scan on public.t12 t12_1
-> Seq Scan on public.t111 t111_1 Output: t12_1.ctid, t12_1.tableoid, t12_1.a
Output: t111_1.a Filter: (t12_1.a = 3)
Filter: (t111_1.a = 3) -> Seq Scan on public.t111 t111_1
Output: t111_1.ctid, t111_1.tableoid, t111_1.a
Filter: (t111_1.a = 3)
-> Subquery Scan on t1_2 -> Subquery Scan on t1_2
Output: 100, t1_2.b, t1_2.c, t1_2.e, t1_2.ctid Output: 100, t1_2.b, t1_2.c, t1_2.e, t1_2.ctid
Filter: snoop(t1_2.a) Filter: snoop(t1_2.a)
-> Nested Loop Semi Join -> LockRows
Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid
-> Seq Scan on public.t12 t12_2 -> Nested Loop Semi Join
Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid
Filter: ((t12_2.a > 5) AND (t12_2.a = 3) AND leakproof(t12_2.a)) -> Seq Scan on public.t12 t12_2
-> Append Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e
-> Seq Scan on public.t12 t12_3 Filter: ((t12_2.a > 5) AND (t12_2.a = 3) AND leakproof(t12_2.a))
Output: t12_3.a -> Append
Filter: (t12_3.a = 3) -> Seq Scan on public.t12 t12_3
-> Seq Scan on public.t111 t111_2 Output: t12_3.ctid, t12_3.tableoid, t12_3.a
Output: t111_2.a Filter: (t12_3.a = 3)
Filter: (t111_2.a = 3) -> Seq Scan on public.t111 t111_2
Output: t111_2.ctid, t111_2.tableoid, t111_2.a
Filter: (t111_2.a = 3)
-> Subquery Scan on t1_3 -> Subquery Scan on t1_3
Output: 100, t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid Output: 100, t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid
Filter: snoop(t1_3.a) Filter: snoop(t1_3.a)
-> Nested Loop Semi Join -> LockRows
Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid
-> Seq Scan on public.t111 t111_3 -> Nested Loop Semi Join
Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid
Filter: ((t111_3.a > 5) AND (t111_3.a = 3) AND leakproof(t111_3.a)) -> Seq Scan on public.t111 t111_3
-> Append Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e
-> Seq Scan on public.t12 t12_4 Filter: ((t111_3.a > 5) AND (t111_3.a = 3) AND leakproof(t111_3.a))
Output: t12_4.a -> Append
Filter: (t12_4.a = 3) -> Seq Scan on public.t12 t12_4
-> Seq Scan on public.t111 t111_4 Output: t12_4.ctid, t12_4.tableoid, t12_4.a
Output: t111_4.a Filter: (t12_4.a = 3)
Filter: (t111_4.a = 3) -> Seq Scan on public.t111 t111_4
(61 rows) Output: t111_4.ctid, t111_4.tableoid, t111_4.a
Filter: (t111_4.a = 3)
(69 rows)
UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3;
SELECT * FROM v1 WHERE a=100; -- Nothing should have been changed to 100 SELECT * FROM v1 WHERE a=100; -- Nothing should have been changed to 100
...@@ -2135,70 +2147,78 @@ SELECT * FROM t1 WHERE a=100; -- Nothing should have been changed to 100 ...@@ -2135,70 +2147,78 @@ SELECT * FROM t1 WHERE a=100; -- Nothing should have been changed to 100
EXPLAIN (VERBOSE, COSTS OFF) EXPLAIN (VERBOSE, COSTS OFF)
UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8; UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8;
QUERY PLAN QUERY PLAN
------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------
Update on public.t1 t1_4 Update on public.t1 t1_4
-> Subquery Scan on t1 -> Subquery Scan on t1
Output: (t1.a + 1), t1.b, t1.c, t1.ctid Output: (t1.a + 1), t1.b, t1.c, t1.ctid
Filter: snoop(t1.a) Filter: snoop(t1.a)
-> Nested Loop Semi Join -> LockRows
Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid
-> Seq Scan on public.t1 t1_5 -> Nested Loop Semi Join
Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid
Filter: ((t1_5.a > 5) AND (t1_5.a = 8) AND leakproof(t1_5.a)) -> Seq Scan on public.t1 t1_5
-> Append Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c
-> Seq Scan on public.t12 Filter: ((t1_5.a > 5) AND (t1_5.a = 8) AND leakproof(t1_5.a))
Output: t12.a -> Append
Filter: (t12.a = 8) -> Seq Scan on public.t12
-> Seq Scan on public.t111 Output: t12.ctid, t12.tableoid, t12.a
Output: t111.a Filter: (t12.a = 8)
Filter: (t111.a = 8) -> Seq Scan on public.t111
Output: t111.ctid, t111.tableoid, t111.a
Filter: (t111.a = 8)
-> Subquery Scan on t1_1 -> Subquery Scan on t1_1
Output: (t1_1.a + 1), t1_1.b, t1_1.c, t1_1.d, t1_1.ctid Output: (t1_1.a + 1), t1_1.b, t1_1.c, t1_1.d, t1_1.ctid
Filter: snoop(t1_1.a) Filter: snoop(t1_1.a)
-> Nested Loop Semi Join -> LockRows
Output: t11.a, t11.ctid, t11.b, t11.c, t11.d Output: t11.a, t11.ctid, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid
-> Seq Scan on public.t11 -> Nested Loop Semi Join
Output: t11.a, t11.ctid, t11.b, t11.c, t11.d Output: t11.a, t11.ctid, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid
Filter: ((t11.a > 5) AND (t11.a = 8) AND leakproof(t11.a)) -> Seq Scan on public.t11
-> Append Output: t11.a, t11.ctid, t11.b, t11.c, t11.d
-> Seq Scan on public.t12 t12_1 Filter: ((t11.a > 5) AND (t11.a = 8) AND leakproof(t11.a))
Output: t12_1.a -> Append
Filter: (t12_1.a = 8) -> Seq Scan on public.t12 t12_1
-> Seq Scan on public.t111 t111_1 Output: t12_1.ctid, t12_1.tableoid, t12_1.a
Output: t111_1.a Filter: (t12_1.a = 8)
Filter: (t111_1.a = 8) -> Seq Scan on public.t111 t111_1
Output: t111_1.ctid, t111_1.tableoid, t111_1.a
Filter: (t111_1.a = 8)
-> Subquery Scan on t1_2 -> Subquery Scan on t1_2
Output: (t1_2.a + 1), t1_2.b, t1_2.c, t1_2.e, t1_2.ctid Output: (t1_2.a + 1), t1_2.b, t1_2.c, t1_2.e, t1_2.ctid
Filter: snoop(t1_2.a) Filter: snoop(t1_2.a)
-> Nested Loop Semi Join -> LockRows
Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid
-> Seq Scan on public.t12 t12_2 -> Nested Loop Semi Join
Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid
Filter: ((t12_2.a > 5) AND (t12_2.a = 8) AND leakproof(t12_2.a)) -> Seq Scan on public.t12 t12_2
-> Append Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e
-> Seq Scan on public.t12 t12_3 Filter: ((t12_2.a > 5) AND (t12_2.a = 8) AND leakproof(t12_2.a))
Output: t12_3.a -> Append
Filter: (t12_3.a = 8) -> Seq Scan on public.t12 t12_3
-> Seq Scan on public.t111 t111_2 Output: t12_3.ctid, t12_3.tableoid, t12_3.a
Output: t111_2.a Filter: (t12_3.a = 8)
Filter: (t111_2.a = 8) -> Seq Scan on public.t111 t111_2
Output: t111_2.ctid, t111_2.tableoid, t111_2.a
Filter: (t111_2.a = 8)
-> Subquery Scan on t1_3 -> Subquery Scan on t1_3
Output: (t1_3.a + 1), t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid Output: (t1_3.a + 1), t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid
Filter: snoop(t1_3.a) Filter: snoop(t1_3.a)
-> Nested Loop Semi Join -> LockRows
Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid
-> Seq Scan on public.t111 t111_3 -> Nested Loop Semi Join
Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid
Filter: ((t111_3.a > 5) AND (t111_3.a = 8) AND leakproof(t111_3.a)) -> Seq Scan on public.t111 t111_3
-> Append Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e
-> Seq Scan on public.t12 t12_4 Filter: ((t111_3.a > 5) AND (t111_3.a = 8) AND leakproof(t111_3.a))
Output: t12_4.a -> Append
Filter: (t12_4.a = 8) -> Seq Scan on public.t12 t12_4
-> Seq Scan on public.t111 t111_4 Output: t12_4.ctid, t12_4.tableoid, t12_4.a
Output: t111_4.a Filter: (t12_4.a = 8)
Filter: (t111_4.a = 8) -> Seq Scan on public.t111 t111_4
(61 rows) Output: t111_4.ctid, t111_4.tableoid, t111_4.a
Filter: (t111_4.a = 8)
(69 rows)
UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8; UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8;
NOTICE: snooped value: 8 NOTICE: snooped value: 8
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment