aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/functions.c6
-rw-r--r--src/backend/rewrite/rewriteHandler.c67
-rw-r--r--src/test/regress/expected/rowsecurity.out100
-rw-r--r--src/test/regress/sql/rowsecurity.sql58
-rw-r--r--src/tools/pgindent/typedefs.list1
5 files changed, 226 insertions, 6 deletions
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 81b0c029e7a..d5b3e48ba67 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -1985,6 +1985,12 @@ tlist_coercion_finished:
rtr->rtindex = 1;
newquery->jointree = makeFromExpr(list_make1(rtr), NULL);
+ /*
+ * Make sure the new query is marked as having row security if the
+ * original one does.
+ */
+ newquery->hasRowSecurity = parse->hasRowSecurity;
+
/* Replace original query in the correct element of the query list */
lfirst(parse_cell) = newquery;
}
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 9cd96fd17ef..27d4f718843 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -59,6 +59,12 @@ typedef struct acquireLocksOnSubLinks_context
bool for_execute; /* AcquireRewriteLocks' forExecute param */
} acquireLocksOnSubLinks_context;
+typedef struct fireRIRonSubLink_context
+{
+ List *activeRIRs;
+ bool hasRowSecurity;
+} fireRIRonSubLink_context;
+
static bool acquireLocksOnSubLinks(Node *node,
acquireLocksOnSubLinks_context *context);
static Query *rewriteRuleAction(Query *parsetree,
@@ -1849,6 +1855,12 @@ ApplyRetrieveRule(Query *parsetree,
rule_action = fireRIRrules(rule_action, activeRIRs);
/*
+ * Make sure the query is marked as having row security if the view query
+ * does.
+ */
+ parsetree->hasRowSecurity |= rule_action->hasRowSecurity;
+
+ /*
* Now, plug the view query in as a subselect, converting the relation's
* original RTE to a subquery RTE.
*/
@@ -1961,7 +1973,7 @@ markQueryForLocking(Query *qry, Node *jtnode,
* the SubLink's subselect link with the possibly-rewritten subquery.
*/
static bool
-fireRIRonSubLink(Node *node, List *activeRIRs)
+fireRIRonSubLink(Node *node, fireRIRonSubLink_context *context)
{
if (node == NULL)
return false;
@@ -1971,7 +1983,13 @@ fireRIRonSubLink(Node *node, List *activeRIRs)
/* Do what we came for */
sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,
- activeRIRs);
+ context->activeRIRs);
+
+ /*
+ * Remember if any of the sublinks have row security.
+ */
+ context->hasRowSecurity |= ((Query *) sub->subselect)->hasRowSecurity;
+
/* Fall through to process lefthand args of SubLink */
}
@@ -1980,7 +1998,7 @@ fireRIRonSubLink(Node *node, List *activeRIRs)
* subselects of subselects for us.
*/
return expression_tree_walker(node, fireRIRonSubLink,
- (void *) activeRIRs);
+ (void *) context);
}
@@ -2041,6 +2059,13 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
if (rte->rtekind == RTE_SUBQUERY)
{
rte->subquery = fireRIRrules(rte->subquery, activeRIRs);
+
+ /*
+ * While we are here, make sure the query is marked as having row
+ * security if any of its subqueries do.
+ */
+ parsetree->hasRowSecurity |= rte->subquery->hasRowSecurity;
+
continue;
}
@@ -2154,6 +2179,12 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
cte->ctequery = (Node *)
fireRIRrules((Query *) cte->ctequery, activeRIRs);
+
+ /*
+ * While we are here, make sure the query is marked as having row
+ * security if any of its CTEs do.
+ */
+ parsetree->hasRowSecurity |= ((Query *) cte->ctequery)->hasRowSecurity;
}
/*
@@ -2161,9 +2192,22 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
* the rtable and cteList.
*/
if (parsetree->hasSubLinks)
- query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,
+ {
+ fireRIRonSubLink_context context;
+
+ context.activeRIRs = activeRIRs;
+ context.hasRowSecurity = false;
+
+ query_tree_walker(parsetree, fireRIRonSubLink, (void *) &context,
QTW_IGNORE_RC_SUBQUERIES);
+ /*
+ * Make sure the query is marked as having row security if any of its
+ * sublinks do.
+ */
+ parsetree->hasRowSecurity |= context.hasRowSecurity;
+ }
+
/*
* Apply any row-level security policies. We do this last because it
* requires special recursion detection if the new quals have sublink
@@ -2202,6 +2246,7 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
if (hasSubLinks)
{
acquireLocksOnSubLinks_context context;
+ fireRIRonSubLink_context fire_context;
/*
* Recursively process the new quals, checking for infinite
@@ -2232,11 +2277,21 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
* Now that we have the locks on anything added by
* get_row_security_policies, fire any RIR rules for them.
*/
+ fire_context.activeRIRs = activeRIRs;
+ fire_context.hasRowSecurity = false;
+
expression_tree_walker((Node *) securityQuals,
- fireRIRonSubLink, (void *) activeRIRs);
+ fireRIRonSubLink, (void *) &fire_context);
expression_tree_walker((Node *) withCheckOptions,
- fireRIRonSubLink, (void *) activeRIRs);
+ fireRIRonSubLink, (void *) &fire_context);
+
+ /*
+ * We can ignore the value of fire_context.hasRowSecurity
+ * since we only reach this code in cases where hasRowSecurity
+ * is already true.
+ */
+ Assert(hasRowSecurity);
activeRIRs = list_delete_last(activeRIRs);
}
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 97ca9bf72c5..218c0c28632 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -4483,8 +4483,108 @@ execute q;
--------------+---
(0 rows)
+-- make sure RLS dependencies in CTEs are handled
+reset role;
+create or replace function rls_f() returns setof rls_t
+ stable language sql
+ as $$ with cte as (select * from rls_t) select * from cte $$;
+prepare r as select current_user, * from rls_f();
+set role regress_rls_alice;
+execute r;
+ current_user | c
+-------------------+------------------
+ regress_rls_alice | invisible to bob
+(1 row)
+
+set role regress_rls_bob;
+execute r;
+ current_user | c
+--------------+---
+(0 rows)
+
+-- make sure RLS dependencies in subqueries are handled
+reset role;
+create or replace function rls_f() returns setof rls_t
+ stable language sql
+ as $$ select * from (select * from rls_t) _ $$;
+prepare s as select current_user, * from rls_f();
+set role regress_rls_alice;
+execute s;
+ current_user | c
+-------------------+------------------
+ regress_rls_alice | invisible to bob
+(1 row)
+
+set role regress_rls_bob;
+execute s;
+ current_user | c
+--------------+---
+(0 rows)
+
+-- make sure RLS dependencies in sublinks are handled
+reset role;
+create or replace function rls_f() returns setof rls_t
+ stable language sql
+ as $$ select exists(select * from rls_t)::text $$;
+prepare t as select current_user, * from rls_f();
+set role regress_rls_alice;
+execute t;
+ current_user | c
+-------------------+------
+ regress_rls_alice | true
+(1 row)
+
+set role regress_rls_bob;
+execute t;
+ current_user | c
+-----------------+-------
+ regress_rls_bob | false
+(1 row)
+
+-- make sure RLS dependencies are handled when coercion projections are inserted
+reset role;
+create or replace function rls_f() returns setof rls_t
+ stable language sql
+ as $$ select * from (select array_agg(c) as cs from rls_t) _ group by cs $$;
+prepare u as select current_user, * from rls_f();
+set role regress_rls_alice;
+execute u;
+ current_user | c
+-------------------+----------------------
+ regress_rls_alice | {"invisible to bob"}
+(1 row)
+
+set role regress_rls_bob;
+execute u;
+ current_user | c
+-----------------+---
+ regress_rls_bob |
+(1 row)
+
+-- make sure RLS dependencies in security invoker views are handled
+reset role;
+create view rls_v with (security_invoker) as select * from rls_t;
+grant select on rls_v to regress_rls_alice, regress_rls_bob;
+create or replace function rls_f() returns setof rls_t
+ stable language sql
+ as $$ select * from rls_v $$;
+prepare v as select current_user, * from rls_f();
+set role regress_rls_alice;
+execute v;
+ current_user | c
+-------------------+------------------
+ regress_rls_alice | invisible to bob
+(1 row)
+
+set role regress_rls_bob;
+execute v;
+ current_user | c
+--------------+---
+(0 rows)
+
RESET ROLE;
DROP FUNCTION rls_f();
+DROP VIEW rls_v;
DROP TABLE rls_t;
--
-- Clean up objects
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index dec7340538c..d3bfd53e237 100644
--- a/src/test/regress/sql/rowsecurity.sql
+++ b/src/test/regress/sql/rowsecurity.sql
@@ -2177,8 +2177,66 @@ execute q;
set role regress_rls_bob;
execute q;
+-- make sure RLS dependencies in CTEs are handled
+reset role;
+create or replace function rls_f() returns setof rls_t
+ stable language sql
+ as $$ with cte as (select * from rls_t) select * from cte $$;
+prepare r as select current_user, * from rls_f();
+set role regress_rls_alice;
+execute r;
+set role regress_rls_bob;
+execute r;
+
+-- make sure RLS dependencies in subqueries are handled
+reset role;
+create or replace function rls_f() returns setof rls_t
+ stable language sql
+ as $$ select * from (select * from rls_t) _ $$;
+prepare s as select current_user, * from rls_f();
+set role regress_rls_alice;
+execute s;
+set role regress_rls_bob;
+execute s;
+
+-- make sure RLS dependencies in sublinks are handled
+reset role;
+create or replace function rls_f() returns setof rls_t
+ stable language sql
+ as $$ select exists(select * from rls_t)::text $$;
+prepare t as select current_user, * from rls_f();
+set role regress_rls_alice;
+execute t;
+set role regress_rls_bob;
+execute t;
+
+-- make sure RLS dependencies are handled when coercion projections are inserted
+reset role;
+create or replace function rls_f() returns setof rls_t
+ stable language sql
+ as $$ select * from (select array_agg(c) as cs from rls_t) _ group by cs $$;
+prepare u as select current_user, * from rls_f();
+set role regress_rls_alice;
+execute u;
+set role regress_rls_bob;
+execute u;
+
+-- make sure RLS dependencies in security invoker views are handled
+reset role;
+create view rls_v with (security_invoker) as select * from rls_t;
+grant select on rls_v to regress_rls_alice, regress_rls_bob;
+create or replace function rls_f() returns setof rls_t
+ stable language sql
+ as $$ select * from rls_v $$;
+prepare v as select current_user, * from rls_f();
+set role regress_rls_alice;
+execute v;
+set role regress_rls_bob;
+execute v;
+
RESET ROLE;
DROP FUNCTION rls_f();
+DROP VIEW rls_v;
DROP TABLE rls_t;
--
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 43570438e99..d48f424fe6d 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3314,6 +3314,7 @@ fill_string_relopt
finalize_primnode_context
find_dependent_phvs_context
find_expr_references_context
+fireRIRonSubLink_context
fix_join_expr_context
fix_scan_expr_context
fix_upper_expr_context