From babf1cc1a3486adfbd78fc6f63f3b4559e9bc793 Mon Sep 17 00:00:00 2001 From: Viktor Holmberg Date: Mon, 20 Oct 2025 15:52:24 +0200 Subject: [PATCH 3/3] Adding comments to new RLS tests --- src/test/regress/expected/rowsecurity.out | 22 ++++++++++++++++++++++ src/test/regress/sql/rowsecurity.sql | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out index a32f8f07e43..f945115ece8 100644 --- a/src/test/regress/expected/rowsecurity.out +++ b/src/test/regress/expected/rowsecurity.out @@ -33,9 +33,12 @@ CREATE OR REPLACE FUNCTION f_leak(text) RETURNS bool GRANT EXECUTE ON FUNCTION f_leak(text) TO public; -- Test policies applied by command type SET SESSION AUTHORIZATION regress_rls_alice; +-- Setup: Create a source table (for MERGE operations) CREATE TABLE rls_test_src (a int PRIMARY KEY, b text); ALTER TABLE rls_test_src ENABLE ROW LEVEL SECURITY; INSERT INTO rls_test_src VALUES (1, 'src a'); +-- Setup: Create a target table with a trigger that sets column c = UPPER(b) +-- This trigger ensures that policy functions see the "final" row state CREATE TABLE rls_test_tgt (a int PRIMARY KEY, b text, c text); ALTER TABLE rls_test_tgt ENABLE ROW LEVEL SECURITY; CREATE FUNCTION rls_test_tgt_set_c() RETURNS trigger AS @@ -43,6 +46,8 @@ CREATE FUNCTION rls_test_tgt_set_c() RETURNS trigger AS LANGUAGE plpgsql; CREATE TRIGGER rls_test_tgt_set_c BEFORE INSERT OR UPDATE ON rls_test_tgt FOR EACH ROW EXECUTE FUNCTION rls_test_tgt_set_c(); +-- Setup: Create policy functions that emit NOTICE messages +-- These let us verify which policies are applied and when CREATE FUNCTION sel_using_fn(text, record) RETURNS bool AS $$ BEGIN RAISE NOTICE 'SELECT USING on %.%', $1, $2; RETURN true; END; $$ LANGUAGE plpgsql; @@ -58,6 +63,7 @@ CREATE FUNCTION upd_check_fn(text, record) RETURNS bool AS CREATE FUNCTION del_using_fn(text, record) RETURNS bool AS $$ BEGIN RAISE NOTICE 'DELETE USING on %.%', $1, $2; RETURN true; END; $$ LANGUAGE plpgsql; +-- Setup: Create policies on both tables CREATE POLICY sel_pol ON rls_test_src FOR SELECT USING (sel_using_fn('rls_test_src', rls_test_src)); CREATE POLICY upd_pol ON rls_test_src FOR UPDATE @@ -75,6 +81,8 @@ CREATE POLICY del_pol ON rls_test_tgt FOR DELETE GRANT SELECT, UPDATE ON rls_test_src TO public; GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE ON rls_test_tgt TO public; SET SESSION AUTHORIZATION regress_rls_bob; +-- Test: SELECT with different locking clauses +-- Verify that FOR UPDATE/SHARE/etc apply UPDATE USING policies SELECT * FROM rls_test_src; NOTICE: SELECT USING on rls_test_src.(1,"src a") a | b @@ -114,6 +122,8 @@ NOTICE: SELECT USING on rls_test_src.(1,"src a") 1 | src a (1 row) +-- Test: Basic INSERT +-- Verify INSERT CHECK is applied; with RETURNING also applies SELECT USING INSERT INTO rls_test_tgt VALUES (1, 'tgt a'); NOTICE: INSERT CHECK on rls_test_tgt.(1,"tgt a","TGT A") TRUNCATE rls_test_tgt; @@ -125,6 +135,10 @@ NOTICE: SELECT USING on rls_test_tgt.(1,"tgt a","TGT A") 1 | tgt a | TGT A (1 row) +-- Test: Basic UPDATE +-- Verify UPDATE USING (on old row) and UPDATE CHECK (on new row) are applied +-- With WHERE clause, also applies SELECT USING when reading rows to update +-- With RETURNING, applies SELECT USING on result UPDATE rls_test_tgt SET b = 'tgt b'; NOTICE: UPDATE USING on rls_test_tgt.(1,"tgt a","TGT A") NOTICE: UPDATE CHECK on rls_test_tgt.(1,"tgt b","TGT B") @@ -143,6 +157,8 @@ NOTICE: SELECT USING on rls_test_tgt.(1,"tgt d","TGT D") 1 | tgt d | TGT D (1 row) +-- Test: Basic DELETE +-- Verify DELETE USING is applied; with WHERE or RETURNING also applies SELECT USING BEGIN; DELETE FROM rls_test_tgt; ROLLBACK; NOTICE: DELETE USING on rls_test_tgt.(1,"tgt d","TGT D") BEGIN; DELETE FROM rls_test_tgt WHERE a = 1; ROLLBACK; @@ -156,12 +172,16 @@ NOTICE: SELECT USING on rls_test_tgt.(1,"tgt d","TGT D") 1 | tgt d | TGT D (1 row) +-- Test: INSERT ON CONFLICT DO NOTHING +-- Verify INSERT CHECK is applied for all rows (even those that conflict) INSERT INTO rls_test_tgt VALUES (1, 'tgt a') ON CONFLICT (a) DO NOTHING; NOTICE: INSERT CHECK on rls_test_tgt.(1,"tgt a","TGT A") NOTICE: SELECT USING on rls_test_tgt.(1,"tgt a","TGT A") INSERT INTO rls_test_tgt VALUES (1, 'tgt b') ON CONFLICT (a) DO NOTHING; NOTICE: INSERT CHECK on rls_test_tgt.(1,"tgt b","TGT B") NOTICE: SELECT USING on rls_test_tgt.(1,"tgt b","TGT B") +-- Test: INSERT ON CONFLICT DO UPDATE +-- Verify INSERT CHECK on all rows, then UPDATE policies on conflicting rows BEGIN; INSERT INTO rls_test_tgt VALUES (2, 'tgt a') ON CONFLICT (a) DO UPDATE SET b = 'tgt b'; NOTICE: INSERT CHECK on rls_test_tgt.(2,"tgt a","TGT A") @@ -194,6 +214,8 @@ NOTICE: SELECT USING on rls_test_tgt.(3,"tgt d","TGT D") (1 row) ROLLBACK; +-- Test: MERGE operations +-- Verify policies for MERGE variants match the documented table MERGE INTO rls_test_tgt t USING rls_test_src s ON t.a = s.a WHEN NOT MATCHED THEN DO NOTHING; NOTICE: SELECT USING on rls_test_tgt.(1,"tgt a","TGT A") diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql index 36046426048..d893bbf71e3 100644 --- a/src/test/regress/sql/rowsecurity.sql +++ b/src/test/regress/sql/rowsecurity.sql @@ -44,10 +44,13 @@ GRANT EXECUTE ON FUNCTION f_leak(text) TO public; -- Test policies applied by command type SET SESSION AUTHORIZATION regress_rls_alice; +-- Setup: Create a source table (for MERGE operations) CREATE TABLE rls_test_src (a int PRIMARY KEY, b text); ALTER TABLE rls_test_src ENABLE ROW LEVEL SECURITY; INSERT INTO rls_test_src VALUES (1, 'src a'); +-- Setup: Create a target table with a trigger that sets column c = UPPER(b) +-- This trigger ensures that policy functions see the "final" row state CREATE TABLE rls_test_tgt (a int PRIMARY KEY, b text, c text); ALTER TABLE rls_test_tgt ENABLE ROW LEVEL SECURITY; @@ -57,6 +60,8 @@ CREATE FUNCTION rls_test_tgt_set_c() RETURNS trigger AS CREATE TRIGGER rls_test_tgt_set_c BEFORE INSERT OR UPDATE ON rls_test_tgt FOR EACH ROW EXECUTE FUNCTION rls_test_tgt_set_c(); +-- Setup: Create policy functions that emit NOTICE messages +-- These let us verify which policies are applied and when CREATE FUNCTION sel_using_fn(text, record) RETURNS bool AS $$ BEGIN RAISE NOTICE 'SELECT USING on %.%', $1, $2; RETURN true; END; $$ LANGUAGE plpgsql; @@ -73,6 +78,7 @@ CREATE FUNCTION del_using_fn(text, record) RETURNS bool AS $$ BEGIN RAISE NOTICE 'DELETE USING on %.%', $1, $2; RETURN true; END; $$ LANGUAGE plpgsql; +-- Setup: Create policies on both tables CREATE POLICY sel_pol ON rls_test_src FOR SELECT USING (sel_using_fn('rls_test_src', rls_test_src)); CREATE POLICY upd_pol ON rls_test_src FOR UPDATE @@ -94,27 +100,41 @@ GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE ON rls_test_tgt TO public; SET SESSION AUTHORIZATION regress_rls_bob; +-- Test: SELECT with different locking clauses +-- Verify that FOR UPDATE/SHARE/etc apply UPDATE USING policies SELECT * FROM rls_test_src; SELECT * FROM rls_test_src FOR UPDATE; SELECT * FROM rls_test_src FOR NO KEY UPDATE; SELECT * FROM rls_test_src FOR SHARE; SELECT * FROM rls_test_src FOR KEY SHARE; +-- Test: Basic INSERT +-- Verify INSERT CHECK is applied; with RETURNING also applies SELECT USING INSERT INTO rls_test_tgt VALUES (1, 'tgt a'); TRUNCATE rls_test_tgt; INSERT INTO rls_test_tgt VALUES (1, 'tgt a') RETURNING *; +-- Test: Basic UPDATE +-- Verify UPDATE USING (on old row) and UPDATE CHECK (on new row) are applied +-- With WHERE clause, also applies SELECT USING when reading rows to update +-- With RETURNING, applies SELECT USING on result UPDATE rls_test_tgt SET b = 'tgt b'; UPDATE rls_test_tgt SET b = 'tgt c' WHERE a = 1; UPDATE rls_test_tgt SET b = 'tgt d' RETURNING *; +-- Test: Basic DELETE +-- Verify DELETE USING is applied; with WHERE or RETURNING also applies SELECT USING BEGIN; DELETE FROM rls_test_tgt; ROLLBACK; BEGIN; DELETE FROM rls_test_tgt WHERE a = 1; ROLLBACK; DELETE FROM rls_test_tgt RETURNING *; +-- Test: INSERT ON CONFLICT DO NOTHING +-- Verify INSERT CHECK is applied for all rows (even those that conflict) INSERT INTO rls_test_tgt VALUES (1, 'tgt a') ON CONFLICT (a) DO NOTHING; INSERT INTO rls_test_tgt VALUES (1, 'tgt b') ON CONFLICT (a) DO NOTHING; +-- Test: INSERT ON CONFLICT DO UPDATE +-- Verify INSERT CHECK on all rows, then UPDATE policies on conflicting rows BEGIN; INSERT INTO rls_test_tgt VALUES (2, 'tgt a') ON CONFLICT (a) DO UPDATE SET b = 'tgt b'; INSERT INTO rls_test_tgt VALUES (2, 'tgt c') ON CONFLICT (a) DO UPDATE SET b = 'tgt d'; @@ -122,6 +142,8 @@ INSERT INTO rls_test_tgt VALUES (3, 'tgt a') ON CONFLICT (a) DO UPDATE SET b = ' INSERT INTO rls_test_tgt VALUES (3, 'tgt c') ON CONFLICT (a) DO UPDATE SET b = 'tgt d' RETURNING *; ROLLBACK; +-- Test: MERGE operations +-- Verify policies for MERGE variants match the documented table MERGE INTO rls_test_tgt t USING rls_test_src s ON t.a = s.a WHEN NOT MATCHED THEN DO NOTHING; -- 2.48.1