summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index b8669d22ae2..98eb40cc47e 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -60,6 +60,7 @@
#include "partitioning/partdesc.h"
#include "rewrite/rewriteManip.h"
#include "storage/dsm_impl.h"
+#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/selfuncs.h"
@@ -770,6 +771,35 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
}
/*
+ * This would be a convenient time to check access permissions for all
+ * relations mentioned in the query, since it would be better to fail now,
+ * before doing any detailed planning. However, for historical reasons,
+ * we leave this to be done at executor startup.
+ *
+ * Note, however, that we do need to check access permissions for any view
+ * relations mentioned in the query, in order to prevent information being
+ * leaked by selectivity estimation functions, which only check view owner
+ * permissions on underlying tables (see all_rows_selectable() and its
+ * callers). This is a little ugly, because it means that access
+ * permissions for views will be checked twice, which is another reason
+ * why it would be better to do all the ACL checks here.
+ */
+ foreach(l, parse->rtable)
+ {
+ RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
+
+ if (rte->relkind == RELKIND_VIEW)
+ {
+ bool result;
+
+ result = ExecCheckRTEPerms(rte);
+ if (!result)
+ aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_VIEW,
+ get_rel_name(rte->relid));
+ }
+ }
+
+ /*
* Preprocess RowMark information. We need to do this after subquery
* pullup, so that all base relations are present.
*/