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;
        }
 
        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,
         */
        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.
  * 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;
 
                /* 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 */
        }
 
         * subselects of subselects for us.
         */
        return expression_tree_walker(node, fireRIRonSubLink,
-                                                                 (void *) activeRIRs);
+                                                                 (void *) context);
 }
 
 
                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;
                }
 
 
                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;
        }
 
        /*
         * 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
                        if (hasSubLinks)
                        {
                                acquireLocksOnSubLinks_context context;
+                               fireRIRonSubLink_context fire_context;
 
                                /*
                                 * Recursively process the new quals, checking for infinite
                                 * 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);
                        }
 
 --------------+---
 (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
 
 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;
 
 --
 
 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