mirror of
https://github.com/postgres/postgres.git
synced 2025-05-29 16:21:20 +03:00
Fix usage of whole-row variables in WCO and RLS policy expressions.
Since WITH CHECK OPTION was introduced, ExecInitModifyTable has initialized WCO expressions with the wrong plan node as parent -- that is, it passed its input subplan not the ModifyTable node itself. Up to now we thought this was harmless, but bug #16006 from Vinay Banakar shows it's not: if the input node is a SubqueryScan then ExecInitWholeRowVar can get confused into doing the wrong thing. (The fact that ExecInitWholeRowVar contains such logic is certainly a horrid kluge that doesn't deserve to live, but figuring out another way to do that is a task for some other day.) Andres had already noticed the wrong-parent mistake and fixed it in commit 148e632c0, but not being aware of any user-visible consequences, he quite reasonably didn't back-patch. This patch is simply a back-patch of 148e632c0, plus addition of a test case based on bug #16006. I also added the test case to v12/HEAD, even though the bug is already fixed there. Back-patch to all supported branches. 9.4 lacks RLS policies so the new test case doesn't work there, but I'm pretty sure a test could be devised based on using a whole-row Var in a plain WITH CHECK OPTION condition. (I lack the cycles to do so myself, though.) Andres Freund and Tom Lane Discussion: https://postgr.es/m/16006-99290d2e4642cbd5@postgresql.org Discussion: https://postgr.es/m/20181205225213.hiwa3kgoxeybqcqv@alap3.anarazel.de
This commit is contained in:
parent
603a28b449
commit
b54cff2bf3
@ -1988,7 +1988,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
|
|||||||
{
|
{
|
||||||
WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
|
WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
|
||||||
ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
|
ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
|
||||||
mtstate->mt_plans[i]);
|
&mtstate->ps);
|
||||||
|
|
||||||
wcoExprs = lappend(wcoExprs, wcoExpr);
|
wcoExprs = lappend(wcoExprs, wcoExpr);
|
||||||
}
|
}
|
||||||
|
@ -3959,6 +3959,40 @@ DROP OPERATOR <<< (int, int);
|
|||||||
DROP FUNCTION op_leak(int, int);
|
DROP FUNCTION op_leak(int, int);
|
||||||
RESET SESSION AUTHORIZATION;
|
RESET SESSION AUTHORIZATION;
|
||||||
DROP TABLE rls_tbl;
|
DROP TABLE rls_tbl;
|
||||||
|
-- Bug #16006: whole-row Vars in a policy don't play nice with sub-selects
|
||||||
|
SET SESSION AUTHORIZATION regress_rls_alice;
|
||||||
|
CREATE TABLE rls_tbl (a int, b int, c int);
|
||||||
|
CREATE POLICY p1 ON rls_tbl USING (rls_tbl >= ROW(1,1,1));
|
||||||
|
ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE rls_tbl FORCE ROW LEVEL SECURITY;
|
||||||
|
INSERT INTO rls_tbl SELECT 10, 20, 30;
|
||||||
|
EXPLAIN (VERBOSE, COSTS OFF)
|
||||||
|
INSERT INTO rls_tbl
|
||||||
|
SELECT * FROM (SELECT b, c FROM rls_tbl ORDER BY a) ss;
|
||||||
|
QUERY PLAN
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
Insert on regress_rls_schema.rls_tbl
|
||||||
|
-> Subquery Scan on ss
|
||||||
|
Output: ss.b, ss.c, NULL::integer
|
||||||
|
-> Sort
|
||||||
|
Output: rls_tbl_1.b, rls_tbl_1.c, rls_tbl_1.a
|
||||||
|
Sort Key: rls_tbl_1.a
|
||||||
|
-> Seq Scan on regress_rls_schema.rls_tbl rls_tbl_1
|
||||||
|
Output: rls_tbl_1.b, rls_tbl_1.c, rls_tbl_1.a
|
||||||
|
Filter: (rls_tbl_1.* >= ROW(1, 1, 1))
|
||||||
|
(9 rows)
|
||||||
|
|
||||||
|
INSERT INTO rls_tbl
|
||||||
|
SELECT * FROM (SELECT b, c FROM rls_tbl ORDER BY a) ss;
|
||||||
|
SELECT * FROM rls_tbl;
|
||||||
|
a | b | c
|
||||||
|
----+----+----
|
||||||
|
10 | 20 | 30
|
||||||
|
20 | 30 |
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
DROP TABLE rls_tbl;
|
||||||
|
RESET SESSION AUTHORIZATION;
|
||||||
--
|
--
|
||||||
-- Clean up objects
|
-- Clean up objects
|
||||||
--
|
--
|
||||||
|
@ -1658,31 +1658,31 @@ UPDATE rw_view1 SET a = a + 5; -- should fail
|
|||||||
ERROR: new row violates check option for view "rw_view1"
|
ERROR: new row violates check option for view "rw_view1"
|
||||||
DETAIL: Failing row contains (15).
|
DETAIL: Failing row contains (15).
|
||||||
EXPLAIN (costs off) INSERT INTO rw_view1 VALUES (5);
|
EXPLAIN (costs off) INSERT INTO rw_view1 VALUES (5);
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------
|
||||||
Insert on base_tbl b
|
Insert on base_tbl b
|
||||||
-> Result
|
-> Result
|
||||||
SubPlan 1
|
SubPlan 1
|
||||||
-> Index Only Scan using ref_tbl_pkey on ref_tbl r
|
-> Index Only Scan using ref_tbl_pkey on ref_tbl r
|
||||||
Index Cond: (a = b.a)
|
Index Cond: (a = b.a)
|
||||||
SubPlan 2
|
SubPlan 2
|
||||||
-> Seq Scan on ref_tbl r_1
|
-> Seq Scan on ref_tbl r_1
|
||||||
(7 rows)
|
(7 rows)
|
||||||
|
|
||||||
EXPLAIN (costs off) UPDATE rw_view1 SET a = a + 5;
|
EXPLAIN (costs off) UPDATE rw_view1 SET a = a + 5;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
-----------------------------------------------------------------
|
-----------------------------------------------------------
|
||||||
Update on base_tbl b
|
Update on base_tbl b
|
||||||
-> Hash Join
|
-> Hash Join
|
||||||
Hash Cond: (b.a = r.a)
|
Hash Cond: (b.a = r.a)
|
||||||
-> Seq Scan on base_tbl b
|
-> Seq Scan on base_tbl b
|
||||||
-> Hash
|
-> Hash
|
||||||
-> Seq Scan on ref_tbl r
|
-> Seq Scan on ref_tbl r
|
||||||
SubPlan 1
|
SubPlan 1
|
||||||
-> Index Only Scan using ref_tbl_pkey on ref_tbl r_1
|
-> Index Only Scan using ref_tbl_pkey on ref_tbl r_1
|
||||||
Index Cond: (a = b.a)
|
Index Cond: (a = b.a)
|
||||||
SubPlan 2
|
SubPlan 2
|
||||||
-> Seq Scan on ref_tbl r_2
|
-> Seq Scan on ref_tbl r_2
|
||||||
(11 rows)
|
(11 rows)
|
||||||
|
|
||||||
DROP TABLE base_tbl, ref_tbl CASCADE;
|
DROP TABLE base_tbl, ref_tbl CASCADE;
|
||||||
|
@ -1813,6 +1813,25 @@ DROP FUNCTION op_leak(int, int);
|
|||||||
RESET SESSION AUTHORIZATION;
|
RESET SESSION AUTHORIZATION;
|
||||||
DROP TABLE rls_tbl;
|
DROP TABLE rls_tbl;
|
||||||
|
|
||||||
|
-- Bug #16006: whole-row Vars in a policy don't play nice with sub-selects
|
||||||
|
SET SESSION AUTHORIZATION regress_rls_alice;
|
||||||
|
CREATE TABLE rls_tbl (a int, b int, c int);
|
||||||
|
CREATE POLICY p1 ON rls_tbl USING (rls_tbl >= ROW(1,1,1));
|
||||||
|
|
||||||
|
ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE rls_tbl FORCE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
INSERT INTO rls_tbl SELECT 10, 20, 30;
|
||||||
|
EXPLAIN (VERBOSE, COSTS OFF)
|
||||||
|
INSERT INTO rls_tbl
|
||||||
|
SELECT * FROM (SELECT b, c FROM rls_tbl ORDER BY a) ss;
|
||||||
|
INSERT INTO rls_tbl
|
||||||
|
SELECT * FROM (SELECT b, c FROM rls_tbl ORDER BY a) ss;
|
||||||
|
SELECT * FROM rls_tbl;
|
||||||
|
|
||||||
|
DROP TABLE rls_tbl;
|
||||||
|
RESET SESSION AUTHORIZATION;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Clean up objects
|
-- Clean up objects
|
||||||
--
|
--
|
||||||
|
Loading…
x
Reference in New Issue
Block a user