Skip to content

Commit b54cff2

Browse files
committed
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 148e632, but not being aware of any user-visible consequences, he quite reasonably didn't back-patch. This patch is simply a back-patch of 148e632, 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
1 parent 603a28b commit b54cff2

File tree

4 files changed

+68
-15
lines changed

4 files changed

+68
-15
lines changed

src/backend/executor/nodeModifyTable.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1988,7 +1988,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
19881988
{
19891989
WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
19901990
ExprState *wcoExpr = ExecInitQual((List *) wco->qual,
1991-
mtstate->mt_plans[i]);
1991+
&mtstate->ps);
19921992

19931993
wcoExprs = lappend(wcoExprs, wcoExpr);
19941994
}

src/test/regress/expected/rowsecurity.out

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3959,6 +3959,40 @@ DROP OPERATOR <<< (int, int);
39593959
DROP FUNCTION op_leak(int, int);
39603960
RESET SESSION AUTHORIZATION;
39613961
DROP TABLE rls_tbl;
3962+
-- Bug #16006: whole-row Vars in a policy don't play nice with sub-selects
3963+
SET SESSION AUTHORIZATION regress_rls_alice;
3964+
CREATE TABLE rls_tbl (a int, b int, c int);
3965+
CREATE POLICY p1 ON rls_tbl USING (rls_tbl >= ROW(1,1,1));
3966+
ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
3967+
ALTER TABLE rls_tbl FORCE ROW LEVEL SECURITY;
3968+
INSERT INTO rls_tbl SELECT 10, 20, 30;
3969+
EXPLAIN (VERBOSE, COSTS OFF)
3970+
INSERT INTO rls_tbl
3971+
SELECT * FROM (SELECT b, c FROM rls_tbl ORDER BY a) ss;
3972+
QUERY PLAN
3973+
--------------------------------------------------------------------
3974+
Insert on regress_rls_schema.rls_tbl
3975+
-> Subquery Scan on ss
3976+
Output: ss.b, ss.c, NULL::integer
3977+
-> Sort
3978+
Output: rls_tbl_1.b, rls_tbl_1.c, rls_tbl_1.a
3979+
Sort Key: rls_tbl_1.a
3980+
-> Seq Scan on regress_rls_schema.rls_tbl rls_tbl_1
3981+
Output: rls_tbl_1.b, rls_tbl_1.c, rls_tbl_1.a
3982+
Filter: (rls_tbl_1.* >= ROW(1, 1, 1))
3983+
(9 rows)
3984+
3985+
INSERT INTO rls_tbl
3986+
SELECT * FROM (SELECT b, c FROM rls_tbl ORDER BY a) ss;
3987+
SELECT * FROM rls_tbl;
3988+
a | b | c
3989+
----+----+----
3990+
10 | 20 | 30
3991+
20 | 30 |
3992+
(2 rows)
3993+
3994+
DROP TABLE rls_tbl;
3995+
RESET SESSION AUTHORIZATION;
39623996
--
39633997
-- Clean up objects
39643998
--

src/test/regress/expected/updatable_views.out

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,31 +1658,31 @@ UPDATE rw_view1 SET a = a + 5; -- should fail
16581658
ERROR: new row violates check option for view "rw_view1"
16591659
DETAIL: Failing row contains (15).
16601660
EXPLAIN (costs off) INSERT INTO rw_view1 VALUES (5);
1661-
QUERY PLAN
1662-
---------------------------------------------------------------
1661+
QUERY PLAN
1662+
---------------------------------------------------------
16631663
Insert on base_tbl b
16641664
-> Result
1665-
SubPlan 1
1666-
-> Index Only Scan using ref_tbl_pkey on ref_tbl r
1667-
Index Cond: (a = b.a)
1668-
SubPlan 2
1669-
-> Seq Scan on ref_tbl r_1
1665+
SubPlan 1
1666+
-> Index Only Scan using ref_tbl_pkey on ref_tbl r
1667+
Index Cond: (a = b.a)
1668+
SubPlan 2
1669+
-> Seq Scan on ref_tbl r_1
16701670
(7 rows)
16711671

16721672
EXPLAIN (costs off) UPDATE rw_view1 SET a = a + 5;
1673-
QUERY PLAN
1674-
-----------------------------------------------------------------
1673+
QUERY PLAN
1674+
-----------------------------------------------------------
16751675
Update on base_tbl b
16761676
-> Hash Join
16771677
Hash Cond: (b.a = r.a)
16781678
-> Seq Scan on base_tbl b
16791679
-> Hash
16801680
-> Seq Scan on ref_tbl r
1681-
SubPlan 1
1682-
-> Index Only Scan using ref_tbl_pkey on ref_tbl r_1
1683-
Index Cond: (a = b.a)
1684-
SubPlan 2
1685-
-> Seq Scan on ref_tbl r_2
1681+
SubPlan 1
1682+
-> Index Only Scan using ref_tbl_pkey on ref_tbl r_1
1683+
Index Cond: (a = b.a)
1684+
SubPlan 2
1685+
-> Seq Scan on ref_tbl r_2
16861686
(11 rows)
16871687

16881688
DROP TABLE base_tbl, ref_tbl CASCADE;

src/test/regress/sql/rowsecurity.sql

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,6 +1813,25 @@ DROP FUNCTION op_leak(int, int);
18131813
RESET SESSION AUTHORIZATION;
18141814
DROP TABLE rls_tbl;
18151815

1816+
-- Bug #16006: whole-row Vars in a policy don't play nice with sub-selects
1817+
SET SESSION AUTHORIZATION regress_rls_alice;
1818+
CREATE TABLE rls_tbl (a int, b int, c int);
1819+
CREATE POLICY p1 ON rls_tbl USING (rls_tbl >= ROW(1,1,1));
1820+
1821+
ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
1822+
ALTER TABLE rls_tbl FORCE ROW LEVEL SECURITY;
1823+
1824+
INSERT INTO rls_tbl SELECT 10, 20, 30;
1825+
EXPLAIN (VERBOSE, COSTS OFF)
1826+
INSERT INTO rls_tbl
1827+
SELECT * FROM (SELECT b, c FROM rls_tbl ORDER BY a) ss;
1828+
INSERT INTO rls_tbl
1829+
SELECT * FROM (SELECT b, c FROM rls_tbl ORDER BY a) ss;
1830+
SELECT * FROM rls_tbl;
1831+
1832+
DROP TABLE rls_tbl;
1833+
RESET SESSION AUTHORIZATION;
1834+
18161835
--
18171836
-- Clean up objects
18181837
--

0 commit comments

Comments
 (0)