-- This file and its contents are licensed under the Apache License 2.0.
-- Please see the included NOTICE for copyright information and
-- LICENSE-APACHE for a copy of the license.
--
-- Test of Row-level security feature
--
-- Clean up in case a prior regression run failed
\c :TEST_DBNAME :ROLE_SUPERUSER
\set ON_ERROR_STOP 0
\set VERBOSITY default
SET timescaledb.enable_constraint_exclusion TO off;
-- Suppress NOTICE messages when users/groups don't exist
SET client_min_messages TO 'warning';
DROP USER IF EXISTS regress_rls_alice;
DROP USER IF EXISTS regress_rls_bob;
DROP USER IF EXISTS regress_rls_carol;
DROP USER IF EXISTS regress_rls_dave;
DROP USER IF EXISTS regress_rls_exempt_user;
DROP ROLE IF EXISTS regress_rls_group1;
DROP ROLE IF EXISTS regress_rls_group2;
DROP SCHEMA IF EXISTS regress_rls_schema CASCADE;
RESET client_min_messages;
-- initial setup
CREATE USER regress_rls_alice NOLOGIN;
CREATE USER regress_rls_bob NOLOGIN;
CREATE USER regress_rls_carol NOLOGIN;
CREATE USER regress_rls_dave NOLOGIN;
CREATE USER regress_rls_exempt_user BYPASSRLS NOLOGIN;
CREATE ROLE regress_rls_group1 NOLOGIN;
CREATE ROLE regress_rls_group2 NOLOGIN;
GRANT regress_rls_group1 TO regress_rls_bob;
GRANT regress_rls_group2 TO regress_rls_carol;
CREATE SCHEMA regress_rls_schema;
GRANT ALL ON SCHEMA regress_rls_schema to public;
SET search_path = regress_rls_schema;
-- setup of malicious function
CREATE OR REPLACE FUNCTION f_leak(text) RETURNS bool
    COST 0.0000001 LANGUAGE plpgsql
    AS 'BEGIN RAISE NOTICE ''f_leak => %'', $1; RETURN true; END';
GRANT EXECUTE ON FUNCTION f_leak(text) TO public;
-- BASIC Row-Level Security Scenario
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE uaccount (
    pguser      name primary key,
    seclv       int
);
GRANT SELECT ON uaccount TO public;
INSERT INTO uaccount VALUES
    ('regress_rls_alice', 99),
    ('regress_rls_bob', 1),
    ('regress_rls_carol', 2),
    ('regress_rls_dave', 3);
CREATE TABLE category (
    cid        int primary key,
    cname      text
);
GRANT ALL ON category TO public;
INSERT INTO category VALUES
    (11, 'novel'),
    (22, 'science fiction'),
    (33, 'technology'),
    (44, 'manga');
CREATE TABLE document (
    did         int primary key,
    cid         int references category(cid),
    dlevel      int not null,
    dauthor     name,
    dtitle      text
);
GRANT ALL ON document TO public;
SELECT public.create_hypertable('document', 'did', chunk_time_interval=>2);
         create_hypertable         
-----------------------------------
 (1,regress_rls_schema,document,t)

INSERT INTO document VALUES
    ( 1, 11, 1, 'regress_rls_bob', 'my first novel'),
    ( 2, 11, 2, 'regress_rls_bob', 'my second novel'),
    ( 3, 22, 2, 'regress_rls_bob', 'my science fiction'),
    ( 4, 44, 1, 'regress_rls_bob', 'my first manga'),
    ( 5, 44, 2, 'regress_rls_bob', 'my second manga'),
    ( 6, 22, 1, 'regress_rls_carol', 'great science fiction'),
    ( 7, 33, 2, 'regress_rls_carol', 'great technology book'),
    ( 8, 44, 1, 'regress_rls_carol', 'great manga'),
    ( 9, 22, 1, 'regress_rls_dave', 'awesome science fiction'),
    (10, 33, 2, 'regress_rls_dave', 'awesome technology book');
ALTER TABLE document ENABLE ROW LEVEL SECURITY;
-- user's security level must be higher than or equal to document's
CREATE POLICY p1 ON document AS PERMISSIVE
    USING (dlevel <= (SELECT seclv FROM uaccount WHERE pguser = current_user));
-- try to create a policy of bogus type
CREATE POLICY p1 ON document AS UGLY
    USING (dlevel <= (SELECT seclv FROM uaccount WHERE pguser = current_user));
ERROR:  unrecognized row security option "ugly"
LINE 1: CREATE POLICY p1 ON document AS UGLY
                                        ^
HINT:  Only PERMISSIVE or RESTRICTIVE policies are supported currently.
-- but Dave isn't allowed to anything at cid 50 or above
-- this is to make sure that we sort the policies by name first
-- when applying WITH CHECK, a later INSERT by Dave should fail due
-- to p1r first
CREATE POLICY p2r ON document AS RESTRICTIVE TO regress_rls_dave
    USING (cid <> 44 AND cid < 50);
-- and Dave isn't allowed to see manga documents
CREATE POLICY p1r ON document AS RESTRICTIVE TO regress_rls_dave
    USING (cid <> 44);
\dp
                                                                  Access privileges
       Schema       |   Name   | Type  |              Access privileges              | Column privileges |                  Policies                  
--------------------+----------+-------+---------------------------------------------+-------------------+--------------------------------------------
 regress_rls_schema | category | table | regress_rls_alice=arwdDxt/regress_rls_alice+|                   | 
                    |          |       | =arwdDxt/regress_rls_alice                  |                   | 
 regress_rls_schema | document | table | regress_rls_alice=arwdDxt/regress_rls_alice+|                   | p1:                                       +
                    |          |       | =arwdDxt/regress_rls_alice                  |                   |   (u): (dlevel <= ( SELECT uaccount.seclv +
                    |          |       |                                             |                   |    FROM uaccount                          +
                    |          |       |                                             |                   |   WHERE (uaccount.pguser = CURRENT_USER)))+
                    |          |       |                                             |                   | p2r (RESTRICTIVE):                        +
                    |          |       |                                             |                   |   (u): ((cid <> 44) AND (cid < 50))       +
                    |          |       |                                             |                   |   to: regress_rls_dave                    +
                    |          |       |                                             |                   | p1r (RESTRICTIVE):                        +
                    |          |       |                                             |                   |   (u): (cid <> 44)                        +
                    |          |       |                                             |                   |   to: regress_rls_dave
 regress_rls_schema | uaccount | table | regress_rls_alice=arwdDxt/regress_rls_alice+|                   | 
                    |          |       | =r/regress_rls_alice                        |                   | 

\d document
        Table "regress_rls_schema.document"
 Column  |  Type   | Collation | Nullable | Default 
---------+---------+-----------+----------+---------
 did     | integer |           | not null | 
 cid     | integer |           |          | 
 dlevel  | integer |           | not null | 
 dauthor | name    |           |          | 
 dtitle  | text    |           |          | 
Indexes:
    "document_pkey" PRIMARY KEY, btree (did)
Foreign-key constraints:
    "document_cid_fkey" FOREIGN KEY (cid) REFERENCES category(cid)
Policies:
    POLICY "p1"
      USING ((dlevel <= ( SELECT uaccount.seclv
   FROM uaccount
  WHERE (uaccount.pguser = CURRENT_USER))))
    POLICY "p1r" AS RESTRICTIVE
      TO regress_rls_dave
      USING ((cid <> 44))
    POLICY "p2r" AS RESTRICTIVE
      TO regress_rls_dave
      USING (((cid <> 44) AND (cid < 50)))
Number of child tables: 6 (Use \d+ to list them.)

SELECT * FROM pg_policies WHERE schemaname = 'regress_rls_schema' AND tablename = 'document' ORDER BY policyname;
     schemaname     | tablename | policyname | permissive  |       roles        | cmd |                    qual                    | with_check 
--------------------+-----------+------------+-------------+--------------------+-----+--------------------------------------------+------------
 regress_rls_schema | document  | p1         | PERMISSIVE  | {public}           | ALL | (dlevel <= ( SELECT uaccount.seclv        +| 
                    |           |            |             |                    |     |    FROM uaccount                          +| 
                    |           |            |             |                    |     |   WHERE (uaccount.pguser = CURRENT_USER))) | 
 regress_rls_schema | document  | p1r        | RESTRICTIVE | {regress_rls_dave} | ALL | (cid <> 44)                                | 
 regress_rls_schema | document  | p2r        | RESTRICTIVE | {regress_rls_dave} | ALL | ((cid <> 44) AND (cid < 50))               | 

-- viewpoint from regress_rls_bob
SET SESSION AUTHORIZATION regress_rls_bob;
SET row_security TO ON;
SELECT * FROM document WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my first manga
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great manga
NOTICE:  f_leak => awesome science fiction
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   4 |  44 |      1 | regress_rls_bob   | my first manga
   6 |  22 |      1 | regress_rls_carol | great science fiction
   8 |  44 |      1 | regress_rls_carol | great manga
   9 |  22 |      1 | regress_rls_dave  | awesome science fiction

SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my first manga
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great manga
NOTICE:  f_leak => awesome science fiction
 cid | did | dlevel |      dauthor      |         dtitle          |      cname      
-----+-----+--------+-------------------+-------------------------+-----------------
  11 |   1 |      1 | regress_rls_bob   | my first novel          | novel
  44 |   4 |      1 | regress_rls_bob   | my first manga          | manga
  22 |   6 |      1 | regress_rls_carol | great science fiction   | science fiction
  44 |   8 |      1 | regress_rls_carol | great manga             | manga
  22 |   9 |      1 | regress_rls_dave  | awesome science fiction | science fiction

-- try a sampled version
SELECT * FROM document TABLESAMPLE BERNOULLI(50) REPEATABLE(0)
  WHERE f_leak(dtitle) ORDER BY did;
 did | cid | dlevel | dauthor | dtitle 
-----+-----+--------+---------+--------

-- viewpoint from regress_rls_carol
SET SESSION AUTHORIZATION regress_rls_carol;
SELECT * FROM document WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => my science fiction
NOTICE:  f_leak => my first manga
NOTICE:  f_leak => my second manga
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great technology book
NOTICE:  f_leak => great manga
NOTICE:  f_leak => awesome science fiction
NOTICE:  f_leak => awesome technology book
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  22 |      2 | regress_rls_bob   | my science fiction
   4 |  44 |      1 | regress_rls_bob   | my first manga
   5 |  44 |      2 | regress_rls_bob   | my second manga
   6 |  22 |      1 | regress_rls_carol | great science fiction
   7 |  33 |      2 | regress_rls_carol | great technology book
   8 |  44 |      1 | regress_rls_carol | great manga
   9 |  22 |      1 | regress_rls_dave  | awesome science fiction
  10 |  33 |      2 | regress_rls_dave  | awesome technology book

SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => my science fiction
NOTICE:  f_leak => my first manga
NOTICE:  f_leak => my second manga
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great technology book
NOTICE:  f_leak => great manga
NOTICE:  f_leak => awesome science fiction
NOTICE:  f_leak => awesome technology book
 cid | did | dlevel |      dauthor      |         dtitle          |      cname      
-----+-----+--------+-------------------+-------------------------+-----------------
  11 |   1 |      1 | regress_rls_bob   | my first novel          | novel
  11 |   2 |      2 | regress_rls_bob   | my second novel         | novel
  22 |   3 |      2 | regress_rls_bob   | my science fiction      | science fiction
  44 |   4 |      1 | regress_rls_bob   | my first manga          | manga
  44 |   5 |      2 | regress_rls_bob   | my second manga         | manga
  22 |   6 |      1 | regress_rls_carol | great science fiction   | science fiction
  33 |   7 |      2 | regress_rls_carol | great technology book   | technology
  44 |   8 |      1 | regress_rls_carol | great manga             | manga
  22 |   9 |      1 | regress_rls_dave  | awesome science fiction | science fiction
  33 |  10 |      2 | regress_rls_dave  | awesome technology book | technology

-- try a sampled version
SELECT * FROM document TABLESAMPLE BERNOULLI(50) REPEATABLE(0)
  WHERE f_leak(dtitle) ORDER BY did;
 did | cid | dlevel | dauthor | dtitle 
-----+-----+--------+---------+--------

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on document
   Chunks excluded during startup: 0
   InitPlan 1 (returns $0)
     ->  Index Scan using uaccount_pkey on uaccount
           Index Cond: (pguser = CURRENT_USER)
   ->  Seq Scan on document document_1
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_1_chunk document_2
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_2_chunk document_3
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_3_chunk document_4
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_4_chunk document_5
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_5_chunk document_6
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_6_chunk document_7
         Filter: ((dlevel <= $0) AND f_leak(dtitle))

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Hash Join
   Hash Cond: (document.cid = category.cid)
   InitPlan 1 (returns $0)
     ->  Index Scan using uaccount_pkey on uaccount
           Index Cond: (pguser = CURRENT_USER)
   ->  Custom Scan (ChunkAppend) on document
         Chunks excluded during startup: 0
         ->  Seq Scan on document document_1
               Filter: ((dlevel <= $0) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_1_chunk document_2
               Filter: ((dlevel <= $0) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_2_chunk document_3
               Filter: ((dlevel <= $0) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_3_chunk document_4
               Filter: ((dlevel <= $0) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_4_chunk document_5
               Filter: ((dlevel <= $0) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_5_chunk document_6
               Filter: ((dlevel <= $0) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_6_chunk document_7
               Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Hash
         ->  Seq Scan on category

-- viewpoint from regress_rls_dave
SET SESSION AUTHORIZATION regress_rls_dave;
SELECT * FROM document WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => my science fiction
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great technology book
NOTICE:  f_leak => awesome science fiction
NOTICE:  f_leak => awesome technology book
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  22 |      2 | regress_rls_bob   | my science fiction
   6 |  22 |      1 | regress_rls_carol | great science fiction
   7 |  33 |      2 | regress_rls_carol | great technology book
   9 |  22 |      1 | regress_rls_dave  | awesome science fiction
  10 |  33 |      2 | regress_rls_dave  | awesome technology book

SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => my science fiction
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great technology book
NOTICE:  f_leak => awesome science fiction
NOTICE:  f_leak => awesome technology book
 cid | did | dlevel |      dauthor      |         dtitle          |      cname      
-----+-----+--------+-------------------+-------------------------+-----------------
  11 |   1 |      1 | regress_rls_bob   | my first novel          | novel
  11 |   2 |      2 | regress_rls_bob   | my second novel         | novel
  22 |   3 |      2 | regress_rls_bob   | my science fiction      | science fiction
  22 |   6 |      1 | regress_rls_carol | great science fiction   | science fiction
  33 |   7 |      2 | regress_rls_carol | great technology book   | technology
  22 |   9 |      1 | regress_rls_dave  | awesome science fiction | science fiction
  33 |  10 |      2 | regress_rls_dave  | awesome technology book | technology

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on document
   Chunks excluded during startup: 0
   InitPlan 1 (returns $0)
     ->  Index Scan using uaccount_pkey on uaccount
           Index Cond: (pguser = CURRENT_USER)
   ->  Seq Scan on document document_1
         Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_1_chunk document_2
         Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_2_chunk document_3
         Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_3_chunk document_4
         Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_4_chunk document_5
         Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_5_chunk document_6
         Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_6_chunk document_7
         Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Hash Join
   Hash Cond: (category.cid = document.cid)
   InitPlan 1 (returns $0)
     ->  Index Scan using uaccount_pkey on uaccount
           Index Cond: (pguser = CURRENT_USER)
   ->  Seq Scan on category
   ->  Hash
         ->  Custom Scan (ChunkAppend) on document
               Chunks excluded during startup: 0
               ->  Seq Scan on document document_1
                     Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
               ->  Seq Scan on _hyper_1_1_chunk document_2
                     Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
               ->  Seq Scan on _hyper_1_2_chunk document_3
                     Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
               ->  Seq Scan on _hyper_1_3_chunk document_4
                     Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
               ->  Seq Scan on _hyper_1_4_chunk document_5
                     Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
               ->  Seq Scan on _hyper_1_5_chunk document_6
                     Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))
               ->  Seq Scan on _hyper_1_6_chunk document_7
                     Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle))

-- 44 would technically fail for both p2r and p1r, but we should get an error
-- back from p1r for this because it sorts first
INSERT INTO document VALUES (100, 44, 1, 'regress_rls_dave', 'testing sorting of policies'); -- fail
ERROR:  new row violates row-level security policy "p1r" for table "document"
-- Just to see a p2r error
INSERT INTO document VALUES (100, 55, 1, 'regress_rls_dave', 'testing sorting of policies'); -- fail
ERROR:  new row violates row-level security policy "p2r" for table "document"
-- only owner can change policies
ALTER POLICY p1 ON document USING (true);    --fail
ERROR:  must be owner of table document
DROP POLICY p1 ON document;                  --fail
ERROR:  must be owner of relation document
SET SESSION AUTHORIZATION regress_rls_alice;
ALTER POLICY p1 ON document USING (dauthor = current_user);
-- viewpoint from regress_rls_bob again
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM document WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => my science fiction
NOTICE:  f_leak => my first manga
NOTICE:  f_leak => my second manga
 did | cid | dlevel |     dauthor     |       dtitle       
-----+-----+--------+-----------------+--------------------
   1 |  11 |      1 | regress_rls_bob | my first novel
   2 |  11 |      2 | regress_rls_bob | my second novel
   3 |  22 |      2 | regress_rls_bob | my science fiction
   4 |  44 |      1 | regress_rls_bob | my first manga
   5 |  44 |      2 | regress_rls_bob | my second manga

SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER by did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => my science fiction
NOTICE:  f_leak => my first manga
NOTICE:  f_leak => my second manga
 cid | did | dlevel |     dauthor     |       dtitle       |      cname      
-----+-----+--------+-----------------+--------------------+-----------------
  11 |   1 |      1 | regress_rls_bob | my first novel     | novel
  11 |   2 |      2 | regress_rls_bob | my second novel    | novel
  22 |   3 |      2 | regress_rls_bob | my science fiction | science fiction
  44 |   4 |      1 | regress_rls_bob | my first manga     | manga
  44 |   5 |      2 | regress_rls_bob | my second manga    | manga

-- viewpoint from rls_regres_carol again
SET SESSION AUTHORIZATION regress_rls_carol;
SELECT * FROM document WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great technology book
NOTICE:  f_leak => great manga
 did | cid | dlevel |      dauthor      |        dtitle         
-----+-----+--------+-------------------+-----------------------
   6 |  22 |      1 | regress_rls_carol | great science fiction
   7 |  33 |      2 | regress_rls_carol | great technology book
   8 |  44 |      1 | regress_rls_carol | great manga

SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER by did;
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great technology book
NOTICE:  f_leak => great manga
 cid | did | dlevel |      dauthor      |        dtitle         |      cname      
-----+-----+--------+-------------------+-----------------------+-----------------
  22 |   6 |      1 | regress_rls_carol | great science fiction | science fiction
  33 |   7 |      2 | regress_rls_carol | great technology book | technology
  44 |   8 |      1 | regress_rls_carol | great manga           | manga

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on document
   Chunks excluded during startup: 0
   ->  Seq Scan on document document_1
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_1_chunk document_2
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_2_chunk document_3
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_3_chunk document_4
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_4_chunk document_5
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_5_chunk document_6
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_1_6_chunk document_7
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Nested Loop
   ->  Custom Scan (ChunkAppend) on document
         Chunks excluded during startup: 0
         ->  Seq Scan on document document_1
               Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_1_chunk document_2
               Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_2_chunk document_3
               Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_3_chunk document_4
               Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_4_chunk document_5
               Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_5_chunk document_6
               Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
         ->  Seq Scan on _hyper_1_6_chunk document_7
               Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Index Scan using category_pkey on category
         Index Cond: (cid = document.cid)

-- interaction of FK/PK constraints
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE POLICY p2 ON category
    USING (CASE WHEN current_user = 'regress_rls_bob' THEN cid IN (11, 33)
           WHEN current_user = 'regress_rls_carol' THEN cid IN (22, 44)
           ELSE false END);
ALTER TABLE category ENABLE ROW LEVEL SECURITY;
-- cannot delete PK referenced by invisible FK
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM document d FULL OUTER JOIN category c on d.cid = c.cid ORDER BY d.did, c.cid;
 did | cid | dlevel |     dauthor     |       dtitle       | cid |   cname    
-----+-----+--------+-----------------+--------------------+-----+------------
   1 |  11 |      1 | regress_rls_bob | my first novel     |  11 | novel
   2 |  11 |      2 | regress_rls_bob | my second novel    |  11 | novel
   3 |  22 |      2 | regress_rls_bob | my science fiction |     | 
   4 |  44 |      1 | regress_rls_bob | my first manga     |     | 
   5 |  44 |      2 | regress_rls_bob | my second manga    |     | 
     |     |        |                 |                    |  33 | technology

\set VERBOSITY sqlstate
DELETE FROM category WHERE cid = 33;    -- fails with FK violation
ERROR:  23503
\set VERBOSITY default
-- can insert FK referencing invisible PK
SET SESSION AUTHORIZATION regress_rls_carol;
SELECT * FROM document d FULL OUTER JOIN category c on d.cid = c.cid ORDER BY d.did, c.cid;
 did | cid | dlevel |      dauthor      |        dtitle         | cid |      cname      
-----+-----+--------+-------------------+-----------------------+-----+-----------------
   6 |  22 |      1 | regress_rls_carol | great science fiction |  22 | science fiction
   7 |  33 |      2 | regress_rls_carol | great technology book |     | 
   8 |  44 |      1 | regress_rls_carol | great manga           |  44 | manga

INSERT INTO document VALUES (11, 33, 1, current_user, 'hoge');
-- UNIQUE or PRIMARY KEY constraint violation DOES reveal presence of row
SET SESSION AUTHORIZATION regress_rls_bob;
INSERT INTO document VALUES (8, 44, 1, 'regress_rls_bob', 'my third manga'); -- Must fail with unique violation, revealing presence of did we can't see
ERROR:  duplicate key value violates unique constraint "5_10_document_pkey"
DETAIL:  Key (did)=(8) already exists.
SELECT * FROM document WHERE did = 8; -- and confirm we can't see it
 did | cid | dlevel | dauthor | dtitle 
-----+-----+--------+---------+--------

-- RLS policies are checked before constraints
INSERT INTO document VALUES (8, 44, 1, 'regress_rls_carol', 'my third manga'); -- Should fail with RLS check violation, not duplicate key violation
ERROR:  new row violates row-level security policy for table "document"
UPDATE document SET did = 8, dauthor = 'regress_rls_carol' WHERE did = 5; -- Should fail with RLS check violation, not duplicate key violation
ERROR:  new row violates row-level security policy for table "document"
-- database superuser does bypass RLS policy when enabled
RESET SESSION AUTHORIZATION;
SET row_security TO ON;
SELECT * FROM document;
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  22 |      2 | regress_rls_bob   | my science fiction
   4 |  44 |      1 | regress_rls_bob   | my first manga
   5 |  44 |      2 | regress_rls_bob   | my second manga
   6 |  22 |      1 | regress_rls_carol | great science fiction
   7 |  33 |      2 | regress_rls_carol | great technology book
   8 |  44 |      1 | regress_rls_carol | great manga
   9 |  22 |      1 | regress_rls_dave  | awesome science fiction
  10 |  33 |      2 | regress_rls_dave  | awesome technology book
  11 |  33 |      1 | regress_rls_carol | hoge

SELECT * FROM category;
 cid |      cname      
-----+-----------------
  11 | novel
  22 | science fiction
  33 | technology
  44 | manga

-- database superuser does bypass RLS policy when disabled
RESET SESSION AUTHORIZATION;
SET row_security TO OFF;
SELECT * FROM document;
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  22 |      2 | regress_rls_bob   | my science fiction
   4 |  44 |      1 | regress_rls_bob   | my first manga
   5 |  44 |      2 | regress_rls_bob   | my second manga
   6 |  22 |      1 | regress_rls_carol | great science fiction
   7 |  33 |      2 | regress_rls_carol | great technology book
   8 |  44 |      1 | regress_rls_carol | great manga
   9 |  22 |      1 | regress_rls_dave  | awesome science fiction
  10 |  33 |      2 | regress_rls_dave  | awesome technology book
  11 |  33 |      1 | regress_rls_carol | hoge

SELECT * FROM category;
 cid |      cname      
-----+-----------------
  11 | novel
  22 | science fiction
  33 | technology
  44 | manga

-- database non-superuser with bypass privilege can bypass RLS policy when disabled
SET SESSION AUTHORIZATION regress_rls_exempt_user;
SET row_security TO OFF;
SELECT * FROM document;
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  22 |      2 | regress_rls_bob   | my science fiction
   4 |  44 |      1 | regress_rls_bob   | my first manga
   5 |  44 |      2 | regress_rls_bob   | my second manga
   6 |  22 |      1 | regress_rls_carol | great science fiction
   7 |  33 |      2 | regress_rls_carol | great technology book
   8 |  44 |      1 | regress_rls_carol | great manga
   9 |  22 |      1 | regress_rls_dave  | awesome science fiction
  10 |  33 |      2 | regress_rls_dave  | awesome technology book
  11 |  33 |      1 | regress_rls_carol | hoge

SELECT * FROM category;
 cid |      cname      
-----+-----------------
  11 | novel
  22 | science fiction
  33 | technology
  44 | manga

-- RLS policy does not apply to table owner when RLS enabled.
SET SESSION AUTHORIZATION regress_rls_alice;
SET row_security TO ON;
SELECT * FROM document;
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  22 |      2 | regress_rls_bob   | my science fiction
   4 |  44 |      1 | regress_rls_bob   | my first manga
   5 |  44 |      2 | regress_rls_bob   | my second manga
   6 |  22 |      1 | regress_rls_carol | great science fiction
   7 |  33 |      2 | regress_rls_carol | great technology book
   8 |  44 |      1 | regress_rls_carol | great manga
   9 |  22 |      1 | regress_rls_dave  | awesome science fiction
  10 |  33 |      2 | regress_rls_dave  | awesome technology book
  11 |  33 |      1 | regress_rls_carol | hoge

SELECT * FROM category;
 cid |      cname      
-----+-----------------
  11 | novel
  22 | science fiction
  33 | technology
  44 | manga

-- RLS policy does not apply to table owner when RLS disabled.
SET SESSION AUTHORIZATION regress_rls_alice;
SET row_security TO OFF;
SELECT * FROM document;
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  22 |      2 | regress_rls_bob   | my science fiction
   4 |  44 |      1 | regress_rls_bob   | my first manga
   5 |  44 |      2 | regress_rls_bob   | my second manga
   6 |  22 |      1 | regress_rls_carol | great science fiction
   7 |  33 |      2 | regress_rls_carol | great technology book
   8 |  44 |      1 | regress_rls_carol | great manga
   9 |  22 |      1 | regress_rls_dave  | awesome science fiction
  10 |  33 |      2 | regress_rls_dave  | awesome technology book
  11 |  33 |      1 | regress_rls_carol | hoge

SELECT * FROM category;
 cid |      cname      
-----+-----------------
  11 | novel
  22 | science fiction
  33 | technology
  44 | manga

--
-- Table inheritance and RLS policy
--
SET SESSION AUTHORIZATION regress_rls_alice;
SET row_security TO ON;
CREATE TABLE t1 (a int, junk1 text, b text);
ALTER TABLE t1 DROP COLUMN junk1;    -- just a disturbing factor
GRANT ALL ON t1 TO public;
COPY t1 FROM stdin;
CREATE TABLE t2 (c float) INHERITS (t1);
GRANT ALL ON t2 TO public;
COPY t2 FROM stdin;
CREATE TABLE t3 (c text, b text, a int);
ALTER TABLE t3 INHERIT t1;
GRANT ALL ON t3 TO public;
COPY t3(a,b,c) FROM stdin;
CREATE POLICY p1 ON t1 FOR ALL TO PUBLIC USING (a % 2 = 0); -- be even number
CREATE POLICY p2 ON t2 FOR ALL TO PUBLIC USING (a % 2 = 1); -- be odd number
ALTER TABLE t1 ENABLE ROW LEVEL SECURITY;
ALTER TABLE t2 ENABLE ROW LEVEL SECURITY;
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM t1;
 a |  b  
---+-----
 2 | bbb
 4 | dad
 2 | bcd
 4 | def
 2 | yyy

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1;
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: ((a % 2) = 0)
   ->  Seq Scan on t2 t1_2
         Filter: ((a % 2) = 0)
   ->  Seq Scan on t3 t1_3
         Filter: ((a % 2) = 0)

SELECT * FROM t1 WHERE f_leak(b);
NOTICE:  f_leak => bbb
NOTICE:  f_leak => dad
NOTICE:  f_leak => bcd
NOTICE:  f_leak => def
NOTICE:  f_leak => yyy
 a |  b  
---+-----
 2 | bbb
 4 | dad
 2 | bcd
 4 | def
 2 | yyy

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on t2 t1_2
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on t3 t1_3
         Filter: (((a % 2) = 0) AND f_leak(b))

-- reference to system column
SELECT ctid, * FROM t1;
 ctid  | a |  b  
-------+---+-----
 (0,2) | 2 | bbb
 (0,4) | 4 | dad
 (0,2) | 2 | bcd
 (0,4) | 4 | def
 (0,2) | 2 | yyy

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT *, t1 FROM t1;
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: ((a % 2) = 0)
   ->  Seq Scan on t2 t1_2
         Filter: ((a % 2) = 0)
   ->  Seq Scan on t3 t1_3
         Filter: ((a % 2) = 0)

-- reference to whole-row reference
SELECT *, t1 FROM t1;
 a |  b  |   t1    
---+-----+---------
 2 | bbb | (2,bbb)
 4 | dad | (4,dad)
 2 | bcd | (2,bcd)
 4 | def | (4,def)
 2 | yyy | (2,yyy)

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT *, t1 FROM t1;
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: ((a % 2) = 0)
   ->  Seq Scan on t2 t1_2
         Filter: ((a % 2) = 0)
   ->  Seq Scan on t3 t1_3
         Filter: ((a % 2) = 0)

-- for share/update lock
SELECT * FROM t1 FOR SHARE;
 a |  b  
---+-----
 2 | bbb
 4 | dad
 2 | bcd
 4 | def
 2 | yyy

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1 FOR SHARE;
--- QUERY PLAN ---
 LockRows
   ->  Append
         ->  Seq Scan on t1 t1_1
               Filter: ((a % 2) = 0)
         ->  Seq Scan on t2 t1_2
               Filter: ((a % 2) = 0)
         ->  Seq Scan on t3 t1_3
               Filter: ((a % 2) = 0)

SELECT * FROM t1 WHERE f_leak(b) FOR SHARE;
NOTICE:  f_leak => bbb
NOTICE:  f_leak => dad
NOTICE:  f_leak => bcd
NOTICE:  f_leak => def
NOTICE:  f_leak => yyy
 a |  b  
---+-----
 2 | bbb
 4 | dad
 2 | bcd
 4 | def
 2 | yyy

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1 WHERE f_leak(b) FOR SHARE;
--- QUERY PLAN ---
 LockRows
   ->  Append
         ->  Seq Scan on t1 t1_1
               Filter: (((a % 2) = 0) AND f_leak(b))
         ->  Seq Scan on t2 t1_2
               Filter: (((a % 2) = 0) AND f_leak(b))
         ->  Seq Scan on t3 t1_3
               Filter: (((a % 2) = 0) AND f_leak(b))

-- union all query
SELECT a, b, ctid FROM t2 UNION ALL SELECT a, b, ctid FROM t3;
 a |  b  | ctid  
---+-----+-------
 1 | abc | (0,1)
 3 | cde | (0,3)
 1 | xxx | (0,1)
 2 | yyy | (0,2)
 3 | zzz | (0,3)

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT a, b, ctid FROM t2 UNION ALL SELECT a, b, ctid FROM t3;
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t2
         Filter: ((a % 2) = 1)
   ->  Seq Scan on t3

-- superuser is allowed to bypass RLS checks
RESET SESSION AUTHORIZATION;
SET row_security TO OFF;
SELECT * FROM t1 WHERE f_leak(b);
NOTICE:  f_leak => aba
NOTICE:  f_leak => bbb
NOTICE:  f_leak => ccc
NOTICE:  f_leak => dad
NOTICE:  f_leak => abc
NOTICE:  f_leak => bcd
NOTICE:  f_leak => cde
NOTICE:  f_leak => def
NOTICE:  f_leak => xxx
NOTICE:  f_leak => yyy
NOTICE:  f_leak => zzz
 a |  b  
---+-----
 1 | aba
 2 | bbb
 3 | ccc
 4 | dad
 1 | abc
 2 | bcd
 3 | cde
 4 | def
 1 | xxx
 2 | yyy
 3 | zzz

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: f_leak(b)
   ->  Seq Scan on t2 t1_2
         Filter: f_leak(b)
   ->  Seq Scan on t3 t1_3
         Filter: f_leak(b)

-- non-superuser with bypass privilege can bypass RLS policy when disabled
SET SESSION AUTHORIZATION regress_rls_exempt_user;
SET row_security TO OFF;
SELECT * FROM t1 WHERE f_leak(b);
NOTICE:  f_leak => aba
NOTICE:  f_leak => bbb
NOTICE:  f_leak => ccc
NOTICE:  f_leak => dad
NOTICE:  f_leak => abc
NOTICE:  f_leak => bcd
NOTICE:  f_leak => cde
NOTICE:  f_leak => def
NOTICE:  f_leak => xxx
NOTICE:  f_leak => yyy
NOTICE:  f_leak => zzz
 a |  b  
---+-----
 1 | aba
 2 | bbb
 3 | ccc
 4 | dad
 1 | abc
 2 | bcd
 3 | cde
 4 | def
 1 | xxx
 2 | yyy
 3 | zzz

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: f_leak(b)
   ->  Seq Scan on t2 t1_2
         Filter: f_leak(b)
   ->  Seq Scan on t3 t1_3
         Filter: f_leak(b)

--
-- Hyper Tables
--
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE hyper_document (
    did         int,
    cid         int,
    dlevel      int not null,
    dauthor     name,
    dtitle      text
);
GRANT ALL ON hyper_document TO public;
SELECT public.create_hypertable('hyper_document', 'did', chunk_time_interval=>2);
            create_hypertable            
-----------------------------------------
 (2,regress_rls_schema,hyper_document,t)

INSERT INTO hyper_document VALUES
    ( 1, 11, 1, 'regress_rls_bob', 'my first novel'),
    ( 2, 11, 2, 'regress_rls_bob', 'my second novel'),
    ( 3, 99, 2, 'regress_rls_bob', 'my science textbook'),
    ( 4, 55, 1, 'regress_rls_bob', 'my first satire'),
    ( 5, 99, 2, 'regress_rls_bob', 'my history book'),
    ( 6, 11, 1, 'regress_rls_carol', 'great science fiction'),
    ( 7, 99, 2, 'regress_rls_carol', 'great technology book'),
    ( 8, 55, 2, 'regress_rls_carol', 'great satire'),
    ( 9, 11, 1, 'regress_rls_dave', 'awesome science fiction'),
    (10, 99, 2, 'regress_rls_dave', 'awesome technology book');
ALTER TABLE hyper_document ENABLE ROW LEVEL SECURITY;
GRANT ALL ON _timescaledb_internal._hyper_2_9_chunk TO public;
-- Create policy on parent
-- user's security level must be higher than or equal to document's
CREATE POLICY pp1 ON hyper_document AS PERMISSIVE
    USING (dlevel <= (SELECT seclv FROM uaccount WHERE pguser = current_user));
-- Dave is only allowed to see cid < 55
CREATE POLICY pp1r ON hyper_document AS RESTRICTIVE TO regress_rls_dave
    USING (cid < 55);
\d+ hyper_document
                         Table "regress_rls_schema.hyper_document"
 Column  |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
---------+---------+-----------+----------+---------+----------+--------------+-------------
 did     | integer |           | not null |         | plain    |              | 
 cid     | integer |           |          |         | plain    |              | 
 dlevel  | integer |           | not null |         | plain    |              | 
 dauthor | name    |           |          |         | plain    |              | 
 dtitle  | text    |           |          |         | extended |              | 
Indexes:
    "hyper_document_did_idx" btree (did DESC)
Policies:
    POLICY "pp1"
      USING ((dlevel <= ( SELECT uaccount.seclv
   FROM uaccount
  WHERE (uaccount.pguser = CURRENT_USER))))
    POLICY "pp1r" AS RESTRICTIVE
      TO regress_rls_dave
      USING ((cid < 55))
Child tables: _timescaledb_internal._hyper_2_10_chunk,
              _timescaledb_internal._hyper_2_11_chunk,
              _timescaledb_internal._hyper_2_12_chunk,
              _timescaledb_internal._hyper_2_13_chunk,
              _timescaledb_internal._hyper_2_14_chunk,
              _timescaledb_internal._hyper_2_9_chunk

SELECT * FROM pg_policies WHERE schemaname = 'regress_rls_schema' AND tablename like '%hyper_document%' ORDER BY policyname;
     schemaname     |   tablename    | policyname | permissive  |       roles        | cmd |                    qual                    | with_check 
--------------------+----------------+------------+-------------+--------------------+-----+--------------------------------------------+------------
 regress_rls_schema | hyper_document | pp1        | PERMISSIVE  | {public}           | ALL | (dlevel <= ( SELECT uaccount.seclv        +| 
                    |                |            |             |                    |     |    FROM uaccount                          +| 
                    |                |            |             |                    |     |   WHERE (uaccount.pguser = CURRENT_USER))) | 
 regress_rls_schema | hyper_document | pp1r       | RESTRICTIVE | {regress_rls_dave} | ALL | (cid < 55)                                 | 

-- viewpoint from regress_rls_bob
SET SESSION AUTHORIZATION regress_rls_bob;
SET row_security TO ON;
SELECT * FROM hyper_document WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my first satire
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => awesome science fiction
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   4 |  55 |      1 | regress_rls_bob   | my first satire
   6 |  11 |      1 | regress_rls_carol | great science fiction
   9 |  11 |      1 | regress_rls_dave  | awesome science fiction

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM hyper_document WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on hyper_document
   Chunks excluded during startup: 0
   InitPlan 1 (returns $0)
     ->  Index Scan using uaccount_pkey on uaccount
           Index Cond: (pguser = CURRENT_USER)
   ->  Seq Scan on hyper_document hyper_document_1
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_9_chunk hyper_document_2
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_10_chunk hyper_document_3
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_11_chunk hyper_document_4
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_12_chunk hyper_document_5
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_13_chunk hyper_document_6
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_14_chunk hyper_document_7
         Filter: ((dlevel <= $0) AND f_leak(dtitle))

-- viewpoint from regress_rls_carol
SET SESSION AUTHORIZATION regress_rls_carol;
SELECT * FROM hyper_document WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => my science textbook
NOTICE:  f_leak => my first satire
NOTICE:  f_leak => my history book
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great technology book
NOTICE:  f_leak => great satire
NOTICE:  f_leak => awesome science fiction
NOTICE:  f_leak => awesome technology book
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  99 |      2 | regress_rls_bob   | my science textbook
   4 |  55 |      1 | regress_rls_bob   | my first satire
   5 |  99 |      2 | regress_rls_bob   | my history book
   6 |  11 |      1 | regress_rls_carol | great science fiction
   7 |  99 |      2 | regress_rls_carol | great technology book
   8 |  55 |      2 | regress_rls_carol | great satire
   9 |  11 |      1 | regress_rls_dave  | awesome science fiction
  10 |  99 |      2 | regress_rls_dave  | awesome technology book

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM hyper_document WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on hyper_document
   Chunks excluded during startup: 0
   InitPlan 1 (returns $0)
     ->  Index Scan using uaccount_pkey on uaccount
           Index Cond: (pguser = CURRENT_USER)
   ->  Seq Scan on hyper_document hyper_document_1
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_9_chunk hyper_document_2
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_10_chunk hyper_document_3
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_11_chunk hyper_document_4
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_12_chunk hyper_document_5
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_13_chunk hyper_document_6
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_14_chunk hyper_document_7
         Filter: ((dlevel <= $0) AND f_leak(dtitle))

-- viewpoint from regress_rls_dave
SET SESSION AUTHORIZATION regress_rls_dave;
SELECT * FROM hyper_document WHERE f_leak(dtitle) ORDER BY did;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => awesome science fiction
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   6 |  11 |      1 | regress_rls_carol | great science fiction
   9 |  11 |      1 | regress_rls_dave  | awesome science fiction

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM hyper_document WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on hyper_document
   Chunks excluded during startup: 0
   InitPlan 1 (returns $0)
     ->  Index Scan using uaccount_pkey on uaccount
           Index Cond: (pguser = CURRENT_USER)
   ->  Seq Scan on hyper_document hyper_document_1
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_9_chunk hyper_document_2
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_10_chunk hyper_document_3
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_11_chunk hyper_document_4
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_12_chunk hyper_document_5
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_13_chunk hyper_document_6
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_14_chunk hyper_document_7
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))

-- pp1 ERROR
INSERT INTO hyper_document VALUES (1, 11, 5, 'regress_rls_dave', 'testing pp1'); -- fail
ERROR:  new row violates row-level security policy for table "hyper_document"
-- pp1r ERROR
INSERT INTO hyper_document VALUES (1, 99, 1, 'regress_rls_dave', 'testing pp1r'); -- fail
ERROR:  new row violates row-level security policy "pp1r" for table "hyper_document"
-- Show that RLS policy does not apply for direct inserts to children
-- This should fail with RLS POLICY pp1r violation.
INSERT INTO hyper_document VALUES (1, 55, 1, 'regress_rls_dave', 'testing RLS with hypertables'); -- fail
ERROR:  new row violates row-level security policy "pp1r" for table "hyper_document"
-- But this should succeed.
INSERT INTO _timescaledb_internal._hyper_2_9_chunk VALUES (1, 55, 1, 'regress_rls_dave', 'testing RLS with hypertables'); -- success
-- We still cannot see the row using the parent
SELECT * FROM hyper_document WHERE f_leak(dtitle) ORDER BY did, cid;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => awesome science fiction
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   6 |  11 |      1 | regress_rls_carol | great science fiction
   9 |  11 |      1 | regress_rls_dave  | awesome science fiction

-- But we can if we look directly
SELECT * FROM _timescaledb_internal._hyper_2_9_chunk WHERE f_leak(dtitle) ORDER BY did, cid;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => testing RLS with hypertables
 did | cid | dlevel |     dauthor      |            dtitle            
-----+-----+--------+------------------+------------------------------
   1 |  11 |      1 | regress_rls_bob  | my first novel
   1 |  55 |      1 | regress_rls_dave | testing RLS with hypertables

-- Turn on RLS and create policy on child to show RLS is checked before constraints
SET SESSION AUTHORIZATION regress_rls_alice;
ALTER TABLE _timescaledb_internal._hyper_2_9_chunk ENABLE ROW LEVEL SECURITY;
CREATE POLICY pp3 ON _timescaledb_internal._hyper_2_9_chunk AS RESTRICTIVE
    USING (cid < 55);
-- This should fail with RLS violation now.
SET SESSION AUTHORIZATION regress_rls_dave;
INSERT INTO _timescaledb_internal._hyper_2_9_chunk VALUES (1, 55, 1, 'regress_rls_dave', 'testing RLS with hypertables - round 2'); -- fail
ERROR:  new row violates row-level security policy for table "_hyper_2_9_chunk"
-- And now we cannot see directly into the partition either, due to RLS
SELECT * FROM _timescaledb_internal._hyper_2_9_chunk WHERE f_leak(dtitle) ORDER BY did, cid;
 did | cid | dlevel | dauthor | dtitle 
-----+-----+--------+---------+--------

-- The parent looks same as before
-- viewpoint from regress_rls_dave
SELECT * FROM hyper_document WHERE f_leak(dtitle) ORDER BY did, cid;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => awesome science fiction
 did | cid | dlevel |      dauthor      |         dtitle          
-----+-----+--------+-------------------+-------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   2 |  11 |      2 | regress_rls_bob   | my second novel
   6 |  11 |      1 | regress_rls_carol | great science fiction
   9 |  11 |      1 | regress_rls_dave  | awesome science fiction

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM hyper_document WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on hyper_document
   Chunks excluded during startup: 0
   InitPlan 1 (returns $0)
     ->  Index Scan using uaccount_pkey on uaccount
           Index Cond: (pguser = CURRENT_USER)
   ->  Seq Scan on hyper_document hyper_document_1
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_9_chunk hyper_document_2
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_10_chunk hyper_document_3
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_11_chunk hyper_document_4
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_12_chunk hyper_document_5
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_13_chunk hyper_document_6
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_14_chunk hyper_document_7
         Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))

-- viewpoint from regress_rls_carol
SET SESSION AUTHORIZATION regress_rls_carol;
SELECT * FROM hyper_document WHERE f_leak(dtitle) ORDER BY did, cid;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => testing RLS with hypertables
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => my science textbook
NOTICE:  f_leak => my first satire
NOTICE:  f_leak => my history book
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great technology book
NOTICE:  f_leak => great satire
NOTICE:  f_leak => awesome science fiction
NOTICE:  f_leak => awesome technology book
 did | cid | dlevel |      dauthor      |            dtitle            
-----+-----+--------+-------------------+------------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   1 |  55 |      1 | regress_rls_dave  | testing RLS with hypertables
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  99 |      2 | regress_rls_bob   | my science textbook
   4 |  55 |      1 | regress_rls_bob   | my first satire
   5 |  99 |      2 | regress_rls_bob   | my history book
   6 |  11 |      1 | regress_rls_carol | great science fiction
   7 |  99 |      2 | regress_rls_carol | great technology book
   8 |  55 |      2 | regress_rls_carol | great satire
   9 |  11 |      1 | regress_rls_dave  | awesome science fiction
  10 |  99 |      2 | regress_rls_dave  | awesome technology book

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM hyper_document WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on hyper_document
   Chunks excluded during startup: 0
   InitPlan 1 (returns $0)
     ->  Index Scan using uaccount_pkey on uaccount
           Index Cond: (pguser = CURRENT_USER)
   ->  Seq Scan on hyper_document hyper_document_1
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_9_chunk hyper_document_2
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_10_chunk hyper_document_3
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_11_chunk hyper_document_4
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_12_chunk hyper_document_5
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_13_chunk hyper_document_6
         Filter: ((dlevel <= $0) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_14_chunk hyper_document_7
         Filter: ((dlevel <= $0) AND f_leak(dtitle))

-- only owner can change policies
ALTER POLICY pp1 ON hyper_document USING (true);    --fail
ERROR:  must be owner of table hyper_document
DROP POLICY pp1 ON hyper_document;                  --fail
ERROR:  must be owner of relation hyper_document
SET SESSION AUTHORIZATION regress_rls_alice;
ALTER POLICY pp1 ON hyper_document USING (dauthor = current_user);
-- viewpoint from regress_rls_bob again
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM hyper_document WHERE f_leak(dtitle) ORDER BY did, cid;
NOTICE:  f_leak => my first novel
NOTICE:  f_leak => my second novel
NOTICE:  f_leak => my science textbook
NOTICE:  f_leak => my first satire
NOTICE:  f_leak => my history book
 did | cid | dlevel |     dauthor     |       dtitle        
-----+-----+--------+-----------------+---------------------
   1 |  11 |      1 | regress_rls_bob | my first novel
   2 |  11 |      2 | regress_rls_bob | my second novel
   3 |  99 |      2 | regress_rls_bob | my science textbook
   4 |  55 |      1 | regress_rls_bob | my first satire
   5 |  99 |      2 | regress_rls_bob | my history book

-- viewpoint from rls_regres_carol again
SET SESSION AUTHORIZATION regress_rls_carol;
SELECT * FROM hyper_document WHERE f_leak(dtitle) ORDER BY did, cid;
NOTICE:  f_leak => great science fiction
NOTICE:  f_leak => great technology book
NOTICE:  f_leak => great satire
 did | cid | dlevel |      dauthor      |        dtitle         
-----+-----+--------+-------------------+-----------------------
   6 |  11 |      1 | regress_rls_carol | great science fiction
   7 |  99 |      2 | regress_rls_carol | great technology book
   8 |  55 |      2 | regress_rls_carol | great satire

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM hyper_document WHERE f_leak(dtitle);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on hyper_document
   Chunks excluded during startup: 0
   ->  Seq Scan on hyper_document hyper_document_1
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_9_chunk hyper_document_2
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_10_chunk hyper_document_3
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_11_chunk hyper_document_4
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_12_chunk hyper_document_5
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_13_chunk hyper_document_6
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
   ->  Seq Scan on _hyper_2_14_chunk hyper_document_7
         Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))

-- database superuser does bypass RLS policy when enabled
RESET SESSION AUTHORIZATION;
SET row_security TO ON;
SELECT * FROM hyper_document ORDER BY did, cid;
 did | cid | dlevel |      dauthor      |            dtitle            
-----+-----+--------+-------------------+------------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   1 |  55 |      1 | regress_rls_dave  | testing RLS with hypertables
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  99 |      2 | regress_rls_bob   | my science textbook
   4 |  55 |      1 | regress_rls_bob   | my first satire
   5 |  99 |      2 | regress_rls_bob   | my history book
   6 |  11 |      1 | regress_rls_carol | great science fiction
   7 |  99 |      2 | regress_rls_carol | great technology book
   8 |  55 |      2 | regress_rls_carol | great satire
   9 |  11 |      1 | regress_rls_dave  | awesome science fiction
  10 |  99 |      2 | regress_rls_dave  | awesome technology book

SELECT * FROM _timescaledb_internal._hyper_2_9_chunk ORDER BY did, cid;
 did | cid | dlevel |     dauthor      |            dtitle            
-----+-----+--------+------------------+------------------------------
   1 |  11 |      1 | regress_rls_bob  | my first novel
   1 |  55 |      1 | regress_rls_dave | testing RLS with hypertables

-- database non-superuser with bypass privilege can bypass RLS policy when disabled
SET SESSION AUTHORIZATION regress_rls_exempt_user;
SET row_security TO OFF;
SELECT * FROM hyper_document ORDER BY did, cid;
 did | cid | dlevel |      dauthor      |            dtitle            
-----+-----+--------+-------------------+------------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   1 |  55 |      1 | regress_rls_dave  | testing RLS with hypertables
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  99 |      2 | regress_rls_bob   | my science textbook
   4 |  55 |      1 | regress_rls_bob   | my first satire
   5 |  99 |      2 | regress_rls_bob   | my history book
   6 |  11 |      1 | regress_rls_carol | great science fiction
   7 |  99 |      2 | regress_rls_carol | great technology book
   8 |  55 |      2 | regress_rls_carol | great satire
   9 |  11 |      1 | regress_rls_dave  | awesome science fiction
  10 |  99 |      2 | regress_rls_dave  | awesome technology book

SELECT * FROM _timescaledb_internal._hyper_2_9_chunk ORDER BY did, cid;
 did | cid | dlevel |     dauthor      |            dtitle            
-----+-----+--------+------------------+------------------------------
   1 |  11 |      1 | regress_rls_bob  | my first novel
   1 |  55 |      1 | regress_rls_dave | testing RLS with hypertables

-- RLS policy does not apply to table owner when RLS enabled.
SET SESSION AUTHORIZATION regress_rls_alice;
SET row_security TO ON;
SELECT * FROM hyper_document ORDER BY did, cid;
 did | cid | dlevel |      dauthor      |            dtitle            
-----+-----+--------+-------------------+------------------------------
   1 |  11 |      1 | regress_rls_bob   | my first novel
   1 |  55 |      1 | regress_rls_dave  | testing RLS with hypertables
   2 |  11 |      2 | regress_rls_bob   | my second novel
   3 |  99 |      2 | regress_rls_bob   | my science textbook
   4 |  55 |      1 | regress_rls_bob   | my first satire
   5 |  99 |      2 | regress_rls_bob   | my history book
   6 |  11 |      1 | regress_rls_carol | great science fiction
   7 |  99 |      2 | regress_rls_carol | great technology book
   8 |  55 |      2 | regress_rls_carol | great satire
   9 |  11 |      1 | regress_rls_dave  | awesome science fiction
  10 |  99 |      2 | regress_rls_dave  | awesome technology book

SELECT * FROM _timescaledb_internal._hyper_2_9_chunk ORDER BY did, cid;
 did | cid | dlevel |     dauthor      |            dtitle            
-----+-----+--------+------------------+------------------------------
   1 |  11 |      1 | regress_rls_bob  | my first novel
   1 |  55 |      1 | regress_rls_dave | testing RLS with hypertables

-- When RLS disabled, other users get ERROR.
SET SESSION AUTHORIZATION regress_rls_dave;
SET row_security TO OFF;
SELECT * FROM hyper_document ORDER BY did, cid;
ERROR:  query would be affected by row-level security policy for table "hyper_document"
SELECT * FROM _timescaledb_internal._hyper_2_9_chunk ORDER BY did, cid;
ERROR:  query would be affected by row-level security policy for table "_hyper_2_9_chunk"
-- Check behavior with a policy that uses a SubPlan not an InitPlan.
SET SESSION AUTHORIZATION regress_rls_alice;
SET row_security TO ON;
CREATE POLICY pp3 ON hyper_document AS RESTRICTIVE
    USING ((SELECT dlevel <= seclv FROM uaccount WHERE pguser = current_user));
SET SESSION AUTHORIZATION regress_rls_carol;
INSERT INTO hyper_document VALUES (100, 11, 5, 'regress_rls_carol', 'testing pp3'); -- fail
ERROR:  new row violates row-level security policy "pp3" for table "hyper_document"
----- Dependencies -----
SET SESSION AUTHORIZATION regress_rls_alice;
SET row_security TO ON;
CREATE TABLE dependee (x integer, y integer);
SELECT public.create_hypertable('dependee', 'x', chunk_time_interval=>2);
         create_hypertable         
-----------------------------------
 (3,regress_rls_schema,dependee,t)

CREATE TABLE dependent (x integer, y integer);
SELECT public.create_hypertable('dependent', 'x', chunk_time_interval=>2);
         create_hypertable          
------------------------------------
 (4,regress_rls_schema,dependent,t)

CREATE POLICY d1 ON dependent FOR ALL
    TO PUBLIC
    USING (x = (SELECT d.x FROM dependee d WHERE d.y = y));
DROP TABLE dependee; -- Should fail without CASCADE due to dependency on row security qual?
ERROR:  cannot drop table dependee because other objects depend on it
DETAIL:  policy d1 on table dependent depends on table dependee
HINT:  Use DROP ... CASCADE to drop the dependent objects too.
DROP TABLE dependee CASCADE;
NOTICE:  drop cascades to policy d1 on table dependent
EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM dependent; -- After drop, should be unqualified
--- QUERY PLAN ---
 Seq Scan on dependent

-----   RECURSION    ----
--
-- Simple recursion
--
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE rec1 (x integer, y integer);
SELECT public.create_hypertable('rec1', 'x', chunk_time_interval=>2);
       create_hypertable       
-------------------------------
 (5,regress_rls_schema,rec1,t)

CREATE POLICY r1 ON rec1 USING (x = (SELECT r.x FROM rec1 r WHERE y = r.y));
ALTER TABLE rec1 ENABLE ROW LEVEL SECURITY;
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM rec1; -- fail, direct recursion
ERROR:  infinite recursion detected in policy for relation "rec1"
--
-- Mutual recursion
--
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE rec2 (a integer, b integer);
SELECT public.create_hypertable('rec2', 'x', chunk_time_interval=>2);
ERROR:  column "x" does not exist
ALTER POLICY r1 ON rec1 USING (x = (SELECT a FROM rec2 WHERE b = y));
CREATE POLICY r2 ON rec2 USING (a = (SELECT x FROM rec1 WHERE y = b));
ALTER TABLE rec2 ENABLE ROW LEVEL SECURITY;
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM rec1;    -- fail, mutual recursion
ERROR:  infinite recursion detected in policy for relation "rec1"
--
-- Mutual recursion via views
--
SET SESSION AUTHORIZATION regress_rls_bob;
CREATE VIEW rec1v AS SELECT * FROM rec1;
CREATE VIEW rec2v AS SELECT * FROM rec2;
SET SESSION AUTHORIZATION regress_rls_alice;
ALTER POLICY r1 ON rec1 USING (x = (SELECT a FROM rec2v WHERE b = y));
ALTER POLICY r2 ON rec2 USING (a = (SELECT x FROM rec1v WHERE y = b));
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM rec1;    -- fail, mutual recursion via views
ERROR:  infinite recursion detected in policy for relation "rec1"
--
-- Mutual recursion via .s.b views
--
SET SESSION AUTHORIZATION regress_rls_bob;
\set VERBOSITY terse \\ -- suppress cascade details
DROP VIEW rec1v, rec2v CASCADE;
NOTICE:  drop cascades to 2 other objects
\set VERBOSITY default
CREATE VIEW rec1v WITH (security_barrier) AS SELECT * FROM rec1;
CREATE VIEW rec2v WITH (security_barrier) AS SELECT * FROM rec2;
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE POLICY r1 ON rec1 USING (x = (SELECT a FROM rec2v WHERE b = y));
CREATE POLICY r2 ON rec2 USING (a = (SELECT x FROM rec1v WHERE y = b));
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM rec1;    -- fail, mutual recursion via s.b. views
ERROR:  infinite recursion detected in policy for relation "rec1"
--
-- recursive RLS and VIEWs in policy
--
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE s1 (a int, b text);
SELECT public.create_hypertable('s1', 'a', chunk_time_interval=>2);
      create_hypertable      
-----------------------------
 (6,regress_rls_schema,s1,t)

INSERT INTO s1 (SELECT x, md5(x::text) FROM generate_series(-10,10) x);
CREATE TABLE s2 (x int, y text);
SELECT public.create_hypertable('s2', 'x', chunk_time_interval=>2);
      create_hypertable      
-----------------------------
 (7,regress_rls_schema,s2,t)

INSERT INTO s2 (SELECT x, md5(x::text) FROM generate_series(-6,6) x);
GRANT SELECT ON s1, s2 TO regress_rls_bob;
CREATE POLICY p1 ON s1 USING (a in (select x from s2 where y like '%2f%'));
CREATE POLICY p2 ON s2 USING (x in (select a from s1 where b like '%22%'));
CREATE POLICY p3 ON s1 FOR INSERT WITH CHECK (a = (SELECT a FROM s1));
ALTER TABLE s1 ENABLE ROW LEVEL SECURITY;
ALTER TABLE s2 ENABLE ROW LEVEL SECURITY;
SET SESSION AUTHORIZATION regress_rls_bob;
CREATE VIEW v2 AS SELECT * FROM s2 WHERE y like '%af%';
SELECT * FROM s1 WHERE f_leak(b); -- fail (infinite recursion)
ERROR:  infinite recursion detected in policy for relation "s1"
INSERT INTO s1 VALUES (1, 'foo'); -- fail (infinite recursion)
ERROR:  infinite recursion detected in policy for relation "s1"
SET SESSION AUTHORIZATION regress_rls_alice;
DROP POLICY p3 on s1;
ALTER POLICY p2 ON s2 USING (x % 2 = 0);
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM s1 WHERE f_leak(b);	-- OK
NOTICE:  f_leak => c81e728d9d4c2f636f067f89cc14862c
NOTICE:  f_leak => a87ff679a2f3e71d9181a67b7542122c
 a |                b                 
---+----------------------------------
 2 | c81e728d9d4c2f636f067f89cc14862c
 4 | a87ff679a2f3e71d9181a67b7542122c

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM only s1 WHERE f_leak(b);
--- QUERY PLAN ---
 Seq Scan on s1
   Filter: ((hashed SubPlan 1) AND f_leak(b))
   SubPlan 1
     ->  Append
           ->  Seq Scan on s2 s2_1
                 Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text))
           ->  Seq Scan on _hyper_7_27_chunk s2_2
                 Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text))
           ->  Seq Scan on _hyper_7_28_chunk s2_3
                 Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text))
           ->  Seq Scan on _hyper_7_29_chunk s2_4
                 Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text))
           ->  Seq Scan on _hyper_7_30_chunk s2_5
                 Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text))
           ->  Seq Scan on _hyper_7_31_chunk s2_6
                 Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text))
           ->  Seq Scan on _hyper_7_32_chunk s2_7
                 Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text))
           ->  Seq Scan on _hyper_7_33_chunk s2_8
                 Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text))

SET SESSION AUTHORIZATION regress_rls_alice;
ALTER POLICY p1 ON s1 USING (a in (select x from v2)); -- using VIEW in RLS policy
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM s1 WHERE f_leak(b);	-- OK
NOTICE:  f_leak => 0267aaf632e87a63288a08331f22c7c3
NOTICE:  f_leak => 1679091c5a880faf6fb5e6087eb1b2dc
 a  |                b                 
----+----------------------------------
 -4 | 0267aaf632e87a63288a08331f22c7c3
  6 | 1679091c5a880faf6fb5e6087eb1b2dc

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM s1 WHERE f_leak(b);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on s1
   Chunks excluded during startup: 0
   ->  Seq Scan on s1 s1_1
         Filter: ((hashed SubPlan 1) AND f_leak(b))
         SubPlan 1
           ->  Append
                 ->  Seq Scan on s2 s2_1
                       Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                 ->  Seq Scan on _hyper_7_27_chunk s2_2
                       Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                 ->  Seq Scan on _hyper_7_28_chunk s2_3
                       Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                 ->  Seq Scan on _hyper_7_29_chunk s2_4
                       Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                 ->  Seq Scan on _hyper_7_30_chunk s2_5
                       Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                 ->  Seq Scan on _hyper_7_31_chunk s2_6
                       Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                 ->  Seq Scan on _hyper_7_32_chunk s2_7
                       Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                 ->  Seq Scan on _hyper_7_33_chunk s2_8
                       Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
   ->  Seq Scan on _hyper_6_16_chunk s1_2
         Filter: ((hashed SubPlan 1) AND f_leak(b))
   ->  Seq Scan on _hyper_6_17_chunk s1_3
         Filter: ((hashed SubPlan 1) AND f_leak(b))
   ->  Seq Scan on _hyper_6_18_chunk s1_4
         Filter: ((hashed SubPlan 1) AND f_leak(b))
   ->  Seq Scan on _hyper_6_19_chunk s1_5
         Filter: ((hashed SubPlan 1) AND f_leak(b))
   ->  Seq Scan on _hyper_6_20_chunk s1_6
         Filter: ((hashed SubPlan 1) AND f_leak(b))
   ->  Seq Scan on _hyper_6_21_chunk s1_7
         Filter: ((hashed SubPlan 1) AND f_leak(b))
   ->  Seq Scan on _hyper_6_22_chunk s1_8
         Filter: ((hashed SubPlan 1) AND f_leak(b))
   ->  Seq Scan on _hyper_6_23_chunk s1_9
         Filter: ((hashed SubPlan 1) AND f_leak(b))
   ->  Seq Scan on _hyper_6_24_chunk s1_10
         Filter: ((hashed SubPlan 1) AND f_leak(b))
   ->  Seq Scan on _hyper_6_25_chunk s1_11
         Filter: ((hashed SubPlan 1) AND f_leak(b))
   ->  Seq Scan on _hyper_6_26_chunk s1_12
         Filter: ((hashed SubPlan 1) AND f_leak(b))

SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like '%28%';
 xx | x  |                y                 
----+----+----------------------------------
 -6 | -6 | 596a3d04481816330f07e4f97510c28f
 -4 | -4 | 0267aaf632e87a63288a08331f22c7c3
  2 |  2 | c81e728d9d4c2f636f067f89cc14862c

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like '%28%';
--- QUERY PLAN ---
 Result
   ->  Append
         ->  Seq Scan on s2 s2_1
               Filter: (((x % 2) = 0) AND (y ~~ '%28%'::text))
         ->  Seq Scan on _hyper_7_27_chunk s2_2
               Filter: (((x % 2) = 0) AND (y ~~ '%28%'::text))
         ->  Seq Scan on _hyper_7_28_chunk s2_3
               Filter: (((x % 2) = 0) AND (y ~~ '%28%'::text))
         ->  Seq Scan on _hyper_7_29_chunk s2_4
               Filter: (((x % 2) = 0) AND (y ~~ '%28%'::text))
         ->  Seq Scan on _hyper_7_30_chunk s2_5
               Filter: (((x % 2) = 0) AND (y ~~ '%28%'::text))
         ->  Seq Scan on _hyper_7_31_chunk s2_6
               Filter: (((x % 2) = 0) AND (y ~~ '%28%'::text))
         ->  Seq Scan on _hyper_7_32_chunk s2_7
               Filter: (((x % 2) = 0) AND (y ~~ '%28%'::text))
         ->  Seq Scan on _hyper_7_33_chunk s2_8
               Filter: (((x % 2) = 0) AND (y ~~ '%28%'::text))
   SubPlan 2
     ->  Limit
           ->  Result
                 ->  Custom Scan (ChunkAppend) on s1
                       ->  Seq Scan on s1 s1_1
                             Filter: (hashed SubPlan 1)
                             SubPlan 1
                               ->  Append
                                     ->  Seq Scan on s2 s2_10
                                           Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                                     ->  Seq Scan on _hyper_7_27_chunk s2_11
                                           Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                                     ->  Seq Scan on _hyper_7_28_chunk s2_12
                                           Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                                     ->  Seq Scan on _hyper_7_29_chunk s2_13
                                           Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                                     ->  Seq Scan on _hyper_7_30_chunk s2_14
                                           Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                                     ->  Seq Scan on _hyper_7_31_chunk s2_15
                                           Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                                     ->  Seq Scan on _hyper_7_32_chunk s2_16
                                           Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                                     ->  Seq Scan on _hyper_7_33_chunk s2_17
                                           Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text))
                       ->  Seq Scan on _hyper_6_16_chunk s1_2
                             Filter: (hashed SubPlan 1)
                       ->  Seq Scan on _hyper_6_17_chunk s1_3
                             Filter: (hashed SubPlan 1)
                       ->  Seq Scan on _hyper_6_18_chunk s1_4
                             Filter: (hashed SubPlan 1)
                       ->  Seq Scan on _hyper_6_19_chunk s1_5
                             Filter: (hashed SubPlan 1)
                       ->  Seq Scan on _hyper_6_20_chunk s1_6
                             Filter: (hashed SubPlan 1)
                       ->  Seq Scan on _hyper_6_21_chunk s1_7
                             Filter: (hashed SubPlan 1)
                       ->  Seq Scan on _hyper_6_22_chunk s1_8
                             Filter: (hashed SubPlan 1)
                       ->  Seq Scan on _hyper_6_23_chunk s1_9
                             Filter: (hashed SubPlan 1)
                       ->  Seq Scan on _hyper_6_24_chunk s1_10
                             Filter: (hashed SubPlan 1)
                       ->  Seq Scan on _hyper_6_25_chunk s1_11
                             Filter: (hashed SubPlan 1)
                       ->  Seq Scan on _hyper_6_26_chunk s1_12
                             Filter: (hashed SubPlan 1)

SET SESSION AUTHORIZATION regress_rls_alice;
ALTER POLICY p2 ON s2 USING (x in (select a from s1 where b like '%d2%'));
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM s1 WHERE f_leak(b);	-- fail (infinite recursion via view)
ERROR:  infinite recursion detected in policy for relation "s1"
-- prepared statement with regress_rls_alice privilege
PREPARE p1(int) AS SELECT * FROM t1 WHERE a <= $1;
EXECUTE p1(2);
 a |  b  
---+-----
 2 | bbb
 2 | bcd
 2 | yyy

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE p1(2);
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: ((a <= 2) AND ((a % 2) = 0))
   ->  Seq Scan on t2 t1_2
         Filter: ((a <= 2) AND ((a % 2) = 0))
   ->  Seq Scan on t3 t1_3
         Filter: ((a <= 2) AND ((a % 2) = 0))

-- superuser is allowed to bypass RLS checks
RESET SESSION AUTHORIZATION;
SET row_security TO OFF;
SELECT * FROM t1 WHERE f_leak(b);
NOTICE:  f_leak => aba
NOTICE:  f_leak => bbb
NOTICE:  f_leak => ccc
NOTICE:  f_leak => dad
NOTICE:  f_leak => abc
NOTICE:  f_leak => bcd
NOTICE:  f_leak => cde
NOTICE:  f_leak => def
NOTICE:  f_leak => xxx
NOTICE:  f_leak => yyy
NOTICE:  f_leak => zzz
 a |  b  
---+-----
 1 | aba
 2 | bbb
 3 | ccc
 4 | dad
 1 | abc
 2 | bcd
 3 | cde
 4 | def
 1 | xxx
 2 | yyy
 3 | zzz

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: f_leak(b)
   ->  Seq Scan on t2 t1_2
         Filter: f_leak(b)
   ->  Seq Scan on t3 t1_3
         Filter: f_leak(b)

-- plan cache should be invalidated
EXECUTE p1(2);
 a |  b  
---+-----
 1 | aba
 2 | bbb
 1 | abc
 2 | bcd
 1 | xxx
 2 | yyy

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE p1(2);
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: (a <= 2)
   ->  Seq Scan on t2 t1_2
         Filter: (a <= 2)
   ->  Seq Scan on t3 t1_3
         Filter: (a <= 2)

PREPARE p2(int) AS SELECT * FROM t1 WHERE a = $1;
EXECUTE p2(2);
 a |  b  
---+-----
 2 | bbb
 2 | bcd
 2 | yyy

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE p2(2);
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: (a = 2)
   ->  Seq Scan on t2 t1_2
         Filter: (a = 2)
   ->  Seq Scan on t3 t1_3
         Filter: (a = 2)

-- also, case when privilege switch from superuser
SET SESSION AUTHORIZATION regress_rls_bob;
SET row_security TO ON;
EXECUTE p2(2);
 a |  b  
---+-----
 2 | bbb
 2 | bcd
 2 | yyy

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE p2(2);
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
         Filter: ((a = 2) AND ((a % 2) = 0))
   ->  Seq Scan on t2 t1_2
         Filter: ((a = 2) AND ((a % 2) = 0))
   ->  Seq Scan on t3 t1_3
         Filter: ((a = 2) AND ((a % 2) = 0))

--
-- UPDATE / DELETE and Row-level security
--
SET SESSION AUTHORIZATION regress_rls_bob;
EXPLAIN (BUFFERS OFF, COSTS OFF) UPDATE t1 SET b = b || b WHERE f_leak(b);
--- QUERY PLAN ---
 Update on t1
   Update on t1 t1_1
   Update on t2 t1_2
   Update on t3 t1_3
   ->  Result
         ->  Append
               ->  Seq Scan on t1 t1_1
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on t2 t1_2
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on t3 t1_3
                     Filter: (((a % 2) = 0) AND f_leak(b))

UPDATE t1 SET b = b || b WHERE f_leak(b);
NOTICE:  f_leak => bbb
NOTICE:  f_leak => dad
NOTICE:  f_leak => bcd
NOTICE:  f_leak => def
NOTICE:  f_leak => yyy
EXPLAIN (BUFFERS OFF, COSTS OFF) UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b);
--- QUERY PLAN ---
 Update on t1
   ->  Seq Scan on t1
         Filter: (((a % 2) = 0) AND f_leak(b))

UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b);
NOTICE:  f_leak => bbbbbb
NOTICE:  f_leak => daddad
-- returning clause with system column
UPDATE only t1 SET b = b WHERE f_leak(b) RETURNING ctid, *, t1;
NOTICE:  f_leak => bbbbbb_updt
NOTICE:  f_leak => daddad_updt
  ctid  | a |      b      |       t1        
--------+---+-------------+-----------------
 (0,9)  | 2 | bbbbbb_updt | (2,bbbbbb_updt)
 (0,10) | 4 | daddad_updt | (4,daddad_updt)

UPDATE t1 SET b = b WHERE f_leak(b) RETURNING *;
NOTICE:  f_leak => bbbbbb_updt
NOTICE:  f_leak => daddad_updt
NOTICE:  f_leak => bcdbcd
NOTICE:  f_leak => defdef
NOTICE:  f_leak => yyyyyy
 a |      b      
---+-------------
 2 | bbbbbb_updt
 4 | daddad_updt
 2 | bcdbcd
 4 | defdef
 2 | yyyyyy

UPDATE t1 SET b = b WHERE f_leak(b) RETURNING ctid, *, t1;
NOTICE:  f_leak => bbbbbb_updt
NOTICE:  f_leak => daddad_updt
NOTICE:  f_leak => bcdbcd
NOTICE:  f_leak => defdef
NOTICE:  f_leak => yyyyyy
  ctid  | a |      b      |       t1        
--------+---+-------------+-----------------
 (0,13) | 2 | bbbbbb_updt | (2,bbbbbb_updt)
 (0,14) | 4 | daddad_updt | (4,daddad_updt)
 (0,9)  | 2 | bcdbcd      | (2,bcdbcd)
 (0,10) | 4 | defdef      | (4,defdef)
 (0,6)  | 2 | yyyyyy      | (2,yyyyyy)

-- updates with from clause
EXPLAIN (BUFFERS OFF, COSTS OFF) UPDATE t2 SET b=t2.b FROM t3
WHERE t2.a = 3 and t3.a = 2 AND f_leak(t2.b) AND f_leak(t3.b);
--- QUERY PLAN ---
 Update on t2
   ->  Nested Loop
         ->  Seq Scan on t2
               Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b))
         ->  Seq Scan on t3
               Filter: ((a = 2) AND f_leak(b))

UPDATE t2 SET b=t2.b FROM t3
WHERE t2.a = 3 and t3.a = 2 AND f_leak(t2.b) AND f_leak(t3.b);
NOTICE:  f_leak => cde
NOTICE:  f_leak => yyyyyy
EXPLAIN (BUFFERS OFF, COSTS OFF) UPDATE t1 SET b=t1.b FROM t2
WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b);
--- QUERY PLAN ---
 Update on t1
   Update on t1 t1_1
   Update on t2 t1_2
   Update on t3 t1_3
   ->  Nested Loop
         ->  Seq Scan on t2
               Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b))
         ->  Append
               ->  Seq Scan on t1 t1_1
                     Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on t2 t1_2
                     Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on t3 t1_3
                     Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))

UPDATE t1 SET b=t1.b FROM t2
WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b);
NOTICE:  f_leak => cde
EXPLAIN (BUFFERS OFF, COSTS OFF) UPDATE t2 SET b=t2.b FROM t1
WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b);
--- QUERY PLAN ---
 Update on t2
   ->  Nested Loop
         ->  Seq Scan on t2
               Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b))
         ->  Append
               ->  Seq Scan on t1 t1_1
                     Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on t2 t1_2
                     Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on t3 t1_3
                     Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))

UPDATE t2 SET b=t2.b FROM t1
WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b);
NOTICE:  f_leak => cde
-- updates with from clause self join
EXPLAIN (BUFFERS OFF, COSTS OFF) UPDATE t2 t2_1 SET b = t2_2.b FROM t2 t2_2
WHERE t2_1.a = 3 AND t2_2.a = t2_1.a AND t2_2.b = t2_1.b
AND f_leak(t2_1.b) AND f_leak(t2_2.b) RETURNING *, t2_1, t2_2;
--- QUERY PLAN ---
 Update on t2 t2_1
   ->  Nested Loop
         Join Filter: (t2_1.b = t2_2.b)
         ->  Seq Scan on t2 t2_1
               Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b))
         ->  Seq Scan on t2 t2_2
               Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b))

UPDATE t2 t2_1 SET b = t2_2.b FROM t2 t2_2
WHERE t2_1.a = 3 AND t2_2.a = t2_1.a AND t2_2.b = t2_1.b
AND f_leak(t2_1.b) AND f_leak(t2_2.b) RETURNING *, t2_1, t2_2;
NOTICE:  f_leak => cde
NOTICE:  f_leak => cde
 a |  b  |  c  | a |  b  |  c  |    t2_1     |    t2_2     
---+-----+-----+---+-----+-----+-------------+-------------
 3 | cde | 3.3 | 3 | cde | 3.3 | (3,cde,3.3) | (3,cde,3.3)

EXPLAIN (BUFFERS OFF, COSTS OFF) UPDATE t1 t1_1 SET b = t1_2.b FROM t1 t1_2
WHERE t1_1.a = 4 AND t1_2.a = t1_1.a AND t1_2.b = t1_1.b
AND f_leak(t1_1.b) AND f_leak(t1_2.b) RETURNING *, t1_1, t1_2;
--- QUERY PLAN ---
 Update on t1 t1_1
   Update on t1 t1_1_1
   Update on t2 t1_1_2
   Update on t3 t1_1_3
   ->  Nested Loop
         Join Filter: (t1_1.b = t1_2.b)
         ->  Append
               ->  Seq Scan on t1 t1_1_1
                     Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on t2 t1_1_2
                     Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on t3 t1_1_3
                     Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
         ->  Materialize
               ->  Append
                     ->  Seq Scan on t1 t1_2_1
                           Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
                     ->  Seq Scan on t2 t1_2_2
                           Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
                     ->  Seq Scan on t3 t1_2_3
                           Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))

UPDATE t1 t1_1 SET b = t1_2.b FROM t1 t1_2
WHERE t1_1.a = 4 AND t1_2.a = t1_1.a AND t1_2.b = t1_1.b
AND f_leak(t1_1.b) AND f_leak(t1_2.b) RETURNING *, t1_1, t1_2;
NOTICE:  f_leak => daddad_updt
NOTICE:  f_leak => daddad_updt
NOTICE:  f_leak => defdef
NOTICE:  f_leak => defdef
 a |      b      | a |      b      |      t1_1       |      t1_2       
---+-------------+---+-------------+-----------------+-----------------
 4 | daddad_updt | 4 | daddad_updt | (4,daddad_updt) | (4,daddad_updt)
 4 | defdef      | 4 | defdef      | (4,defdef)      | (4,defdef)

RESET SESSION AUTHORIZATION;
SET row_security TO OFF;
SELECT * FROM t1 ORDER BY a,b;
 a |      b      
---+-------------
 1 | aba
 1 | abc
 1 | xxx
 2 | bbbbbb_updt
 2 | bcdbcd
 2 | yyyyyy
 3 | ccc
 3 | cde
 3 | zzz
 4 | daddad_updt
 4 | defdef

SET SESSION AUTHORIZATION regress_rls_bob;
SET row_security TO ON;
EXPLAIN (BUFFERS OFF, COSTS OFF) DELETE FROM only t1 WHERE f_leak(b);
--- QUERY PLAN ---
 Delete on t1
   ->  Seq Scan on t1
         Filter: (((a % 2) = 0) AND f_leak(b))

EXPLAIN (BUFFERS OFF, COSTS OFF) DELETE FROM t1 WHERE f_leak(b);
--- QUERY PLAN ---
 Delete on t1
   Delete on t1 t1_1
   Delete on t2 t1_2
   Delete on t3 t1_3
   ->  Append
         ->  Seq Scan on t1 t1_1
               Filter: (((a % 2) = 0) AND f_leak(b))
         ->  Seq Scan on t2 t1_2
               Filter: (((a % 2) = 0) AND f_leak(b))
         ->  Seq Scan on t3 t1_3
               Filter: (((a % 2) = 0) AND f_leak(b))

DELETE FROM only t1 WHERE f_leak(b) RETURNING ctid, *, t1;
NOTICE:  f_leak => bbbbbb_updt
NOTICE:  f_leak => daddad_updt
  ctid  | a |      b      |       t1        
--------+---+-------------+-----------------
 (0,13) | 2 | bbbbbb_updt | (2,bbbbbb_updt)
 (0,15) | 4 | daddad_updt | (4,daddad_updt)

DELETE FROM t1 WHERE f_leak(b) RETURNING ctid, *, t1;
NOTICE:  f_leak => bcdbcd
NOTICE:  f_leak => defdef
NOTICE:  f_leak => yyyyyy
  ctid  | a |   b    |     t1     
--------+---+--------+------------
 (0,9)  | 2 | bcdbcd | (2,bcdbcd)
 (0,13) | 4 | defdef | (4,defdef)
 (0,6)  | 2 | yyyyyy | (2,yyyyyy)

--
-- S.b. view on top of Row-level security
--
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE b1 (a int, b text);
SELECT public.create_hypertable('b1', 'a', chunk_time_interval=>2);
      create_hypertable      
-----------------------------
 (8,regress_rls_schema,b1,t)

INSERT INTO b1 (SELECT x, md5(x::text) FROM generate_series(-10,10) x);
CREATE POLICY p1 ON b1 USING (a % 2 = 0);
ALTER TABLE b1 ENABLE ROW LEVEL SECURITY;
GRANT ALL ON b1 TO regress_rls_bob;
SET SESSION AUTHORIZATION regress_rls_bob;
CREATE VIEW bv1 WITH (security_barrier) AS SELECT * FROM b1 WHERE a > 0 WITH CHECK OPTION;
GRANT ALL ON bv1 TO regress_rls_carol;
SET SESSION AUTHORIZATION regress_rls_carol;
EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM bv1 WHERE f_leak(b);
--- QUERY PLAN ---
 Subquery Scan on bv1
   Filter: f_leak(bv1.b)
   ->  Append
         ->  Seq Scan on b1 b1_1
               Filter: ((a > 0) AND ((a % 2) = 0))
         ->  Index Scan using _hyper_8_39_chunk_b1_a_idx on _hyper_8_39_chunk b1_2
               Index Cond: (a > 0)
               Filter: ((a % 2) = 0)
         ->  Index Scan using _hyper_8_40_chunk_b1_a_idx on _hyper_8_40_chunk b1_3
               Index Cond: (a > 0)
               Filter: ((a % 2) = 0)
         ->  Index Scan using _hyper_8_41_chunk_b1_a_idx on _hyper_8_41_chunk b1_4
               Index Cond: (a > 0)
               Filter: ((a % 2) = 0)
         ->  Index Scan using _hyper_8_42_chunk_b1_a_idx on _hyper_8_42_chunk b1_5
               Index Cond: (a > 0)
               Filter: ((a % 2) = 0)
         ->  Index Scan using _hyper_8_43_chunk_b1_a_idx on _hyper_8_43_chunk b1_6
               Index Cond: (a > 0)
               Filter: ((a % 2) = 0)
         ->  Index Scan using _hyper_8_44_chunk_b1_a_idx on _hyper_8_44_chunk b1_7
               Index Cond: (a > 0)
               Filter: ((a % 2) = 0)

SELECT * FROM bv1 WHERE f_leak(b);
NOTICE:  f_leak => c81e728d9d4c2f636f067f89cc14862c
NOTICE:  f_leak => a87ff679a2f3e71d9181a67b7542122c
NOTICE:  f_leak => 1679091c5a880faf6fb5e6087eb1b2dc
NOTICE:  f_leak => c9f0f895fb98ab9159f51fd0297e236d
NOTICE:  f_leak => d3d9446802a44259755d38e6d163e820
 a  |                b                 
----+----------------------------------
  2 | c81e728d9d4c2f636f067f89cc14862c
  4 | a87ff679a2f3e71d9181a67b7542122c
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  8 | c9f0f895fb98ab9159f51fd0297e236d
 10 | d3d9446802a44259755d38e6d163e820

INSERT INTO bv1 VALUES (-1, 'xxx'); -- should fail view WCO
ERROR:  new row violates row-level security policy for table "b1"
INSERT INTO bv1 VALUES (11, 'xxx'); -- should fail RLS check
ERROR:  new row violates row-level security policy for table "b1"
INSERT INTO bv1 VALUES (12, 'xxx'); -- ok
EXPLAIN (BUFFERS OFF, COSTS OFF) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b);
--- QUERY PLAN ---
 Custom Scan (ModifyHypertable)
   ->  Update on b1
         Update on _hyper_8_41_chunk b1_1
         ->  Result
               ->  Custom Scan (ChunkAppend) on b1
                     Chunks excluded during startup: 0
                     ->  Index Scan using _hyper_8_41_chunk_b1_a_idx on _hyper_8_41_chunk b1_1
                           Index Cond: ((a > 0) AND (a = 4))
                           Filter: (((a % 2) = 0) AND f_leak(b))

UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b);
NOTICE:  f_leak => a87ff679a2f3e71d9181a67b7542122c
EXPLAIN (BUFFERS OFF, COSTS OFF) DELETE FROM bv1 WHERE a = 6 AND f_leak(b);
--- QUERY PLAN ---
 Custom Scan (ModifyHypertable)
   ->  Delete on b1
         Delete on _hyper_8_42_chunk b1_1
         ->  Custom Scan (ChunkAppend) on b1
               Chunks excluded during startup: 0
               ->  Index Scan using _hyper_8_42_chunk_b1_a_idx on _hyper_8_42_chunk b1_1
                     Index Cond: ((a > 0) AND (a = 6))
                     Filter: (((a % 2) = 0) AND f_leak(b))

DELETE FROM bv1 WHERE a = 6 AND f_leak(b);
NOTICE:  f_leak => 1679091c5a880faf6fb5e6087eb1b2dc
SET SESSION AUTHORIZATION regress_rls_alice;
SELECT * FROM b1;
  a  |                b                 
-----+----------------------------------
 -10 | 1b0fd9efa5279c4203b7c70233f86dbf
  -9 | 252e691406782824eec43d7eadc3d256
  -8 | a8d2ec85eaf98407310b72eb73dda247
  -7 | 74687a12d3915d3c4d83f1af7b3683d5
  -6 | 596a3d04481816330f07e4f97510c28f
  -5 | 47c1b025fa18ea96c33fbb6718688c0f
  -4 | 0267aaf632e87a63288a08331f22c7c3
  -3 | b3149ecea4628efd23d2f86e5a723472
  -2 | 5d7b9adcbe1c629ec722529dd12e5129
  -1 | 6bb61e3b7bce0931da574d19d1d82c88
   0 | cfcd208495d565ef66e7dff9f98764da
   1 | c4ca4238a0b923820dcc509a6f75849b
   2 | c81e728d9d4c2f636f067f89cc14862c
   3 | eccbc87e4b5ce2fe28308fd9f2a7baf3
   5 | e4da3b7fbbce2345d7772b0674a318d5
   4 | yyy
   7 | 8f14e45fceea167a5a36dedd4bea2543
   8 | c9f0f895fb98ab9159f51fd0297e236d
   9 | 45c48cce2e2d7fbdea1afc51c7c6ad26
  10 | d3d9446802a44259755d38e6d163e820
  12 | xxx

--
-- INSERT ... ON CONFLICT DO UPDATE and Row-level security
--
SET SESSION AUTHORIZATION regress_rls_alice;
DROP POLICY p1 ON document;
DROP POLICY p1r ON document;
CREATE POLICY p1 ON document FOR SELECT USING (true);
CREATE POLICY p2 ON document FOR INSERT WITH CHECK (dauthor = current_user);
CREATE POLICY p3 ON document FOR UPDATE
  USING (cid = (SELECT cid from category WHERE cname = 'novel'))
  WITH CHECK (dauthor = current_user);
SET SESSION AUTHORIZATION regress_rls_bob;
-- Exists...
SELECT * FROM document WHERE did = 2;
 did | cid | dlevel |     dauthor     |     dtitle      
-----+-----+--------+-----------------+-----------------
   2 |  11 |      2 | regress_rls_bob | my second novel

-- ...so violates actual WITH CHECK OPTION within UPDATE (not INSERT, since
-- alternative UPDATE path happens to be taken):
INSERT INTO document VALUES (2, (SELECT cid from category WHERE cname = 'novel'), 1, 'regress_rls_carol', 'my first novel')
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle, dauthor = EXCLUDED.dauthor;
ERROR:  new row violates row-level security policy for table "document"
-- Violates USING qual for UPDATE policy p3.
--
-- UPDATE path is taken, but UPDATE fails purely because *existing* row to be
-- updated is not a "novel"/cid 11 (row is not leaked, even though we have
-- SELECT privileges sufficient to see the row in this instance):
INSERT INTO document VALUES (33, 22, 1, 'regress_rls_bob', 'okay science fiction'); -- preparation for next statement
INSERT INTO document VALUES (33, (SELECT cid from category WHERE cname = 'novel'), 1, 'regress_rls_bob', 'Some novel, replaces sci-fi') -- takes UPDATE path
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle;
ERROR:  new row violates row-level security policy (USING expression) for table "document"
-- Fine (we UPDATE, since INSERT WCOs and UPDATE security barrier quals + WCOs
-- not violated):
INSERT INTO document VALUES (2, (SELECT cid from category WHERE cname = 'novel'), 1, 'regress_rls_bob', 'my first novel')
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle RETURNING *;
 did | cid | dlevel |     dauthor     |     dtitle     
-----+-----+--------+-----------------+----------------
   2 |  11 |      2 | regress_rls_bob | my first novel

-- Fine (we INSERT, so "cid = 33" ("technology") isn't evaluated):
INSERT INTO document VALUES (78, (SELECT cid from category WHERE cname = 'novel'), 1, 'regress_rls_bob', 'some technology novel')
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle, cid = 33 RETURNING *;
 did | cid | dlevel |     dauthor     |        dtitle         
-----+-----+--------+-----------------+-----------------------
  78 |  11 |      1 | regress_rls_bob | some technology novel

-- Fine (same query, but we UPDATE, so "cid = 33", ("technology") is not the
-- case in respect of *existing* tuple):
INSERT INTO document VALUES (78, (SELECT cid from category WHERE cname = 'novel'), 1, 'regress_rls_bob', 'some technology novel')
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle, cid = 33 RETURNING *;
 did | cid | dlevel |     dauthor     |        dtitle         
-----+-----+--------+-----------------+-----------------------
  78 |  33 |      1 | regress_rls_bob | some technology novel

-- Same query a third time, but now fails due to existing tuple finally not
-- passing quals:
INSERT INTO document VALUES (78, (SELECT cid from category WHERE cname = 'novel'), 1, 'regress_rls_bob', 'some technology novel')
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle, cid = 33 RETURNING *;
ERROR:  new row violates row-level security policy (USING expression) for table "document"
-- Don't fail just because INSERT doesn't satisfy WITH CHECK option that
-- originated as a barrier/USING() qual from the UPDATE.  Note that the UPDATE
-- path *isn't* taken, and so UPDATE-related policy does not apply:
INSERT INTO document VALUES (79, (SELECT cid from category WHERE cname = 'technology'), 1, 'regress_rls_bob', 'technology book, can only insert')
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle RETURNING *;
 did | cid | dlevel |     dauthor     |              dtitle              
-----+-----+--------+-----------------+----------------------------------
  79 |  33 |      1 | regress_rls_bob | technology book, can only insert

-- But this time, the same statement fails, because the UPDATE path is taken,
-- and updating the row just inserted falls afoul of security barrier qual
-- (enforced as WCO) -- what we might have updated target tuple to is
-- irrelevant, in fact.
INSERT INTO document VALUES (79, (SELECT cid from category WHERE cname = 'technology'), 1, 'regress_rls_bob', 'technology book, can only insert')
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle RETURNING *;
ERROR:  new row violates row-level security policy (USING expression) for table "document"
-- Test default USING qual enforced as WCO
SET SESSION AUTHORIZATION regress_rls_alice;
DROP POLICY p1 ON document;
DROP POLICY p2 ON document;
DROP POLICY p3 ON document;
CREATE POLICY p3_with_default ON document FOR UPDATE
  USING (cid = (SELECT cid from category WHERE cname = 'novel'));
SET SESSION AUTHORIZATION regress_rls_bob;
-- Just because WCO-style enforcement of USING quals occurs with
-- existing/target tuple does not mean that the implementation can be allowed
-- to fail to also enforce this qual against the final tuple appended to
-- relation (since in the absence of an explicit WCO, this is also interpreted
-- as an UPDATE/ALL WCO in general).
--
-- UPDATE path is taken here (fails due to existing tuple).  Note that this is
-- not reported as a "USING expression", because it's an RLS UPDATE check that originated as
-- a USING qual for the purposes of RLS in general, as opposed to an explicit
-- USING qual that is ordinarily a security barrier.  We leave it up to the
-- UPDATE to make this fail:
INSERT INTO document VALUES (79, (SELECT cid from category WHERE cname = 'technology'), 1, 'regress_rls_bob', 'technology book, can only insert')
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle RETURNING *;
ERROR:  new row violates row-level security policy for table "document"
-- UPDATE path is taken here.  Existing tuple passes, since it's cid
-- corresponds to "novel", but default USING qual is enforced against
-- post-UPDATE tuple too (as always when updating with a policy that lacks an
-- explicit WCO), and so this fails:
INSERT INTO document VALUES (2, (SELECT cid from category WHERE cname = 'technology'), 1, 'regress_rls_bob', 'my first novel')
    ON CONFLICT (did) DO UPDATE SET cid = EXCLUDED.cid, dtitle = EXCLUDED.dtitle RETURNING *;
ERROR:  new row violates row-level security policy for table "document"
SET SESSION AUTHORIZATION regress_rls_alice;
DROP POLICY p3_with_default ON document;
--
-- Test ALL policies with ON CONFLICT DO UPDATE (much the same as existing UPDATE
-- tests)
--
CREATE POLICY p3_with_all ON document FOR ALL
  USING (cid = (SELECT cid from category WHERE cname = 'novel'))
  WITH CHECK (dauthor = current_user);
SET SESSION AUTHORIZATION regress_rls_bob;
-- Fails, since ALL WCO is enforced in insert path:
INSERT INTO document VALUES (80, (SELECT cid from category WHERE cname = 'novel'), 1, 'regress_rls_carol', 'my first novel')
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle, cid = 33;
ERROR:  new row violates row-level security policy for table "document"
-- Fails, since ALL policy USING qual is enforced (existing, target tuple is in
-- violation, since it has the "manga" cid):
INSERT INTO document VALUES (4, (SELECT cid from category WHERE cname = 'novel'), 1, 'regress_rls_bob', 'my first novel')
    ON CONFLICT (did) DO UPDATE SET dtitle = EXCLUDED.dtitle;
ERROR:  new row violates row-level security policy (USING expression) for table "document"
-- Fails, since ALL WCO are enforced:
INSERT INTO document VALUES (1, (SELECT cid from category WHERE cname = 'novel'), 1, 'regress_rls_bob', 'my first novel')
    ON CONFLICT (did) DO UPDATE SET dauthor = 'regress_rls_carol';
ERROR:  new row violates row-level security policy for table "document"
--
-- ROLE/GROUP
--
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE z1 (a int, b text);
SELECT public.create_hypertable('z1', 'a', chunk_time_interval=>2);
      create_hypertable      
-----------------------------
 (9,regress_rls_schema,z1,t)

CREATE TABLE z2 (a int, b text);
SELECT public.create_hypertable('z2', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (10,regress_rls_schema,z2,t)

GRANT SELECT ON z1,z2 TO regress_rls_group1, regress_rls_group2,
    regress_rls_bob, regress_rls_carol;
INSERT INTO z1 VALUES
    (1, 'aba'),
    (2, 'bbb'),
    (3, 'ccc'),
    (4, 'dad');
CREATE POLICY p1 ON z1 TO regress_rls_group1 USING (a % 2 = 0);
CREATE POLICY p2 ON z1 TO regress_rls_group2 USING (a % 2 = 1);
ALTER TABLE z1 ENABLE ROW LEVEL SECURITY;
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM z1 WHERE f_leak(b);
NOTICE:  f_leak => bbb
NOTICE:  f_leak => dad
 a |  b  
---+-----
 2 | bbb
 4 | dad

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 0) AND f_leak(b))

PREPARE plancache_test AS SELECT * FROM z1 WHERE f_leak(b);
EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 0) AND f_leak(b))

PREPARE plancache_test2 AS WITH q AS MATERIALIZED (SELECT * FROM z1 WHERE f_leak(b)) SELECT * FROM q,z2;
EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test2;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Custom Scan (ChunkAppend) on z1
           Chunks excluded during startup: 0
           ->  Seq Scan on z1 z1_1
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_49_chunk z1_2
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_50_chunk z1_3
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_51_chunk z1_4
                 Filter: (((a % 2) = 0) AND f_leak(b))
   ->  CTE Scan on q
   ->  Materialize
         ->  Seq Scan on z2

PREPARE plancache_test4 AS WITH q AS (SELECT * FROM z1 WHERE f_leak(b)) SELECT * FROM q,z2;
EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test4;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Custom Scan (ChunkAppend) on z1
           Chunks excluded during startup: 0
           ->  Seq Scan on z1 z1_1
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_49_chunk z1_2
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_50_chunk z1_3
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_51_chunk z1_4
                 Filter: (((a % 2) = 0) AND f_leak(b))
   ->  CTE Scan on q
   ->  Materialize
         ->  Seq Scan on z2

PREPARE plancache_test6 AS WITH q AS NOT MATERIALIZED (SELECT * FROM z1 WHERE f_leak(b)) SELECT * FROM q,z2;
EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test6;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Custom Scan (ChunkAppend) on z1
           Chunks excluded during startup: 0
           ->  Seq Scan on z1 z1_1
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_49_chunk z1_2
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_50_chunk z1_3
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_51_chunk z1_4
                 Filter: (((a % 2) = 0) AND f_leak(b))
   ->  CTE Scan on q
   ->  Materialize
         ->  Seq Scan on z2

PREPARE plancache_test3 AS WITH q AS MATERIALIZED (SELECT * FROM z2) SELECT * FROM q,z1 WHERE f_leak(z1.b);
EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test3;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Seq Scan on z2
   ->  CTE Scan on q
   ->  Materialize
         ->  Custom Scan (ChunkAppend) on z1
               Chunks excluded during startup: 0
               ->  Seq Scan on z1 z1_1
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_49_chunk z1_2
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_50_chunk z1_3
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_51_chunk z1_4
                     Filter: (((a % 2) = 0) AND f_leak(b))

PREPARE plancache_test5 AS WITH q AS (SELECT * FROM z2) SELECT * FROM q,z1 WHERE f_leak(z1.b);
EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test5;
--- QUERY PLAN ---
 Nested Loop
   ->  Seq Scan on z2
   ->  Materialize
         ->  Custom Scan (ChunkAppend) on z1
               Chunks excluded during startup: 0
               ->  Seq Scan on z1 z1_1
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_49_chunk z1_2
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_50_chunk z1_3
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_51_chunk z1_4
                     Filter: (((a % 2) = 0) AND f_leak(b))

PREPARE plancache_test7 AS WITH q AS NOT MATERIALIZED (SELECT * FROM z2) SELECT * FROM q,z1 WHERE f_leak(z1.b);
EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test7;
--- QUERY PLAN ---
 Nested Loop
   ->  Seq Scan on z2
   ->  Materialize
         ->  Custom Scan (ChunkAppend) on z1
               Chunks excluded during startup: 0
               ->  Seq Scan on z1 z1_1
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_49_chunk z1_2
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_50_chunk z1_3
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_51_chunk z1_4
                     Filter: (((a % 2) = 0) AND f_leak(b))

SET ROLE regress_rls_group1;
SELECT * FROM z1 WHERE f_leak(b);
NOTICE:  f_leak => bbb
NOTICE:  f_leak => dad
 a |  b  
---+-----
 2 | bbb
 4 | dad

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 0) AND f_leak(b))

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 0) AND f_leak(b))

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test2;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Custom Scan (ChunkAppend) on z1
           Chunks excluded during startup: 0
           ->  Seq Scan on z1 z1_1
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_49_chunk z1_2
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_50_chunk z1_3
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_51_chunk z1_4
                 Filter: (((a % 2) = 0) AND f_leak(b))
   ->  CTE Scan on q
   ->  Materialize
         ->  Seq Scan on z2

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test4;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Custom Scan (ChunkAppend) on z1
           Chunks excluded during startup: 0
           ->  Seq Scan on z1 z1_1
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_49_chunk z1_2
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_50_chunk z1_3
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_9_51_chunk z1_4
                 Filter: (((a % 2) = 0) AND f_leak(b))
   ->  CTE Scan on q
   ->  Materialize
         ->  Seq Scan on z2

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test3;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Seq Scan on z2
   ->  CTE Scan on q
   ->  Materialize
         ->  Custom Scan (ChunkAppend) on z1
               Chunks excluded during startup: 0
               ->  Seq Scan on z1 z1_1
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_49_chunk z1_2
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_50_chunk z1_3
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_51_chunk z1_4
                     Filter: (((a % 2) = 0) AND f_leak(b))

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test5;
--- QUERY PLAN ---
 Nested Loop
   ->  Seq Scan on z2
   ->  Materialize
         ->  Custom Scan (ChunkAppend) on z1
               Chunks excluded during startup: 0
               ->  Seq Scan on z1 z1_1
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_49_chunk z1_2
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_50_chunk z1_3
                     Filter: (((a % 2) = 0) AND f_leak(b))
               ->  Seq Scan on _hyper_9_51_chunk z1_4
                     Filter: (((a % 2) = 0) AND f_leak(b))

SET SESSION AUTHORIZATION regress_rls_carol;
SELECT * FROM z1 WHERE f_leak(b);
NOTICE:  f_leak => aba
NOTICE:  f_leak => ccc
 a |  b  
---+-----
 1 | aba
 3 | ccc

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 1) AND f_leak(b))

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 1) AND f_leak(b))

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test2;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Custom Scan (ChunkAppend) on z1
           Chunks excluded during startup: 0
           ->  Seq Scan on z1 z1_1
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_49_chunk z1_2
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_50_chunk z1_3
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_51_chunk z1_4
                 Filter: (((a % 2) = 1) AND f_leak(b))
   ->  CTE Scan on q
   ->  Materialize
         ->  Seq Scan on z2

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test4;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Custom Scan (ChunkAppend) on z1
           Chunks excluded during startup: 0
           ->  Seq Scan on z1 z1_1
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_49_chunk z1_2
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_50_chunk z1_3
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_51_chunk z1_4
                 Filter: (((a % 2) = 1) AND f_leak(b))
   ->  CTE Scan on q
   ->  Materialize
         ->  Seq Scan on z2

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test3;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Seq Scan on z2
   ->  CTE Scan on q
   ->  Materialize
         ->  Custom Scan (ChunkAppend) on z1
               Chunks excluded during startup: 0
               ->  Seq Scan on z1 z1_1
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_49_chunk z1_2
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_50_chunk z1_3
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_51_chunk z1_4
                     Filter: (((a % 2) = 1) AND f_leak(b))

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test5;
--- QUERY PLAN ---
 Nested Loop
   ->  Seq Scan on z2
   ->  Materialize
         ->  Custom Scan (ChunkAppend) on z1
               Chunks excluded during startup: 0
               ->  Seq Scan on z1 z1_1
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_49_chunk z1_2
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_50_chunk z1_3
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_51_chunk z1_4
                     Filter: (((a % 2) = 1) AND f_leak(b))

SET ROLE regress_rls_group2;
SELECT * FROM z1 WHERE f_leak(b);
NOTICE:  f_leak => aba
NOTICE:  f_leak => ccc
 a |  b  
---+-----
 1 | aba
 3 | ccc

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 1) AND f_leak(b))

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 1) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 1) AND f_leak(b))

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test2;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Custom Scan (ChunkAppend) on z1
           Chunks excluded during startup: 0
           ->  Seq Scan on z1 z1_1
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_49_chunk z1_2
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_50_chunk z1_3
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_51_chunk z1_4
                 Filter: (((a % 2) = 1) AND f_leak(b))
   ->  CTE Scan on q
   ->  Materialize
         ->  Seq Scan on z2

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test4;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Custom Scan (ChunkAppend) on z1
           Chunks excluded during startup: 0
           ->  Seq Scan on z1 z1_1
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_49_chunk z1_2
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_50_chunk z1_3
                 Filter: (((a % 2) = 1) AND f_leak(b))
           ->  Seq Scan on _hyper_9_51_chunk z1_4
                 Filter: (((a % 2) = 1) AND f_leak(b))
   ->  CTE Scan on q
   ->  Materialize
         ->  Seq Scan on z2

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test3;
--- QUERY PLAN ---
 Nested Loop
   CTE q
     ->  Seq Scan on z2
   ->  CTE Scan on q
   ->  Materialize
         ->  Custom Scan (ChunkAppend) on z1
               Chunks excluded during startup: 0
               ->  Seq Scan on z1 z1_1
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_49_chunk z1_2
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_50_chunk z1_3
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_51_chunk z1_4
                     Filter: (((a % 2) = 1) AND f_leak(b))

EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE plancache_test5;
--- QUERY PLAN ---
 Nested Loop
   ->  Seq Scan on z2
   ->  Materialize
         ->  Custom Scan (ChunkAppend) on z1
               Chunks excluded during startup: 0
               ->  Seq Scan on z1 z1_1
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_49_chunk z1_2
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_50_chunk z1_3
                     Filter: (((a % 2) = 1) AND f_leak(b))
               ->  Seq Scan on _hyper_9_51_chunk z1_4
                     Filter: (((a % 2) = 1) AND f_leak(b))

--
-- Views should follow policy for view owner.
--
-- View and Table owner are the same.
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE VIEW rls_view AS SELECT * FROM z1 WHERE f_leak(b);
GRANT SELECT ON rls_view TO regress_rls_bob;
-- Query as role that is not owner of view or table.  Should return all records.
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM rls_view;
NOTICE:  f_leak => aba
NOTICE:  f_leak => bbb
NOTICE:  f_leak => ccc
NOTICE:  f_leak => dad
 a |  b  
---+-----
 1 | aba
 2 | bbb
 3 | ccc
 4 | dad

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM rls_view;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: f_leak(b)
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: f_leak(b)
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: f_leak(b)
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: f_leak(b)

-- Query as view/table owner.  Should return all records.
SET SESSION AUTHORIZATION regress_rls_alice;
SELECT * FROM rls_view;
NOTICE:  f_leak => aba
NOTICE:  f_leak => bbb
NOTICE:  f_leak => ccc
NOTICE:  f_leak => dad
 a |  b  
---+-----
 1 | aba
 2 | bbb
 3 | ccc
 4 | dad

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM rls_view;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: f_leak(b)
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: f_leak(b)
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: f_leak(b)
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: f_leak(b)

DROP VIEW rls_view;
-- View and Table owners are different.
SET SESSION AUTHORIZATION regress_rls_bob;
CREATE VIEW rls_view AS SELECT * FROM z1 WHERE f_leak(b);
GRANT SELECT ON rls_view TO regress_rls_alice;
-- Query as role that is not owner of view but is owner of table.
-- Should return records based on view owner policies.
SET SESSION AUTHORIZATION regress_rls_alice;
SELECT * FROM rls_view;
NOTICE:  f_leak => bbb
NOTICE:  f_leak => dad
 a |  b  
---+-----
 2 | bbb
 4 | dad

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM rls_view;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 0) AND f_leak(b))

-- Query as role that is not owner of table but is owner of view.
-- Should return records based on view owner policies.
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM rls_view;
NOTICE:  f_leak => bbb
NOTICE:  f_leak => dad
 a |  b  
---+-----
 2 | bbb
 4 | dad

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM rls_view;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 0) AND f_leak(b))

-- Query as role that is not the owner of the table or view without permissions.
SET SESSION AUTHORIZATION regress_rls_carol;
SELECT * FROM rls_view; --fail - permission denied.
ERROR:  permission denied for view rls_view
EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM rls_view; --fail - permission denied.
ERROR:  permission denied for view rls_view
-- Query as role that is not the owner of the table or view with permissions.
SET SESSION AUTHORIZATION regress_rls_bob;
GRANT SELECT ON rls_view TO regress_rls_carol;
SELECT * FROM rls_view;
NOTICE:  f_leak => bbb
NOTICE:  f_leak => dad
 a |  b  
---+-----
 2 | bbb
 4 | dad

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM rls_view;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on z1
   Chunks excluded during startup: 0
   ->  Seq Scan on z1 z1_1
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_49_chunk z1_2
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_50_chunk z1_3
         Filter: (((a % 2) = 0) AND f_leak(b))
   ->  Seq Scan on _hyper_9_51_chunk z1_4
         Filter: (((a % 2) = 0) AND f_leak(b))

SET SESSION AUTHORIZATION regress_rls_bob;
DROP VIEW rls_view;
--
-- Command specific
--
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE x1 (a int, b text, c text);
SELECT public.create_hypertable('x1', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (11,regress_rls_schema,x1,t)

GRANT ALL ON x1 TO PUBLIC;
INSERT INTO x1 VALUES
    (1, 'abc', 'regress_rls_bob'),
    (2, 'bcd', 'regress_rls_bob'),
    (3, 'cde', 'regress_rls_carol'),
    (4, 'def', 'regress_rls_carol'),
    (5, 'efg', 'regress_rls_bob'),
    (6, 'fgh', 'regress_rls_bob'),
    (7, 'fgh', 'regress_rls_carol'),
    (8, 'fgh', 'regress_rls_carol');
CREATE POLICY p0 ON x1 FOR ALL USING (c = current_user);
CREATE POLICY p1 ON x1 FOR SELECT USING (a % 2 = 0);
CREATE POLICY p2 ON x1 FOR INSERT WITH CHECK (a % 2 = 1);
CREATE POLICY p3 ON x1 FOR UPDATE USING (a % 2 = 0);
CREATE POLICY p4 ON x1 FOR DELETE USING (a < 8);
ALTER TABLE x1 ENABLE ROW LEVEL SECURITY;
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM x1 WHERE f_leak(b) ORDER BY a ASC;
NOTICE:  f_leak => abc
NOTICE:  f_leak => bcd
NOTICE:  f_leak => def
NOTICE:  f_leak => efg
NOTICE:  f_leak => fgh
NOTICE:  f_leak => fgh
 a |  b  |         c         
---+-----+-------------------
 1 | abc | regress_rls_bob
 2 | bcd | regress_rls_bob
 4 | def | regress_rls_carol
 5 | efg | regress_rls_bob
 6 | fgh | regress_rls_bob
 8 | fgh | regress_rls_carol

UPDATE x1 SET b = b || '_updt' WHERE f_leak(b) RETURNING *;
NOTICE:  f_leak => abc
NOTICE:  f_leak => bcd
NOTICE:  f_leak => def
NOTICE:  f_leak => efg
NOTICE:  f_leak => fgh
NOTICE:  f_leak => fgh
 a |    b     |         c         
---+----------+-------------------
 1 | abc_updt | regress_rls_bob
 2 | bcd_updt | regress_rls_bob
 4 | def_updt | regress_rls_carol
 5 | efg_updt | regress_rls_bob
 6 | fgh_updt | regress_rls_bob
 8 | fgh_updt | regress_rls_carol

SET SESSION AUTHORIZATION regress_rls_carol;
SELECT * FROM x1 WHERE f_leak(b) ORDER BY a ASC;
NOTICE:  f_leak => cde
NOTICE:  f_leak => bcd_updt
NOTICE:  f_leak => def_updt
NOTICE:  f_leak => fgh
NOTICE:  f_leak => fgh_updt
NOTICE:  f_leak => fgh_updt
 a |    b     |         c         
---+----------+-------------------
 2 | bcd_updt | regress_rls_bob
 3 | cde      | regress_rls_carol
 4 | def_updt | regress_rls_carol
 6 | fgh_updt | regress_rls_bob
 7 | fgh      | regress_rls_carol
 8 | fgh_updt | regress_rls_carol

UPDATE x1 SET b = b || '_updt' WHERE f_leak(b) RETURNING *;
NOTICE:  f_leak => cde
NOTICE:  f_leak => bcd_updt
NOTICE:  f_leak => def_updt
NOTICE:  f_leak => fgh
NOTICE:  f_leak => fgh_updt
NOTICE:  f_leak => fgh_updt
 a |       b       |         c         
---+---------------+-------------------
 3 | cde_updt      | regress_rls_carol
 2 | bcd_updt_updt | regress_rls_bob
 4 | def_updt_updt | regress_rls_carol
 7 | fgh_updt      | regress_rls_carol
 6 | fgh_updt_updt | regress_rls_bob
 8 | fgh_updt_updt | regress_rls_carol

DELETE FROM x1 WHERE f_leak(b) RETURNING *;
NOTICE:  f_leak => cde_updt
NOTICE:  f_leak => bcd_updt_updt
NOTICE:  f_leak => def_updt_updt
NOTICE:  f_leak => fgh_updt
NOTICE:  f_leak => fgh_updt_updt
NOTICE:  f_leak => fgh_updt_updt
 a |       b       |         c         
---+---------------+-------------------
 3 | cde_updt      | regress_rls_carol
 2 | bcd_updt_updt | regress_rls_bob
 4 | def_updt_updt | regress_rls_carol
 7 | fgh_updt      | regress_rls_carol
 6 | fgh_updt_updt | regress_rls_bob
 8 | fgh_updt_updt | regress_rls_carol

--
-- Duplicate Policy Names
--
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE y1 (a int, b text);
SELECT public.create_hypertable('y1', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (12,regress_rls_schema,y1,t)

INSERT INTO y1 VALUES(1,2);
CREATE TABLE y2 (a int, b text);
SELECT public.create_hypertable('y2', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (13,regress_rls_schema,y2,t)

GRANT ALL ON y1, y2 TO regress_rls_bob;
CREATE POLICY p1 ON y1 FOR ALL USING (a % 2 = 0);
CREATE POLICY p2 ON y1 FOR SELECT USING (a > 2);
CREATE POLICY p1 ON y1 FOR SELECT USING (a % 2 = 1);  --fail
ERROR:  policy "p1" for table "y1" already exists
CREATE POLICY p1 ON y2 FOR ALL USING (a % 2 = 0);  --OK
ALTER TABLE y1 ENABLE ROW LEVEL SECURITY;
ALTER TABLE y2 ENABLE ROW LEVEL SECURITY;
--
-- Expression structure with SBV
--
-- Create view as table owner.  RLS should NOT be applied.
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE VIEW rls_sbv WITH (security_barrier) AS
    SELECT * FROM y1 WHERE f_leak(b);
EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM rls_sbv WHERE (a = 1);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on y1
   Chunks excluded during startup: 0
   ->  Seq Scan on y1 y1_1
         Filter: (f_leak(b) AND (a = 1))
   ->  Index Scan using _hyper_12_57_chunk_y1_a_idx on _hyper_12_57_chunk y1_2
         Index Cond: (a = 1)
         Filter: f_leak(b)

DROP VIEW rls_sbv;
-- Create view as role that does not own table.  RLS should be applied.
SET SESSION AUTHORIZATION regress_rls_bob;
CREATE VIEW rls_sbv WITH (security_barrier) AS
    SELECT * FROM y1 WHERE f_leak(b);
EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM rls_sbv WHERE (a = 1);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on y1
   Chunks excluded during startup: 0
   ->  Seq Scan on y1 y1_1
         Filter: ((a = 1) AND ((a > 2) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Index Scan using _hyper_12_57_chunk_y1_a_idx on _hyper_12_57_chunk y1_2
         Index Cond: (a = 1)
         Filter: (((a > 2) OR ((a % 2) = 0)) AND f_leak(b))

DROP VIEW rls_sbv;
--
-- Expression structure
--
SET SESSION AUTHORIZATION regress_rls_alice;
INSERT INTO y2 (SELECT x, md5(x::text) FROM generate_series(0,20) x);
CREATE POLICY p2 ON y2 USING (a % 3 = 0);
CREATE POLICY p3 ON y2 USING (a % 4 = 0);
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM y2 WHERE f_leak(b);
NOTICE:  f_leak => cfcd208495d565ef66e7dff9f98764da
NOTICE:  f_leak => c81e728d9d4c2f636f067f89cc14862c
NOTICE:  f_leak => eccbc87e4b5ce2fe28308fd9f2a7baf3
NOTICE:  f_leak => a87ff679a2f3e71d9181a67b7542122c
NOTICE:  f_leak => 1679091c5a880faf6fb5e6087eb1b2dc
NOTICE:  f_leak => c9f0f895fb98ab9159f51fd0297e236d
NOTICE:  f_leak => 45c48cce2e2d7fbdea1afc51c7c6ad26
NOTICE:  f_leak => d3d9446802a44259755d38e6d163e820
NOTICE:  f_leak => c20ad4d76fe97759aa27a0c99bff6710
NOTICE:  f_leak => aab3238922bcc25a6f606eb525ffdc56
NOTICE:  f_leak => 9bf31c7ff062936a96d3c8bd1f8f2ff3
NOTICE:  f_leak => c74d97b01eae257e44aa9d5bade97baf
NOTICE:  f_leak => 6f4922f45568161a8cdf4ad2299f6d23
NOTICE:  f_leak => 98f13708210194c475687be6106a3b84
 a  |                b                 
----+----------------------------------
  0 | cfcd208495d565ef66e7dff9f98764da
  2 | c81e728d9d4c2f636f067f89cc14862c
  3 | eccbc87e4b5ce2fe28308fd9f2a7baf3
  4 | a87ff679a2f3e71d9181a67b7542122c
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  8 | c9f0f895fb98ab9159f51fd0297e236d
  9 | 45c48cce2e2d7fbdea1afc51c7c6ad26
 10 | d3d9446802a44259755d38e6d163e820
 12 | c20ad4d76fe97759aa27a0c99bff6710
 14 | aab3238922bcc25a6f606eb525ffdc56
 15 | 9bf31c7ff062936a96d3c8bd1f8f2ff3
 16 | c74d97b01eae257e44aa9d5bade97baf
 18 | 6f4922f45568161a8cdf4ad2299f6d23
 20 | 98f13708210194c475687be6106a3b84

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM y2 WHERE f_leak(b);
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on y2
   Chunks excluded during startup: 0
   ->  Seq Scan on y2 y2_1
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_58_chunk y2_2
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_59_chunk y2_3
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_60_chunk y2_4
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_61_chunk y2_5
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_62_chunk y2_6
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_63_chunk y2_7
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_64_chunk y2_8
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_65_chunk y2_9
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_66_chunk y2_10
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_67_chunk y2_11
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
   ->  Seq Scan on _hyper_13_68_chunk y2_12
         Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))

--
-- Qual push-down of leaky functions, when not referring to table
--
SELECT * FROM y2 WHERE f_leak('abc');
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
NOTICE:  f_leak => abc
 a  |                b                 
----+----------------------------------
  0 | cfcd208495d565ef66e7dff9f98764da
  2 | c81e728d9d4c2f636f067f89cc14862c
  3 | eccbc87e4b5ce2fe28308fd9f2a7baf3
  4 | a87ff679a2f3e71d9181a67b7542122c
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  8 | c9f0f895fb98ab9159f51fd0297e236d
  9 | 45c48cce2e2d7fbdea1afc51c7c6ad26
 10 | d3d9446802a44259755d38e6d163e820
 12 | c20ad4d76fe97759aa27a0c99bff6710
 14 | aab3238922bcc25a6f606eb525ffdc56
 15 | 9bf31c7ff062936a96d3c8bd1f8f2ff3
 16 | c74d97b01eae257e44aa9d5bade97baf
 18 | 6f4922f45568161a8cdf4ad2299f6d23
 20 | 98f13708210194c475687be6106a3b84

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM y2 WHERE f_leak('abc');
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on y2
   Chunks excluded during startup: 0
   ->  Seq Scan on y2 y2_1
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_58_chunk y2_2
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_59_chunk y2_3
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_60_chunk y2_4
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_61_chunk y2_5
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_62_chunk y2_6
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_63_chunk y2_7
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_64_chunk y2_8
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_65_chunk y2_9
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_66_chunk y2_10
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_67_chunk y2_11
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))
   ->  Seq Scan on _hyper_13_68_chunk y2_12
         Filter: (f_leak('abc'::text) AND (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)))

CREATE TABLE test_qual_pushdown (
    abc text
);
INSERT INTO test_qual_pushdown VALUES ('abc'),('def');
SELECT * FROM y2 JOIN test_qual_pushdown ON (b = abc) WHERE f_leak(abc);
NOTICE:  f_leak => abc
NOTICE:  f_leak => def
 a | b | abc 
---+---+-----

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM y2 JOIN test_qual_pushdown ON (b = abc) WHERE f_leak(abc);
--- QUERY PLAN ---
 Hash Join
   Hash Cond: (y2.b = test_qual_pushdown.abc)
   ->  Append
         ->  Seq Scan on y2 y2_1
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_58_chunk y2_2
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_59_chunk y2_3
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_60_chunk y2_4
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_61_chunk y2_5
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_62_chunk y2_6
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_63_chunk y2_7
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_64_chunk y2_8
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_65_chunk y2_9
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_66_chunk y2_10
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_67_chunk y2_11
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
         ->  Seq Scan on _hyper_13_68_chunk y2_12
               Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0))
   ->  Hash
         ->  Seq Scan on test_qual_pushdown
               Filter: f_leak(abc)

SELECT * FROM y2 JOIN test_qual_pushdown ON (b = abc) WHERE f_leak(b);
NOTICE:  f_leak => cfcd208495d565ef66e7dff9f98764da
NOTICE:  f_leak => c81e728d9d4c2f636f067f89cc14862c
NOTICE:  f_leak => eccbc87e4b5ce2fe28308fd9f2a7baf3
NOTICE:  f_leak => a87ff679a2f3e71d9181a67b7542122c
NOTICE:  f_leak => 1679091c5a880faf6fb5e6087eb1b2dc
NOTICE:  f_leak => c9f0f895fb98ab9159f51fd0297e236d
NOTICE:  f_leak => 45c48cce2e2d7fbdea1afc51c7c6ad26
NOTICE:  f_leak => d3d9446802a44259755d38e6d163e820
NOTICE:  f_leak => c20ad4d76fe97759aa27a0c99bff6710
NOTICE:  f_leak => aab3238922bcc25a6f606eb525ffdc56
NOTICE:  f_leak => 9bf31c7ff062936a96d3c8bd1f8f2ff3
NOTICE:  f_leak => c74d97b01eae257e44aa9d5bade97baf
NOTICE:  f_leak => 6f4922f45568161a8cdf4ad2299f6d23
NOTICE:  f_leak => 98f13708210194c475687be6106a3b84
 a | b | abc 
---+---+-----

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM y2 JOIN test_qual_pushdown ON (b = abc) WHERE f_leak(b);
--- QUERY PLAN ---
 Hash Join
   Hash Cond: (test_qual_pushdown.abc = y2.b)
   ->  Seq Scan on test_qual_pushdown
   ->  Hash
         ->  Custom Scan (ChunkAppend) on y2
               Chunks excluded during startup: 0
               ->  Seq Scan on y2 y2_1
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_58_chunk y2_2
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_59_chunk y2_3
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_60_chunk y2_4
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_61_chunk y2_5
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_62_chunk y2_6
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_63_chunk y2_7
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_64_chunk y2_8
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_65_chunk y2_9
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_66_chunk y2_10
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_67_chunk y2_11
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))
               ->  Seq Scan on _hyper_13_68_chunk y2_12
                     Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b))

DROP TABLE test_qual_pushdown;
--
-- Plancache invalidate on user change.
--
RESET SESSION AUTHORIZATION;
\set VERBOSITY terse \\ -- suppress cascade details
DROP TABLE t1 CASCADE;
NOTICE:  drop cascades to 2 other objects
\set VERBOSITY default
CREATE TABLE t1 (a integer);
SELECT public.create_hypertable('t1', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (14,regress_rls_schema,t1,t)

GRANT SELECT ON t1 TO regress_rls_bob, regress_rls_carol;
CREATE POLICY p1 ON t1 TO regress_rls_bob USING ((a % 2) = 0);
CREATE POLICY p2 ON t1 TO regress_rls_carol USING ((a % 4) = 0);
ALTER TABLE t1 ENABLE ROW LEVEL SECURITY;
-- Prepare as regress_rls_bob
SET ROLE regress_rls_bob;
PREPARE role_inval AS SELECT * FROM t1;
-- Check plan
EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE role_inval;
--- QUERY PLAN ---
 Seq Scan on t1
   Filter: ((a % 2) = 0)

-- Change to regress_rls_carol
SET ROLE regress_rls_carol;
-- Check plan- should be different
EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE role_inval;
--- QUERY PLAN ---
 Seq Scan on t1
   Filter: ((a % 4) = 0)

-- Change back to regress_rls_bob
SET ROLE regress_rls_bob;
-- Check plan- should be back to original
EXPLAIN (BUFFERS OFF, COSTS OFF) EXECUTE role_inval;
--- QUERY PLAN ---
 Seq Scan on t1
   Filter: ((a % 2) = 0)

--
-- CTE and RLS
--
RESET SESSION AUTHORIZATION;
DROP TABLE t1 CASCADE;
CREATE TABLE t1 (a integer, b text);
SELECT public.create_hypertable('t1', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (15,regress_rls_schema,t1,t)

CREATE POLICY p1 ON t1 USING (a % 2 = 0);
ALTER TABLE t1 ENABLE ROW LEVEL SECURITY;
GRANT ALL ON t1 TO regress_rls_bob;
INSERT INTO t1 (SELECT x, md5(x::text) FROM generate_series(0,20) x);
SET SESSION AUTHORIZATION regress_rls_bob;
WITH cte1 AS (SELECT * FROM t1 WHERE f_leak(b)) SELECT * FROM cte1;
NOTICE:  f_leak => cfcd208495d565ef66e7dff9f98764da
NOTICE:  f_leak => c81e728d9d4c2f636f067f89cc14862c
NOTICE:  f_leak => a87ff679a2f3e71d9181a67b7542122c
NOTICE:  f_leak => 1679091c5a880faf6fb5e6087eb1b2dc
NOTICE:  f_leak => c9f0f895fb98ab9159f51fd0297e236d
NOTICE:  f_leak => d3d9446802a44259755d38e6d163e820
NOTICE:  f_leak => c20ad4d76fe97759aa27a0c99bff6710
NOTICE:  f_leak => aab3238922bcc25a6f606eb525ffdc56
NOTICE:  f_leak => c74d97b01eae257e44aa9d5bade97baf
NOTICE:  f_leak => 6f4922f45568161a8cdf4ad2299f6d23
NOTICE:  f_leak => 98f13708210194c475687be6106a3b84
 a  |                b                 
----+----------------------------------
  0 | cfcd208495d565ef66e7dff9f98764da
  2 | c81e728d9d4c2f636f067f89cc14862c
  4 | a87ff679a2f3e71d9181a67b7542122c
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  8 | c9f0f895fb98ab9159f51fd0297e236d
 10 | d3d9446802a44259755d38e6d163e820
 12 | c20ad4d76fe97759aa27a0c99bff6710
 14 | aab3238922bcc25a6f606eb525ffdc56
 16 | c74d97b01eae257e44aa9d5bade97baf
 18 | 6f4922f45568161a8cdf4ad2299f6d23
 20 | 98f13708210194c475687be6106a3b84

EXPLAIN (BUFFERS OFF, COSTS OFF) WITH cte1 AS (SELECT * FROM t1 WHERE f_leak(b)) SELECT * FROM cte1;
--- QUERY PLAN ---
 CTE Scan on cte1
   CTE cte1
     ->  Custom Scan (ChunkAppend) on t1
           Chunks excluded during startup: 0
           ->  Seq Scan on t1 t1_1
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_69_chunk t1_2
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_70_chunk t1_3
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_71_chunk t1_4
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_72_chunk t1_5
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_73_chunk t1_6
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_74_chunk t1_7
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_75_chunk t1_8
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_76_chunk t1_9
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_77_chunk t1_10
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_78_chunk t1_11
                 Filter: (((a % 2) = 0) AND f_leak(b))
           ->  Seq Scan on _hyper_15_79_chunk t1_12
                 Filter: (((a % 2) = 0) AND f_leak(b))

WITH cte1 AS (UPDATE t1 SET a = a + 1 RETURNING *) SELECT * FROM cte1; --fail
ERROR:  new row violates row-level security policy for table "t1"
WITH cte1 AS (UPDATE t1 SET a = a RETURNING *) SELECT * FROM cte1; --ok
 a  |                b                 
----+----------------------------------
  0 | cfcd208495d565ef66e7dff9f98764da
  2 | c81e728d9d4c2f636f067f89cc14862c
  4 | a87ff679a2f3e71d9181a67b7542122c
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  8 | c9f0f895fb98ab9159f51fd0297e236d
 10 | d3d9446802a44259755d38e6d163e820
 12 | c20ad4d76fe97759aa27a0c99bff6710
 14 | aab3238922bcc25a6f606eb525ffdc56
 16 | c74d97b01eae257e44aa9d5bade97baf
 18 | 6f4922f45568161a8cdf4ad2299f6d23
 20 | 98f13708210194c475687be6106a3b84

WITH cte1 AS (INSERT INTO t1 VALUES (21, 'Fail') RETURNING *) SELECT * FROM cte1; --fail
ERROR:  new row violates row-level security policy for table "t1"
WITH cte1 AS (INSERT INTO t1 VALUES (20, 'Success') RETURNING *) SELECT * FROM cte1; --ok
 a  |    b    
----+---------
 20 | Success

--
-- Rename Policy
--
RESET SESSION AUTHORIZATION;
ALTER POLICY p1 ON t1 RENAME TO p1; --fail
ERROR:  policy "p1" for table "t1" already exists
SELECT polname, relname
    FROM pg_policy pol
    JOIN pg_class pc ON (pc.oid = pol.polrelid)
    WHERE relname = 't1';
 polname | relname 
---------+---------
 p1      | t1

ALTER POLICY p1 ON t1 RENAME TO p2; --ok
SELECT polname, relname
    FROM pg_policy pol
    JOIN pg_class pc ON (pc.oid = pol.polrelid)
    WHERE relname = 't1';
 polname | relname 
---------+---------
 p2      | t1

--
-- Check INSERT SELECT
--
SET SESSION AUTHORIZATION regress_rls_bob;
CREATE TABLE t2 (a integer, b text);
SELECT public.create_hypertable('t2', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (16,regress_rls_schema,t2,t)

INSERT INTO t2 (SELECT * FROM t1);
EXPLAIN (BUFFERS OFF, COSTS OFF) INSERT INTO t2 (SELECT * FROM t1);
--- QUERY PLAN ---
 Custom Scan (ModifyHypertable)
   ->  Insert on t2
         ->  Append
               ->  Seq Scan on t1 t1_1
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_69_chunk t1_2
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_70_chunk t1_3
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_71_chunk t1_4
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_72_chunk t1_5
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_73_chunk t1_6
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_74_chunk t1_7
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_75_chunk t1_8
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_76_chunk t1_9
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_77_chunk t1_10
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_78_chunk t1_11
                     Filter: ((a % 2) = 0)
               ->  Seq Scan on _hyper_15_79_chunk t1_12
                     Filter: ((a % 2) = 0)

SELECT * FROM t2;
 a  |                b                 
----+----------------------------------
  0 | cfcd208495d565ef66e7dff9f98764da
  2 | c81e728d9d4c2f636f067f89cc14862c
  4 | a87ff679a2f3e71d9181a67b7542122c
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  8 | c9f0f895fb98ab9159f51fd0297e236d
 10 | d3d9446802a44259755d38e6d163e820
 12 | c20ad4d76fe97759aa27a0c99bff6710
 14 | aab3238922bcc25a6f606eb525ffdc56
 16 | c74d97b01eae257e44aa9d5bade97baf
 18 | 6f4922f45568161a8cdf4ad2299f6d23
 20 | 98f13708210194c475687be6106a3b84
 20 | Success

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t2;
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t2 t2_1
   ->  Seq Scan on _hyper_16_80_chunk t2_2
   ->  Seq Scan on _hyper_16_81_chunk t2_3
   ->  Seq Scan on _hyper_16_82_chunk t2_4
   ->  Seq Scan on _hyper_16_83_chunk t2_5
   ->  Seq Scan on _hyper_16_84_chunk t2_6
   ->  Seq Scan on _hyper_16_85_chunk t2_7
   ->  Seq Scan on _hyper_16_86_chunk t2_8
   ->  Seq Scan on _hyper_16_87_chunk t2_9
   ->  Seq Scan on _hyper_16_88_chunk t2_10
   ->  Seq Scan on _hyper_16_89_chunk t2_11
   ->  Seq Scan on _hyper_16_90_chunk t2_12

CREATE TABLE t3 AS SELECT * FROM t1;
SELECT public.create_hypertable('t2', 'a', chunk_time_interval=>2);
ERROR:  table "t2" is already a hypertable
SELECT * FROM t3;
 a  |                b                 
----+----------------------------------
  0 | cfcd208495d565ef66e7dff9f98764da
  2 | c81e728d9d4c2f636f067f89cc14862c
  4 | a87ff679a2f3e71d9181a67b7542122c
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  8 | c9f0f895fb98ab9159f51fd0297e236d
 10 | d3d9446802a44259755d38e6d163e820
 12 | c20ad4d76fe97759aa27a0c99bff6710
 14 | aab3238922bcc25a6f606eb525ffdc56
 16 | c74d97b01eae257e44aa9d5bade97baf
 18 | 6f4922f45568161a8cdf4ad2299f6d23
 20 | 98f13708210194c475687be6106a3b84
 20 | Success

SELECT * INTO t4 FROM t1;
SELECT * FROM t4;
 a  |                b                 
----+----------------------------------
  0 | cfcd208495d565ef66e7dff9f98764da
  2 | c81e728d9d4c2f636f067f89cc14862c
  4 | a87ff679a2f3e71d9181a67b7542122c
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  8 | c9f0f895fb98ab9159f51fd0297e236d
 10 | d3d9446802a44259755d38e6d163e820
 12 | c20ad4d76fe97759aa27a0c99bff6710
 14 | aab3238922bcc25a6f606eb525ffdc56
 16 | c74d97b01eae257e44aa9d5bade97baf
 18 | 6f4922f45568161a8cdf4ad2299f6d23
 20 | 98f13708210194c475687be6106a3b84
 20 | Success

--
-- RLS with JOIN
--
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE blog (id integer, author text, post text);
SELECT public.create_hypertable('blog', 'id', chunk_time_interval=>2);
       create_hypertable        
--------------------------------
 (17,regress_rls_schema,blog,t)

CREATE TABLE comment (blog_id integer, message text);
SELECT public.create_hypertable('comment', 'blog_id', chunk_time_interval=>2);
         create_hypertable         
-----------------------------------
 (18,regress_rls_schema,comment,t)

GRANT ALL ON blog, comment TO regress_rls_bob;
CREATE POLICY blog_1 ON blog USING (id % 2 = 0);
ALTER TABLE blog ENABLE ROW LEVEL SECURITY;
INSERT INTO blog VALUES
    (1, 'alice', 'blog #1'),
    (2, 'bob', 'blog #1'),
    (3, 'alice', 'blog #2'),
    (4, 'alice', 'blog #3'),
    (5, 'john', 'blog #1');
INSERT INTO comment VALUES
    (1, 'cool blog'),
    (1, 'fun blog'),
    (3, 'crazy blog'),
    (5, 'what?'),
    (4, 'insane!'),
    (2, 'who did it?');
SET SESSION AUTHORIZATION regress_rls_bob;
-- Check RLS JOIN with Non-RLS.
SELECT id, author, message FROM blog JOIN comment ON id = blog_id;
 id | author |   message   
----+--------+-------------
  2 | bob    | who did it?
  4 | alice  | insane!

-- Check Non-RLS JOIN with RLS.
SELECT id, author, message FROM comment JOIN blog ON id = blog_id;
 id | author |   message   
----+--------+-------------
  2 | bob    | who did it?
  4 | alice  | insane!

SET SESSION AUTHORIZATION regress_rls_alice;
CREATE POLICY comment_1 ON comment USING (blog_id < 4);
ALTER TABLE comment ENABLE ROW LEVEL SECURITY;
SET SESSION AUTHORIZATION regress_rls_bob;
-- Check RLS JOIN RLS
SELECT id, author, message FROM blog JOIN comment ON id = blog_id;
 id | author |   message   
----+--------+-------------
  2 | bob    | who did it?

SELECT id, author, message FROM comment JOIN blog ON id = blog_id;
 id | author |   message   
----+--------+-------------
  2 | bob    | who did it?

SET SESSION AUTHORIZATION regress_rls_alice;
DROP TABLE blog;
DROP TABLE comment;
--
-- Default Deny Policy
--
RESET SESSION AUTHORIZATION;
DROP POLICY p2 ON t1;
ALTER TABLE t1 OWNER TO regress_rls_alice;
-- Check that default deny does not apply to superuser.
RESET SESSION AUTHORIZATION;
SELECT * FROM t1;
 a  |                b                 
----+----------------------------------
  1 | c4ca4238a0b923820dcc509a6f75849b
  0 | cfcd208495d565ef66e7dff9f98764da
  3 | eccbc87e4b5ce2fe28308fd9f2a7baf3
  2 | c81e728d9d4c2f636f067f89cc14862c
  5 | e4da3b7fbbce2345d7772b0674a318d5
  4 | a87ff679a2f3e71d9181a67b7542122c
  7 | 8f14e45fceea167a5a36dedd4bea2543
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  9 | 45c48cce2e2d7fbdea1afc51c7c6ad26
  8 | c9f0f895fb98ab9159f51fd0297e236d
 11 | 6512bd43d9caa6e02c990b0a82652dca
 10 | d3d9446802a44259755d38e6d163e820
 13 | c51ce410c124a10e0db5e4b97fc2af39
 12 | c20ad4d76fe97759aa27a0c99bff6710
 15 | 9bf31c7ff062936a96d3c8bd1f8f2ff3
 14 | aab3238922bcc25a6f606eb525ffdc56
 17 | 70efdf2ec9b086079795c442636b55fb
 16 | c74d97b01eae257e44aa9d5bade97baf
 19 | 1f0e3dad99908345f7439f8ffabdffc4
 18 | 6f4922f45568161a8cdf4ad2299f6d23
 20 | 98f13708210194c475687be6106a3b84
 20 | Success

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1;
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
   ->  Seq Scan on _hyper_15_69_chunk t1_2
   ->  Seq Scan on _hyper_15_70_chunk t1_3
   ->  Seq Scan on _hyper_15_71_chunk t1_4
   ->  Seq Scan on _hyper_15_72_chunk t1_5
   ->  Seq Scan on _hyper_15_73_chunk t1_6
   ->  Seq Scan on _hyper_15_74_chunk t1_7
   ->  Seq Scan on _hyper_15_75_chunk t1_8
   ->  Seq Scan on _hyper_15_76_chunk t1_9
   ->  Seq Scan on _hyper_15_77_chunk t1_10
   ->  Seq Scan on _hyper_15_78_chunk t1_11
   ->  Seq Scan on _hyper_15_79_chunk t1_12

-- Check that default deny does not apply to table owner.
SET SESSION AUTHORIZATION regress_rls_alice;
SELECT * FROM t1;
 a  |                b                 
----+----------------------------------
  1 | c4ca4238a0b923820dcc509a6f75849b
  0 | cfcd208495d565ef66e7dff9f98764da
  3 | eccbc87e4b5ce2fe28308fd9f2a7baf3
  2 | c81e728d9d4c2f636f067f89cc14862c
  5 | e4da3b7fbbce2345d7772b0674a318d5
  4 | a87ff679a2f3e71d9181a67b7542122c
  7 | 8f14e45fceea167a5a36dedd4bea2543
  6 | 1679091c5a880faf6fb5e6087eb1b2dc
  9 | 45c48cce2e2d7fbdea1afc51c7c6ad26
  8 | c9f0f895fb98ab9159f51fd0297e236d
 11 | 6512bd43d9caa6e02c990b0a82652dca
 10 | d3d9446802a44259755d38e6d163e820
 13 | c51ce410c124a10e0db5e4b97fc2af39
 12 | c20ad4d76fe97759aa27a0c99bff6710
 15 | 9bf31c7ff062936a96d3c8bd1f8f2ff3
 14 | aab3238922bcc25a6f606eb525ffdc56
 17 | 70efdf2ec9b086079795c442636b55fb
 16 | c74d97b01eae257e44aa9d5bade97baf
 19 | 1f0e3dad99908345f7439f8ffabdffc4
 18 | 6f4922f45568161a8cdf4ad2299f6d23
 20 | 98f13708210194c475687be6106a3b84
 20 | Success

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1;
--- QUERY PLAN ---
 Append
   ->  Seq Scan on t1 t1_1
   ->  Seq Scan on _hyper_15_69_chunk t1_2
   ->  Seq Scan on _hyper_15_70_chunk t1_3
   ->  Seq Scan on _hyper_15_71_chunk t1_4
   ->  Seq Scan on _hyper_15_72_chunk t1_5
   ->  Seq Scan on _hyper_15_73_chunk t1_6
   ->  Seq Scan on _hyper_15_74_chunk t1_7
   ->  Seq Scan on _hyper_15_75_chunk t1_8
   ->  Seq Scan on _hyper_15_76_chunk t1_9
   ->  Seq Scan on _hyper_15_77_chunk t1_10
   ->  Seq Scan on _hyper_15_78_chunk t1_11
   ->  Seq Scan on _hyper_15_79_chunk t1_12

-- Check that default deny applies to non-owner/non-superuser when RLS on.
SET SESSION AUTHORIZATION regress_rls_bob;
SET row_security TO ON;
SELECT * FROM t1;
 a | b 
---+---

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1;
--- QUERY PLAN ---
 Result
   One-Time Filter: false

SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM t1;
 a | b 
---+---

EXPLAIN (BUFFERS OFF, COSTS OFF) SELECT * FROM t1;
--- QUERY PLAN ---
 Result
   One-Time Filter: false

--
-- COPY TO/FROM
--
RESET SESSION AUTHORIZATION;
DROP TABLE copy_t CASCADE;
ERROR:  table "copy_t" does not exist
CREATE TABLE copy_t (a integer, b text);
SELECT public.create_hypertable('copy_t', 'a', chunk_time_interval=>2);
        create_hypertable         
----------------------------------
 (19,regress_rls_schema,copy_t,t)

CREATE POLICY p1 ON copy_t USING (a % 2 = 0);
ALTER TABLE copy_t ENABLE ROW LEVEL SECURITY;
GRANT ALL ON copy_t TO regress_rls_bob, regress_rls_exempt_user;
INSERT INTO copy_t (SELECT x, md5(x::text) FROM generate_series(0,10) x);
-- Check COPY TO as Superuser/owner.
RESET SESSION AUTHORIZATION;
SET row_security TO OFF;
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ',';
0,cfcd208495d565ef66e7dff9f98764da
1,c4ca4238a0b923820dcc509a6f75849b
2,c81e728d9d4c2f636f067f89cc14862c
3,eccbc87e4b5ce2fe28308fd9f2a7baf3
4,a87ff679a2f3e71d9181a67b7542122c
5,e4da3b7fbbce2345d7772b0674a318d5
6,1679091c5a880faf6fb5e6087eb1b2dc
7,8f14e45fceea167a5a36dedd4bea2543
8,c9f0f895fb98ab9159f51fd0297e236d
9,45c48cce2e2d7fbdea1afc51c7c6ad26
10,d3d9446802a44259755d38e6d163e820
SET row_security TO ON;
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ',';
0,cfcd208495d565ef66e7dff9f98764da
1,c4ca4238a0b923820dcc509a6f75849b
2,c81e728d9d4c2f636f067f89cc14862c
3,eccbc87e4b5ce2fe28308fd9f2a7baf3
4,a87ff679a2f3e71d9181a67b7542122c
5,e4da3b7fbbce2345d7772b0674a318d5
6,1679091c5a880faf6fb5e6087eb1b2dc
7,8f14e45fceea167a5a36dedd4bea2543
8,c9f0f895fb98ab9159f51fd0297e236d
9,45c48cce2e2d7fbdea1afc51c7c6ad26
10,d3d9446802a44259755d38e6d163e820
-- Check COPY TO as user with permissions.
SET SESSION AUTHORIZATION regress_rls_bob;
SET row_security TO OFF;
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --fail - would be affected by RLS
ERROR:  query would be affected by row-level security policy for table "copy_t"
SET row_security TO ON;
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --ok
0,cfcd208495d565ef66e7dff9f98764da
2,c81e728d9d4c2f636f067f89cc14862c
4,a87ff679a2f3e71d9181a67b7542122c
6,1679091c5a880faf6fb5e6087eb1b2dc
8,c9f0f895fb98ab9159f51fd0297e236d
10,d3d9446802a44259755d38e6d163e820
-- Check COPY TO as user with permissions and BYPASSRLS
SET SESSION AUTHORIZATION regress_rls_exempt_user;
SET row_security TO OFF;
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --ok
0,cfcd208495d565ef66e7dff9f98764da
1,c4ca4238a0b923820dcc509a6f75849b
2,c81e728d9d4c2f636f067f89cc14862c
3,eccbc87e4b5ce2fe28308fd9f2a7baf3
4,a87ff679a2f3e71d9181a67b7542122c
5,e4da3b7fbbce2345d7772b0674a318d5
6,1679091c5a880faf6fb5e6087eb1b2dc
7,8f14e45fceea167a5a36dedd4bea2543
8,c9f0f895fb98ab9159f51fd0297e236d
9,45c48cce2e2d7fbdea1afc51c7c6ad26
10,d3d9446802a44259755d38e6d163e820
SET row_security TO ON;
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --ok
0,cfcd208495d565ef66e7dff9f98764da
1,c4ca4238a0b923820dcc509a6f75849b
2,c81e728d9d4c2f636f067f89cc14862c
3,eccbc87e4b5ce2fe28308fd9f2a7baf3
4,a87ff679a2f3e71d9181a67b7542122c
5,e4da3b7fbbce2345d7772b0674a318d5
6,1679091c5a880faf6fb5e6087eb1b2dc
7,8f14e45fceea167a5a36dedd4bea2543
8,c9f0f895fb98ab9159f51fd0297e236d
9,45c48cce2e2d7fbdea1afc51c7c6ad26
10,d3d9446802a44259755d38e6d163e820
-- Check COPY TO as user without permissions. SET row_security TO OFF;
SET SESSION AUTHORIZATION regress_rls_carol;
SET row_security TO OFF;
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --fail - would be affected by RLS
ERROR:  query would be affected by row-level security policy for table "copy_t"
SET row_security TO ON;
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --fail - permission denied
ERROR:  permission denied for table copy_t
-- Check COPY relation TO; keep it just one row to avoid reordering issues
RESET SESSION AUTHORIZATION;
SET row_security TO ON;
CREATE TABLE copy_rel_to (a integer, b text);
SELECT public.create_hypertable('copy_rel_to', 'a', chunk_time_interval=>2);
           create_hypertable           
---------------------------------------
 (20,regress_rls_schema,copy_rel_to,t)

CREATE POLICY p1 ON copy_rel_to USING (a % 2 = 0);
ALTER TABLE copy_rel_to ENABLE ROW LEVEL SECURITY;
GRANT ALL ON copy_rel_to TO regress_rls_bob, regress_rls_exempt_user;
INSERT INTO copy_rel_to VALUES (1, md5('1'));
-- Check COPY TO as Superuser/owner.
RESET SESSION AUTHORIZATION;
SET row_security TO OFF;
COPY (SELECT * FROM copy_rel_to) TO STDOUT WITH DELIMITER ',';
1,c4ca4238a0b923820dcc509a6f75849b
SET row_security TO ON;
COPY (SELECT * FROM copy_rel_to) TO STDOUT WITH DELIMITER ',';
1,c4ca4238a0b923820dcc509a6f75849b
-- Check COPY TO as user with permissions.
SET SESSION AUTHORIZATION regress_rls_bob;
SET row_security TO OFF;
COPY (SELECT * FROM copy_rel_to) TO STDOUT WITH DELIMITER ','; --fail - would be affected by RLS
ERROR:  query would be affected by row-level security policy for table "copy_rel_to"
SET row_security TO ON;
COPY (SELECT * FROM copy_rel_to) TO STDOUT WITH DELIMITER ','; --ok
-- Check COPY TO as user with permissions and BYPASSRLS
SET SESSION AUTHORIZATION regress_rls_exempt_user;
SET row_security TO OFF;
COPY (SELECT * FROM copy_rel_to) TO STDOUT WITH DELIMITER ','; --ok
1,c4ca4238a0b923820dcc509a6f75849b
SET row_security TO ON;
COPY (SELECT * FROM copy_rel_to) TO STDOUT WITH DELIMITER ','; --ok
1,c4ca4238a0b923820dcc509a6f75849b
-- Check COPY TO as user without permissions. SET row_security TO OFF;
SET SESSION AUTHORIZATION regress_rls_carol;
SET row_security TO OFF;
COPY (SELECT * FROM copy_rel_to) TO STDOUT WITH DELIMITER ','; --fail - permission denied
ERROR:  query would be affected by row-level security policy for table "copy_rel_to"
SET row_security TO ON;
COPY (SELECT * FROM copy_rel_to) TO STDOUT WITH DELIMITER ','; --fail - permission denied
ERROR:  permission denied for table copy_rel_to
-- Check COPY FROM as Superuser/owner.
RESET SESSION AUTHORIZATION;
SET row_security TO OFF;
COPY copy_t FROM STDIN; --ok
SET row_security TO ON;
COPY copy_t FROM STDIN; --ok
-- Check COPY FROM as user with permissions.
SET SESSION AUTHORIZATION regress_rls_bob;
SET row_security TO OFF;
COPY copy_t FROM STDIN; --fail - would be affected by RLS.
ERROR:  query would be affected by row-level security policy for table "copy_t"
SET row_security TO ON;
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
ERROR:  COPY FROM not supported with row-level security
HINT:  Use INSERT statements instead.
-- Check COPY FROM as user with permissions and BYPASSRLS
SET SESSION AUTHORIZATION regress_rls_exempt_user;
SET row_security TO ON;
COPY copy_t FROM STDIN; --ok
-- Check COPY FROM as user without permissions.
SET SESSION AUTHORIZATION regress_rls_carol;
SET row_security TO OFF;
COPY copy_t FROM STDIN; --fail - permission denied.
ERROR:  permission denied for table copy_t
SET row_security TO ON;
COPY copy_t FROM STDIN; --fail - permission denied.
ERROR:  permission denied for table copy_t
RESET SESSION AUTHORIZATION;
DROP TABLE copy_t;
DROP TABLE copy_rel_to CASCADE;
-- Check WHERE CURRENT OF
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE current_check (currentid int, payload text, rlsuser text);
SELECT public.create_hypertable('current_check', 'currentid', chunk_time_interval=>10);
            create_hypertable            
-----------------------------------------
 (21,regress_rls_schema,current_check,t)

GRANT ALL ON current_check TO PUBLIC;
INSERT INTO current_check VALUES
    (1, 'abc', 'regress_rls_bob'),
    (2, 'bcd', 'regress_rls_bob'),
    (3, 'cde', 'regress_rls_bob'),
    (4, 'def', 'regress_rls_bob');
CREATE POLICY p1 ON current_check FOR SELECT USING (currentid % 2 = 0);
CREATE POLICY p2 ON current_check FOR DELETE USING (currentid = 4 AND rlsuser = current_user);
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 regress_rls_bob;
-- Can SELECT even rows
SELECT * FROM current_check;
 currentid | payload |     rlsuser     
-----------+---------+-----------------
         2 | bcd     | regress_rls_bob
         4 | def     | regress_rls_bob

-- Cannot UPDATE row 2
UPDATE current_check SET payload = payload || '_new' WHERE currentid = 2 RETURNING *;
 currentid | payload | rlsuser 
-----------+---------+---------

BEGIN;
-- WHERE CURRENT OF does not work with custom scan nodes
-- so we have to disable chunk append here
SET timescaledb.enable_chunk_append TO false;
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 (even rows)
FETCH ABSOLUTE 1 FROM current_check_cursor;
 currentid | payload |     rlsuser     
-----------+---------+-----------------
         2 | bcd     | regress_rls_bob

-- Still cannot UPDATE row 2 through cursor
UPDATE current_check SET payload = payload || '_new' WHERE CURRENT OF current_check_cursor RETURNING *;
 currentid | payload | rlsuser 
-----------+---------+---------

-- Can update row 4 through cursor, which is the next visible row
FETCH RELATIVE 1 FROM current_check_cursor;
 currentid | payload |     rlsuser     
-----------+---------+-----------------
         4 | def     | regress_rls_bob

UPDATE current_check SET payload = payload || '_new' WHERE CURRENT OF current_check_cursor RETURNING *;
 currentid | payload |     rlsuser     
-----------+---------+-----------------
         4 | def_new | regress_rls_bob

SELECT * FROM current_check;
 currentid | payload |     rlsuser     
-----------+---------+-----------------
         2 | bcd     | regress_rls_bob
         4 | def_new | regress_rls_bob

-- Plan should be a subquery TID scan
EXPLAIN (BUFFERS OFF, COSTS OFF) UPDATE current_check SET payload = payload WHERE CURRENT OF current_check_cursor;
--- QUERY PLAN ---
 Custom Scan (ModifyHypertable)
   ->  Update on current_check
         Update on _hyper_21_104_chunk current_check_1
         ->  Tid Scan on _hyper_21_104_chunk current_check_1
               TID Cond: CURRENT OF current_check_cursor
               Filter: ((currentid = 4) AND ((currentid % 2) = 0))

-- Similarly can only delete row 4
FETCH ABSOLUTE 1 FROM current_check_cursor;
 currentid | payload |     rlsuser     
-----------+---------+-----------------
         2 | bcd     | regress_rls_bob

DELETE FROM current_check WHERE CURRENT OF current_check_cursor RETURNING *;
 currentid | payload | rlsuser 
-----------+---------+---------

FETCH RELATIVE 1 FROM current_check_cursor;
 currentid | payload |     rlsuser     
-----------+---------+-----------------
         4 | def     | regress_rls_bob

DELETE FROM current_check WHERE CURRENT OF current_check_cursor RETURNING *;
 currentid | payload |     rlsuser     
-----------+---------+-----------------
         4 | def_new | regress_rls_bob

SELECT * FROM current_check;
 currentid | payload |     rlsuser     
-----------+---------+-----------------
         2 | bcd     | regress_rls_bob

RESET timescaledb.enable_chunk_append;
COMMIT;
--
-- check pg_stats view filtering
--
SET row_security TO ON;
SET SESSION AUTHORIZATION regress_rls_alice;
ANALYZE current_check;
-- Stats visible
SELECT row_security_active('current_check');
 row_security_active 
---------------------
 f

SELECT attname, most_common_vals FROM pg_stats
  WHERE tablename = 'current_check'
  ORDER BY 1;
  attname  | most_common_vals  
-----------+-------------------
 currentid | 
 payload   | 
 rlsuser   | {regress_rls_bob}

SET SESSION AUTHORIZATION regress_rls_bob;
-- Stats not visible
SELECT row_security_active('current_check');
 row_security_active 
---------------------
 t

SELECT attname, most_common_vals FROM pg_stats
  WHERE tablename = 'current_check'
  ORDER BY 1;
 attname | most_common_vals 
---------+------------------

--
-- Collation support
--
BEGIN;
CREATE TABLE coll_t (c) AS VALUES ('bar'::text);
CREATE POLICY coll_p ON coll_t USING (c < ('foo'::text COLLATE "C"));
ALTER TABLE coll_t ENABLE ROW LEVEL SECURITY;
GRANT SELECT ON coll_t TO regress_rls_alice;
SELECT (string_to_array(polqual, ':'))[7] AS inputcollid FROM pg_policy WHERE polrelid = 'coll_t'::regclass;
   inputcollid    
------------------
 inputcollid 950 

SET SESSION AUTHORIZATION regress_rls_alice;
SELECT * FROM coll_t;
  c  
-----
 bar

ROLLBACK;
--
-- Shared Object Dependencies
--
RESET SESSION AUTHORIZATION;
BEGIN;
CREATE ROLE regress_rls_eve;
CREATE ROLE regress_rls_frank;
CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
GRANT SELECT ON TABLE tbl1 TO regress_rls_eve;
CREATE POLICY P ON tbl1 TO regress_rls_eve, regress_rls_frank USING (true);
SELECT refclassid::regclass, deptype
  FROM pg_depend
  WHERE classid = 'pg_policy'::regclass
  AND refobjid = 'tbl1'::regclass;
 refclassid | deptype 
------------+---------
 pg_class   | a

SELECT refclassid::regclass, deptype
  FROM pg_shdepend
  WHERE classid = 'pg_policy'::regclass
  AND refobjid IN ('regress_rls_eve'::regrole, 'regress_rls_frank'::regrole);
 refclassid | deptype 
------------+---------
 pg_authid  | r
 pg_authid  | r

SAVEPOINT q;
DROP ROLE regress_rls_eve; --fails due to dependency on POLICY p
ERROR:  role "regress_rls_eve" cannot be dropped because some objects depend on it
DETAIL:  privileges for table tbl1
target of policy p on table tbl1
ROLLBACK TO q;
ALTER POLICY p ON tbl1 TO regress_rls_frank USING (true);
SAVEPOINT q;
DROP ROLE regress_rls_eve; --fails due to dependency on GRANT SELECT
ERROR:  role "regress_rls_eve" cannot be dropped because some objects depend on it
DETAIL:  privileges for table tbl1
ROLLBACK TO q;
REVOKE ALL ON TABLE tbl1 FROM regress_rls_eve;
SAVEPOINT q;
DROP ROLE regress_rls_eve; --succeeds
ROLLBACK TO q;
SAVEPOINT q;
DROP ROLE regress_rls_frank; --fails due to dependency on POLICY p
ERROR:  role "regress_rls_frank" cannot be dropped because some objects depend on it
DETAIL:  target of policy p on table tbl1
ROLLBACK TO q;
DROP POLICY p ON tbl1;
SAVEPOINT q;
DROP ROLE regress_rls_frank; -- succeeds
ROLLBACK TO q;
ROLLBACK; -- cleanup
--
-- Converting table to view
--
BEGIN;
CREATE TABLE t (c int);
SELECT public.create_hypertable('t', 'c', chunk_time_interval=>2);
      create_hypertable      
-----------------------------
 (22,regress_rls_schema,t,t)

CREATE POLICY p ON t USING (c % 2 = 1);
ALTER TABLE t ENABLE ROW LEVEL SECURITY;
SAVEPOINT q;
CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
  SELECT * FROM generate_series(1,5) t0(c); -- fails due to row level security enabled
ERROR:  hypertables do not support rules
ROLLBACK TO q;
ALTER TABLE t DISABLE ROW LEVEL SECURITY;
SAVEPOINT q;
CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
  SELECT * FROM generate_series(1,5) t0(c); -- fails due to policy p on t
ERROR:  hypertables do not support rules
ROLLBACK TO q;
DROP POLICY p ON t;
CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
  SELECT * FROM generate_series(1,5) t0(c); -- succeeds
ERROR:  hypertables do not support rules
ROLLBACK;
--
-- Policy expression handling
--
BEGIN;
CREATE TABLE t (c) AS VALUES ('bar'::text);
CREATE POLICY p ON t USING (max(c)); -- fails: aggregate functions are not allowed in policy expressions
ERROR:  aggregate functions are not allowed in policy expressions
ROLLBACK;
--
-- Non-target relations are only subject to SELECT policies
--
SET SESSION AUTHORIZATION regress_rls_alice;
CREATE TABLE r1 (a int);
SELECT public.create_hypertable('r1', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (23,regress_rls_schema,r1,t)

CREATE TABLE r2 (a int);
SELECT public.create_hypertable('r2', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (24,regress_rls_schema,r2,t)

INSERT INTO r1 VALUES (10), (20);
INSERT INTO r2 VALUES (10), (20);
GRANT ALL ON r1, r2 TO regress_rls_bob;
CREATE POLICY p1 ON r1 USING (true);
ALTER TABLE r1 ENABLE ROW LEVEL SECURITY;
CREATE POLICY p1 ON r2 FOR SELECT USING (true);
CREATE POLICY p2 ON r2 FOR INSERT WITH CHECK (false);
CREATE POLICY p3 ON r2 FOR UPDATE USING (false);
CREATE POLICY p4 ON r2 FOR DELETE USING (false);
ALTER TABLE r2 ENABLE ROW LEVEL SECURITY;
SET SESSION AUTHORIZATION regress_rls_bob;
SELECT * FROM r1;
 a  
----
 10
 20

SELECT * FROM r2;
 a  
----
 10
 20

-- r2 is read-only
INSERT INTO r2 VALUES (2); -- Not allowed
ERROR:  new row violates row-level security policy for table "r2"
\pset tuples_only 1
UPDATE r2 SET a = 2 RETURNING *; -- Updates nothing

DELETE FROM r2 RETURNING *; -- Deletes nothing

\pset tuples_only 0
-- r2 can be used as a non-target relation in DML
INSERT INTO r1 SELECT a + 1 FROM r2 RETURNING *; -- OK
 a  
----
 11
 21

UPDATE r1 SET a = r2.a + 2 FROM r2 WHERE r1.a = r2.a RETURNING *; -- OK
ERROR:  new row for relation "_hyper_23_105_chunk" violates check constraint "constraint_105"
DELETE FROM r1 USING r2 WHERE r1.a = r2.a + 2 RETURNING *; -- OK
 a | a 
---+---

SELECT * FROM r1;
 a  
----
 10
 11
 20
 21

SELECT * FROM r2;
 a  
----
 10
 20

SET SESSION AUTHORIZATION regress_rls_alice;
DROP TABLE r1;
DROP TABLE r2;
--
-- FORCE ROW LEVEL SECURITY applies RLS to owners too
--
SET SESSION AUTHORIZATION regress_rls_alice;
SET row_security = on;
CREATE TABLE r1 (a int);
SELECT public.create_hypertable('r1', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (25,regress_rls_schema,r1,t)

INSERT INTO r1 VALUES (10), (20);
CREATE POLICY p1 ON r1 USING (false);
ALTER TABLE r1 ENABLE ROW LEVEL SECURITY;
ALTER TABLE r1 FORCE ROW LEVEL SECURITY;
-- No error, but no rows
TABLE r1;
 a 
---

-- RLS error
INSERT INTO r1 VALUES (1);
ERROR:  new row violates row-level security policy for table "r1"
-- No error (unable to see any rows to update)
UPDATE r1 SET a = 1;
TABLE r1;
 a 
---

-- No error (unable to see any rows to delete)
DELETE FROM r1;
TABLE r1;
 a 
---

SET row_security = off;
-- these all fail, would be affected by RLS
TABLE r1;
ERROR:  query would be affected by row-level security policy for table "r1"
HINT:  To disable the policy for the table's owner, use ALTER TABLE NO FORCE ROW LEVEL SECURITY.
UPDATE r1 SET a = 1;
ERROR:  query would be affected by row-level security policy for table "r1"
HINT:  To disable the policy for the table's owner, use ALTER TABLE NO FORCE ROW LEVEL SECURITY.
DELETE FROM r1;
ERROR:  query would be affected by row-level security policy for table "r1"
HINT:  To disable the policy for the table's owner, use ALTER TABLE NO FORCE ROW LEVEL SECURITY.
DROP TABLE r1;
--
-- FORCE ROW LEVEL SECURITY does not break RI
--
SET SESSION AUTHORIZATION regress_rls_alice;
SET row_security = on;
CREATE TABLE r1 (a int PRIMARY KEY);
-- r1 is not a hypertable since r1.a is referenced by r2
CREATE TABLE r2 (a int REFERENCES r1);
SELECT public.create_hypertable('r2', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (26,regress_rls_schema,r2,t)

INSERT INTO r1 VALUES (10), (20);
INSERT INTO r2 VALUES (10), (20);
-- Create policies on r2 which prevent the
-- owner from seeing any rows, but RI should
-- still see them.
CREATE POLICY p1 ON r2 USING (false);
ALTER TABLE r2 ENABLE ROW LEVEL SECURITY;
ALTER TABLE r2 FORCE ROW LEVEL SECURITY;
-- Errors due to rows in r2
DELETE FROM r1;
ERROR:  update or delete on table "r1" violates foreign key constraint "r2_a_fkey" on table "r2"
DETAIL:  Key (a)=(10) is still referenced from table "r2".
-- Reset r2 to no-RLS
DROP POLICY p1 ON r2;
ALTER TABLE r2 NO FORCE ROW LEVEL SECURITY;
ALTER TABLE r2 DISABLE ROW LEVEL SECURITY;
-- clean out r2 for INSERT test below
DELETE FROM r2;
-- Change r1 to not allow rows to be seen
CREATE POLICY p1 ON r1 USING (false);
ALTER TABLE r1 ENABLE ROW LEVEL SECURITY;
ALTER TABLE r1 FORCE ROW LEVEL SECURITY;
-- No rows seen
TABLE r1;
 a 
---

-- No error, RI still sees that row exists in r1
INSERT INTO r2 VALUES (10);
DROP TABLE r2;
DROP TABLE r1;
-- Ensure cascaded DELETE works
CREATE TABLE r1 (a int PRIMARY KEY);
-- r1 is not a hypertable since r1.a is referenced by r2
CREATE TABLE r2 (a int REFERENCES r1 ON DELETE CASCADE);
SELECT public.create_hypertable('r2', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (27,regress_rls_schema,r2,t)

INSERT INTO r1 VALUES (10), (20);
INSERT INTO r2 VALUES (10), (20);
-- Create policies on r2 which prevent the
-- owner from seeing any rows, but RI should
-- still see them.
CREATE POLICY p1 ON r2 USING (false);
ALTER TABLE r2 ENABLE ROW LEVEL SECURITY;
ALTER TABLE r2 FORCE ROW LEVEL SECURITY;
-- Deletes all records from both
DELETE FROM r1;
-- Remove FORCE from r2
ALTER TABLE r2 NO FORCE ROW LEVEL SECURITY;
-- As owner, we now bypass RLS
-- verify no rows in r2 now
TABLE r2;
 a 
---

DROP TABLE r2;
DROP TABLE r1;
-- Ensure cascaded UPDATE works
CREATE TABLE r1 (a int PRIMARY KEY);
-- r1 is not a hypertable since r1.a is referenced by r2
CREATE TABLE r2 (a int REFERENCES r1 ON UPDATE CASCADE);
SELECT public.create_hypertable('r2', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (28,regress_rls_schema,r2,t)

INSERT INTO r1 VALUES (10), (20);
INSERT INTO r2 VALUES (10), (20);
-- Create policies on r2 which prevent the
-- owner from seeing any rows, but RI should
-- still see them.
CREATE POLICY p1 ON r2 USING (false);
ALTER TABLE r2 ENABLE ROW LEVEL SECURITY;
ALTER TABLE r2 FORCE ROW LEVEL SECURITY;
-- Updates records in both (terse output to not print CONTEXT, which can be different).
\set VERBOSITY terse
UPDATE r1 SET a = a+5;
ERROR:  new row for relation "_hyper_28_117_chunk" violates check constraint "constraint_117"
\set VERBOSITY default
-- Remove FORCE from r2
ALTER TABLE r2 NO FORCE ROW LEVEL SECURITY;
-- As owner, we now bypass RLS
-- verify records in r2 updated
TABLE r2;
 a  
----
 10
 20

DROP TABLE r2;
DROP TABLE r1;
--
-- Test INSERT+RETURNING applies SELECT policies as
-- WithCheckOptions (meaning an error is thrown)
--
SET SESSION AUTHORIZATION regress_rls_alice;
SET row_security = on;
CREATE TABLE r1 (a int);
SELECT public.create_hypertable('r1', 'a', chunk_time_interval=>2);
      create_hypertable       
------------------------------
 (29,regress_rls_schema,r1,t)

CREATE POLICY p1 ON r1 FOR SELECT USING (false);
CREATE POLICY p2 ON r1 FOR INSERT WITH CHECK (true);
ALTER TABLE r1 ENABLE ROW LEVEL SECURITY;
ALTER TABLE r1 FORCE ROW LEVEL SECURITY;
-- Works fine
INSERT INTO r1 VALUES (10), (20);
-- No error, but no rows
TABLE r1;
 a 
---

SET row_security = off;
-- fail, would be affected by RLS
TABLE r1;
ERROR:  query would be affected by row-level security policy for table "r1"
HINT:  To disable the policy for the table's owner, use ALTER TABLE NO FORCE ROW LEVEL SECURITY.
SET row_security = on;
-- Error
INSERT INTO r1 VALUES (10), (20) RETURNING *;
ERROR:  new row violates row-level security policy for table "r1"
DROP TABLE r1;
--
-- Test UPDATE+RETURNING applies SELECT policies as
-- WithCheckOptions (meaning an error is thrown)
--
SET SESSION AUTHORIZATION regress_rls_alice;
SET row_security = on;
CREATE TABLE r1 (a int PRIMARY KEY);
SELECT public.create_hypertable('r1', 'a', chunk_time_interval=>100);
      create_hypertable       
------------------------------
 (30,regress_rls_schema,r1,t)

CREATE POLICY p1 ON r1 FOR SELECT USING (a < 20);
CREATE POLICY p2 ON r1 FOR UPDATE USING (a < 20) WITH CHECK (true);
CREATE POLICY p3 ON r1 FOR INSERT WITH CHECK (true);
INSERT INTO r1 VALUES (10);
ALTER TABLE r1 ENABLE ROW LEVEL SECURITY;
ALTER TABLE r1 FORCE ROW LEVEL SECURITY;
-- Works fine
UPDATE r1 SET a = 30;
-- Show updated rows
ALTER TABLE r1 NO FORCE ROW LEVEL SECURITY;
TABLE r1;
 a  
----
 30

-- reset value in r1 for test with RETURNING
UPDATE r1 SET a = 10;
-- Verify row reset
TABLE r1;
 a  
----
 10

ALTER TABLE r1 FORCE ROW LEVEL SECURITY;
-- Error
UPDATE r1 SET a = 30 RETURNING *;
ERROR:  new row violates row-level security policy for table "r1"
-- UPDATE path of INSERT ... ON CONFLICT DO UPDATE should also error out
INSERT INTO r1 VALUES (10)
    ON CONFLICT (a) DO UPDATE SET a = 30 RETURNING *;
ERROR:  new row violates row-level security policy for table "r1"
-- Should still error out without RETURNING (use of arbiter always requires
-- SELECT permissions)
INSERT INTO r1 VALUES (10)
    ON CONFLICT (a) DO UPDATE SET a = 30;
ERROR:  new row violates row-level security policy for table "r1"
-- ON CONFLICT ON CONSTRAINT
INSERT INTO r1 VALUES (10)
    ON CONFLICT ON CONSTRAINT r1_pkey DO UPDATE SET a = 30;
ERROR:  new row violates row-level security policy for table "r1"
DROP TABLE r1;
-- Check dependency handling
RESET SESSION AUTHORIZATION;
CREATE TABLE dep1 (c1 int);
SELECT public.create_hypertable('dep1', 'c1', chunk_time_interval=>2);
       create_hypertable        
--------------------------------
 (31,regress_rls_schema,dep1,t)

CREATE TABLE dep2 (c1 int);
SELECT public.create_hypertable('dep2', 'c1', chunk_time_interval=>2);
       create_hypertable        
--------------------------------
 (32,regress_rls_schema,dep2,t)

CREATE POLICY dep_p1 ON dep1 TO regress_rls_bob USING (c1 > (select max(dep2.c1) from dep2));
ALTER POLICY dep_p1 ON dep1 TO regress_rls_bob,regress_rls_carol;
-- Should return one
SELECT count(*) = 1 FROM pg_depend
				   WHERE objid = (SELECT oid FROM pg_policy WHERE polname = 'dep_p1')
					 AND refobjid = (SELECT oid FROM pg_class WHERE relname = 'dep2');
 ?column? 
----------
 t

ALTER POLICY dep_p1 ON dep1 USING (true);
-- Should return one
SELECT count(*) = 1 FROM pg_shdepend
				   WHERE objid = (SELECT oid FROM pg_policy WHERE polname = 'dep_p1')
					 AND refobjid = (SELECT oid FROM pg_authid WHERE rolname = 'regress_rls_bob');
 ?column? 
----------
 t

-- Should return one
SELECT count(*) = 1 FROM pg_shdepend
				   WHERE objid = (SELECT oid FROM pg_policy WHERE polname = 'dep_p1')
					 AND refobjid = (SELECT oid FROM pg_authid WHERE rolname = 'regress_rls_carol');
 ?column? 
----------
 t

-- Should return zero
SELECT count(*) = 0 FROM pg_depend
				   WHERE objid = (SELECT oid FROM pg_policy WHERE polname = 'dep_p1')
					 AND refobjid = (SELECT oid FROM pg_class WHERE relname = 'dep2');
 ?column? 
----------
 t

-- DROP OWNED BY testing
RESET SESSION AUTHORIZATION;
CREATE ROLE regress_rls_dob_role1;
CREATE ROLE regress_rls_dob_role2;
CREATE TABLE dob_t1 (c1 int);
SELECT public.create_hypertable('dob_t1', 'c1', chunk_time_interval=>2);
        create_hypertable         
----------------------------------
 (33,regress_rls_schema,dob_t1,t)

CREATE TABLE dob_t2 (c1 int) PARTITION BY RANGE (c1);
CREATE POLICY p1 ON dob_t1 TO regress_rls_dob_role1 USING (true);
DROP OWNED BY regress_rls_dob_role1;
DROP POLICY p1 ON dob_t1; -- should fail, already gone
ERROR:  policy "p1" for table "dob_t1" does not exist
CREATE POLICY p1 ON dob_t1 TO regress_rls_dob_role1,regress_rls_dob_role2 USING (true);
DROP OWNED BY regress_rls_dob_role1;
DROP POLICY p1 ON dob_t1; -- should succeed
CREATE POLICY p1 ON dob_t2 TO regress_rls_dob_role1,regress_rls_dob_role2 USING (true);
DROP OWNED BY regress_rls_dob_role1;
DROP POLICY p1 ON dob_t2; -- should succeed
DROP USER regress_rls_dob_role1;
DROP USER regress_rls_dob_role2;
--
-- Clean up objects
--
RESET SESSION AUTHORIZATION;
\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA regress_rls_schema CASCADE;
NOTICE:  drop cascades to 116 other objects
\set VERBOSITY default
DROP USER regress_rls_alice;
DROP USER regress_rls_bob;
DROP USER regress_rls_carol;
DROP USER regress_rls_dave;
DROP USER regress_rls_exempt_user;
DROP ROLE regress_rls_group1;
DROP ROLE regress_rls_group2;
-- Arrange to have a few policies left over, for testing
-- pg_dump/pg_restore
CREATE SCHEMA regress_rls_schema;
CREATE TABLE rls_tbl (c1 int);
SELECT public.create_hypertable('rls_tbl', 'c1', chunk_time_interval=>2);
         create_hypertable         
-----------------------------------
 (34,regress_rls_schema,rls_tbl,t)

ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
CREATE POLICY p1 ON rls_tbl USING (c1 > 5);
CREATE POLICY p2 ON rls_tbl FOR SELECT USING (c1 <= 3);
CREATE POLICY p3 ON rls_tbl FOR UPDATE USING (c1 <= 3) WITH CHECK (c1 > 5);
CREATE POLICY p4 ON rls_tbl FOR DELETE USING (c1 <= 3);
CREATE TABLE rls_tbl_force (c1 int);
SELECT public.create_hypertable('rls_tbl_force', 'c1', chunk_time_interval=>2);
            create_hypertable            
-----------------------------------------
 (35,regress_rls_schema,rls_tbl_force,t)

ALTER TABLE rls_tbl_force ENABLE ROW LEVEL SECURITY;
ALTER TABLE rls_tbl_force FORCE ROW LEVEL SECURITY;
CREATE POLICY p1 ON rls_tbl_force USING (c1 = 5) WITH CHECK (c1 < 5);
CREATE POLICY p2 ON rls_tbl_force FOR SELECT USING (c1 = 8);
CREATE POLICY p3 ON rls_tbl_force FOR UPDATE USING (c1 = 8) WITH CHECK (c1 >= 5);
CREATE POLICY p4 ON rls_tbl_force FOR DELETE USING (c1 = 8);
