Fix incorrect varlevelsup in security_barrier_replace_vars().
authorDean Rasheed <dean.a.rasheed@gmail.com>
Mon, 29 Feb 2016 12:28:06 +0000 (12:28 +0000)
committerDean Rasheed <dean.a.rasheed@gmail.com>
Mon, 29 Feb 2016 12:28:06 +0000 (12:28 +0000)
When converting an RTE with securityQuals into a security barrier
subquery RTE, ensure that the Vars in the new subquery's targetlist
all have varlevelsup = 0 so that they correctly refer to the
underlying base relation being wrapped.

The original code was creating new Vars by copying them from existing
Vars referencing the base relation found elsewhere in the query, but
failed to account for the fact that such Vars could come from sublink
subqueries, and hence have varlevelsup > 0. In practice it looks like
this could only happen with nested security barrier views, where the
outer view has a WHERE clause containing a correlated subquery, due to
the order in which the Vars are processed.

Bug: #13988
Reported-by: Adam Guthrie
Backpatch-to: 9.4, where updatable SB views were introduced
src/backend/optimizer/prep/prepsecurity.c
src/test/regress/expected/updatable_views.out
src/test/regress/sql/updatable_views.sql

index f4e8e4e93c9e12b75bb2b871586a1a01ddf39c47..01eddf0fbf7448336c9fd088ed609b0bca162b1c 100644 (file)
@@ -446,6 +446,7 @@ security_barrier_replace_vars_walker(Node *node,
                        /* New variable for subquery targetlist */
                        newvar = copyObject(var);
                        newvar->varno = newvar->varnoold = 1;
+                       newvar->varlevelsup = 0;
 
                        attno = list_length(context->targetlist) + 1;
                        tle = makeTargetEntry((Expr *) newvar,
index 6c7137155d8933723a0ad1483c12cf86aaaa8c12..c5dfbb5dee8325dabb828d09e1abf7df64d5f4dd 100644 (file)
@@ -2420,3 +2420,42 @@ DROP VIEW vx1;
 DROP TABLE tx1;
 DROP TABLE tx2;
 DROP TABLE tx3;
+--
+-- Test handling of vars from correlated subqueries in quals from outer
+-- security barrier views, per bug #13988
+--
+CREATE TABLE t1 (a int, b text, c int);
+INSERT INTO t1 VALUES (1, 'one', 10);
+CREATE TABLE t2 (cc int);
+INSERT INTO t2 VALUES (10), (20);
+CREATE VIEW v1 WITH (security_barrier = true) AS
+  SELECT * FROM t1 WHERE (a > 0)
+  WITH CHECK OPTION;
+CREATE VIEW v2 WITH (security_barrier = true) AS
+  SELECT * FROM v1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.cc = v1.c)
+  WITH CHECK OPTION;
+INSERT INTO v2 VALUES (2, 'two', 20); -- ok
+INSERT INTO v2 VALUES (-2, 'minus two', 20); -- not allowed
+ERROR:  new row violates check option for view "v1"
+DETAIL:  Failing row contains (-2, minus two, 20).
+INSERT INTO v2 VALUES (3, 'three', 30); -- not allowed
+ERROR:  new row violates check option for view "v2"
+DETAIL:  Failing row contains (3, three, 30).
+UPDATE v2 SET b = 'ONE' WHERE a = 1; -- ok
+UPDATE v2 SET a = -1 WHERE a = 1; -- not allowed
+ERROR:  new row violates check option for view "v1"
+DETAIL:  Failing row contains (-1, ONE, 10).
+UPDATE v2 SET c = 30 WHERE a = 1; -- not allowed
+ERROR:  new row violates check option for view "v2"
+DETAIL:  Failing row contains (1, ONE, 30).
+DELETE FROM v2 WHERE a = 2; -- ok
+SELECT * FROM v2;
+ a |  b  | c  
+---+-----+----
+ 1 | ONE | 10
+(1 row)
+
+DROP VIEW v2;
+DROP VIEW v1;
+DROP TABLE t2;
+DROP TABLE t1;
index 5297a718228a696ed300885faf9af2c2a0f5c6aa..e6674cd8678164f1cd1a03cc01121aa83e632abe 100644 (file)
@@ -1064,3 +1064,37 @@ DROP VIEW vx1;
 DROP TABLE tx1;
 DROP TABLE tx2;
 DROP TABLE tx3;
+
+--
+-- Test handling of vars from correlated subqueries in quals from outer
+-- security barrier views, per bug #13988
+--
+CREATE TABLE t1 (a int, b text, c int);
+INSERT INTO t1 VALUES (1, 'one', 10);
+
+CREATE TABLE t2 (cc int);
+INSERT INTO t2 VALUES (10), (20);
+
+CREATE VIEW v1 WITH (security_barrier = true) AS
+  SELECT * FROM t1 WHERE (a > 0)
+  WITH CHECK OPTION;
+
+CREATE VIEW v2 WITH (security_barrier = true) AS
+  SELECT * FROM v1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.cc = v1.c)
+  WITH CHECK OPTION;
+
+INSERT INTO v2 VALUES (2, 'two', 20); -- ok
+INSERT INTO v2 VALUES (-2, 'minus two', 20); -- not allowed
+INSERT INTO v2 VALUES (3, 'three', 30); -- not allowed
+
+UPDATE v2 SET b = 'ONE' WHERE a = 1; -- ok
+UPDATE v2 SET a = -1 WHERE a = 1; -- not allowed
+UPDATE v2 SET c = 30 WHERE a = 1; -- not allowed
+
+DELETE FROM v2 WHERE a = 2; -- ok
+SELECT * FROM v2;
+
+DROP VIEW v2;
+DROP VIEW v1;
+DROP TABLE t2;
+DROP TABLE t1;