Attached test case patch shows how RLS fails to play nice with UPDATE
... WHERE CURRENT OF. If you run the revised rowsecurity regression
test against the master branch, the tests do not pass (which, ideally,
they would -- "expected" is actually what I expect here):

*** /home/pg/postgresql/src/test/regress/expected/rowsecurity.out
2015-06-06 15:04:02.142084059 -0700
--- /home/pg/postgresql/src/test/regress/results/rowsecurity.out
2015-06-06 15:04:09.014083800 -0700
***************
*** 2771,2780 ****

  -- Still cannot UPDATE row through cursor:
  UPDATE current_check SET payload = payload || '_new' WHERE CURRENT
OF current_check_cursor RETURNING *;
!  currentid | payload | rlsuser
! -----------+---------+---------
! (0 rows)
! commit;
  --
  -- Clean up objects
  --
--- 2771,2778 ----

  -- Still cannot UPDATE row through cursor:
  UPDATE current_check SET payload = payload || '_new' WHERE CURRENT
OF current_check_cursor RETURNING *;
! ERROR:  WHERE CURRENT OF is not supported for this table type
! COMMIT;
  --
  -- Clean up objects
  --

======================================================================

What's actually occurring here is that the executor imagines that this
involves a foreign table scan (although I suppose it's equivocating a
little bit by not saying so explicitly) -- ExecEvalCurrentOfExpr()
comments imply that that's the only reason why control should reach it
in practice. It looks like RLS has added a new way that CURRENT OF can
fail to be made into a TidScan qualification. It doesn't look like
Dean's most recent round of RLS fixes [1] addressed this case, based
on his remarks. This non-support of WHERE CURRENT OF certainly isn't
documented, and so looks like a bug.

Unfortunately, the fact that WHERE CURRENT OF doesn't already accept
additional qualifications doesn't leave me optimistic about this bug
being easy to fix -- consider the gymnastics performed by commit
c29a9c37 to get an idea of what I mean. Maybe it should just be
formally desupported with RLS, as a stopgap solution for 9.5.

[1] 
http://www.postgresql.org/message-id/caezatcve7hdtfzgcjn-oevvawbtbgg8-fbch9vhdbhuzrsw...@mail.gmail.com
-- 
Peter Geoghegan
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 0ae5557..1c4c551 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -2729,6 +2729,52 @@ COPY copy_t FROM STDIN; --fail - permission denied.
 ERROR:  permission denied for relation copy_t
 RESET SESSION AUTHORIZATION;
 DROP TABLE copy_t;
+-- Check WHERE CURRENT OF
+SET SESSION AUTHORIZATION rls_regress_user0;
+CREATE TABLE current_check (currentid int, payload text, rlsuser text);
+GRANT ALL ON current_check TO PUBLIC;
+INSERT INTO current_check VALUES
+    (1, 'abc', 'rls_regress_user1'),
+    (2, 'bcd', 'rls_regress_user1'),
+    (3, 'cde', 'rls_regress_user1'),
+    (4, 'def', 'rls_regress_user1'),
+    (5, 'efg', 'rls_regress_user1'),
+    (6, 'fgh', 'rls_regress_user1'),
+    (7, 'fgh', 'rls_regress_user1'),
+    (8, 'fgh', 'rls_regress_user1');
+CREATE POLICY p1 ON current_check FOR SELECT USING (currentid % 2 = 0);
+CREATE POLICY p3 ON current_check FOR UPDATE USING (currentid = 4) WITH CHECK (rlsuser = current_user);
+ALTER TABLE current_check ENABLE ROW LEVEL SECURITY;
+SET SESSION AUTHORIZATION rls_regress_user1;
+-- Can SELECT this row just fine:
+SELECT * FROM current_check WHERE currentid = 2;
+ currentid | payload |      rlsuser      
+-----------+---------+-------------------
+         2 | bcd     | rls_regress_user1
+(1 row)
+
+-- Cannot UPDATE it, though:
+UPDATE current_check SET payload = payload || '_new' WHERE currentid = 2 RETURNING *;
+ currentid | payload | rlsuser 
+-----------+---------+---------
+(0 rows)
+
+BEGIN;
+DECLARE current_check_cursor SCROLL CURSOR FOR SELECT * FROM current_check;
+-- Returns rows that can be seen according to SELECT policy, like plain SELECT
+-- above:
+FETCH ABSOLUTE 1 FROM current_check_cursor;
+ currentid | payload |      rlsuser      
+-----------+---------+-------------------
+         2 | bcd     | rls_regress_user1
+(1 row)
+
+-- Still cannot UPDATE row through cursor:
+UPDATE current_check SET payload = payload || '_new' WHERE CURRENT OF current_check_cursor RETURNING *;
+ currentid | payload | rlsuser 
+-----------+---------+---------
+(0 rows)
+COMMIT;
 --
 -- Clean up objects
 --
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index fdadf99..aeed5b1 100644
--- a/src/test/regress/sql/rowsecurity.sql
+++ b/src/test/regress/sql/rowsecurity.sql
@@ -1087,6 +1087,46 @@ COPY copy_t FROM STDIN; --fail - permission denied.
 RESET SESSION AUTHORIZATION;
 DROP TABLE copy_t;
 
+-- Check WHERE CURRENT OF
+SET SESSION AUTHORIZATION rls_regress_user0;
+
+CREATE TABLE current_check (currentid int, payload text, rlsuser text);
+GRANT ALL ON current_check TO PUBLIC;
+
+INSERT INTO current_check VALUES
+    (1, 'abc', 'rls_regress_user1'),
+    (2, 'bcd', 'rls_regress_user1'),
+    (3, 'cde', 'rls_regress_user1'),
+    (4, 'def', 'rls_regress_user1'),
+    (5, 'efg', 'rls_regress_user1'),
+    (6, 'fgh', 'rls_regress_user1'),
+    (7, 'fgh', 'rls_regress_user1'),
+    (8, 'fgh', 'rls_regress_user1');
+
+CREATE POLICY p1 ON current_check FOR SELECT USING (currentid % 2 = 0);
+CREATE POLICY p3 ON current_check FOR UPDATE USING (currentid = 4) WITH CHECK (rlsuser = current_user);
+
+ALTER TABLE current_check ENABLE ROW LEVEL SECURITY;
+
+SET SESSION AUTHORIZATION rls_regress_user1;
+
+-- Can SELECT this row just fine:
+SELECT * FROM current_check WHERE currentid = 2;
+
+-- Cannot UPDATE it, though:
+UPDATE current_check SET payload = payload || '_new' WHERE currentid = 2 RETURNING *;
+
+BEGIN;
+
+DECLARE current_check_cursor SCROLL CURSOR FOR SELECT * FROM current_check;
+-- Returns rows that can be seen according to SELECT policy, like plain SELECT
+-- above:
+FETCH ABSOLUTE 1 FROM current_check_cursor;
+-- Still cannot UPDATE row through cursor:
+UPDATE current_check SET payload = payload || '_new' WHERE CURRENT OF current_check_cursor RETURNING *;
+
+COMMIT;
+
 --
 -- Clean up objects
 --
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to