aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c117
-rw-r--r--src/backend/executor/execParallel.c1
-rw-r--r--src/backend/executor/execUtils.c134
3 files changed, 146 insertions, 106 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 12ff4f3de58..872b879387b 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -54,6 +54,7 @@
#include "jit/jit.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
+#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
@@ -74,7 +75,7 @@ ExecutorRun_hook_type ExecutorRun_hook = NULL;
ExecutorFinish_hook_type ExecutorFinish_hook = NULL;
ExecutorEnd_hook_type ExecutorEnd_hook = NULL;
-/* Hook for plugin to get control in ExecCheckRTPerms() */
+/* Hook for plugin to get control in ExecCheckPermissions() */
ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook = NULL;
/* decls for local routines only used within this module */
@@ -90,10 +91,10 @@ static void ExecutePlan(EState *estate, PlanState *planstate,
ScanDirection direction,
DestReceiver *dest,
bool execute_once);
-static bool ExecCheckRTEPerms(RangeTblEntry *rte);
-static bool ExecCheckRTEPermsModified(Oid relOid, Oid userid,
- Bitmapset *modifiedCols,
- AclMode requiredPerms);
+static bool ExecCheckOneRelPerms(RTEPermissionInfo *perminfo);
+static bool ExecCheckPermissionsModified(Oid relOid, Oid userid,
+ Bitmapset *modifiedCols,
+ AclMode requiredPerms);
static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt);
static char *ExecBuildSlotValueDescription(Oid reloid,
TupleTableSlot *slot,
@@ -554,8 +555,8 @@ ExecutorRewind(QueryDesc *queryDesc)
/*
- * ExecCheckRTPerms
- * Check access permissions for all relations listed in a range table.
+ * ExecCheckPermissions
+ * Check access permissions of relations mentioned in a query
*
* Returns true if permissions are adequate. Otherwise, throws an appropriate
* error if ereport_on_violation is true, or simply returns false otherwise.
@@ -565,73 +566,65 @@ ExecutorRewind(QueryDesc *queryDesc)
* passing, then RLS also needs to be consulted (and check_enable_rls()).
*
* See rewrite/rowsecurity.c.
+ *
+ * NB: rangeTable is no longer used by us, but kept around for the hooks that
+ * might still want to look at the RTEs.
*/
bool
-ExecCheckRTPerms(List *rangeTable, bool ereport_on_violation)
+ExecCheckPermissions(List *rangeTable, List *rteperminfos,
+ bool ereport_on_violation)
{
ListCell *l;
bool result = true;
- foreach(l, rangeTable)
+ foreach(l, rteperminfos)
{
- RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
+ RTEPermissionInfo *perminfo = lfirst_node(RTEPermissionInfo, l);
- result = ExecCheckRTEPerms(rte);
+ Assert(OidIsValid(perminfo->relid));
+ result = ExecCheckOneRelPerms(perminfo);
if (!result)
{
- Assert(rte->rtekind == RTE_RELATION);
if (ereport_on_violation)
- aclcheck_error(ACLCHECK_NO_PRIV, get_relkind_objtype(get_rel_relkind(rte->relid)),
- get_rel_name(rte->relid));
+ aclcheck_error(ACLCHECK_NO_PRIV,
+ get_relkind_objtype(get_rel_relkind(perminfo->relid)),
+ get_rel_name(perminfo->relid));
return false;
}
}
if (ExecutorCheckPerms_hook)
- result = (*ExecutorCheckPerms_hook) (rangeTable,
+ result = (*ExecutorCheckPerms_hook) (rangeTable, rteperminfos,
ereport_on_violation);
return result;
}
/*
- * ExecCheckRTEPerms
- * Check access permissions for a single RTE.
+ * ExecCheckOneRelPerms
+ * Check access permissions for a single relation.
*/
static bool
-ExecCheckRTEPerms(RangeTblEntry *rte)
+ExecCheckOneRelPerms(RTEPermissionInfo *perminfo)
{
AclMode requiredPerms;
AclMode relPerms;
AclMode remainingPerms;
- Oid relOid;
Oid userid;
+ Oid relOid = perminfo->relid;
- /*
- * Only plain-relation RTEs need to be checked here. Function RTEs are
- * checked when the function is prepared for execution. Join, subquery,
- * and special RTEs need no checks.
- */
- if (rte->rtekind != RTE_RELATION)
- return true;
-
- /*
- * No work if requiredPerms is empty.
- */
- requiredPerms = rte->requiredPerms;
- if (requiredPerms == 0)
- return true;
-
- relOid = rte->relid;
+ requiredPerms = perminfo->requiredPerms;
+ Assert(requiredPerms != 0);
/*
* userid to check as: current user unless we have a setuid indication.
*
* Note: GetUserId() is presently fast enough that there's no harm in
- * calling it separately for each RTE. If that stops being true, we could
- * call it once in ExecCheckRTPerms and pass the userid down from there.
- * But for now, no need for the extra clutter.
+ * calling it separately for each relation. If that stops being true, we
+ * could call it once in ExecCheckPermissions and pass the userid down
+ * from there. But for now, no need for the extra clutter.
*/
- userid = OidIsValid(rte->checkAsUser) ? rte->checkAsUser : GetUserId();
+ userid = OidIsValid(perminfo->checkAsUser) ?
+ perminfo->checkAsUser : GetUserId();
/*
* We must have *all* the requiredPerms bits, but some of the bits can be
@@ -665,14 +658,14 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
* example, SELECT COUNT(*) FROM table), allow the query if we
* have SELECT on any column of the rel, as per SQL spec.
*/
- if (bms_is_empty(rte->selectedCols))
+ if (bms_is_empty(perminfo->selectedCols))
{
if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
ACLMASK_ANY) != ACLCHECK_OK)
return false;
}
- while ((col = bms_next_member(rte->selectedCols, col)) >= 0)
+ while ((col = bms_next_member(perminfo->selectedCols, col)) >= 0)
{
/* bit #s are offset by FirstLowInvalidHeapAttributeNumber */
AttrNumber attno = col + FirstLowInvalidHeapAttributeNumber;
@@ -697,29 +690,31 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
* Basically the same for the mod columns, for both INSERT and UPDATE
* privilege as specified by remainingPerms.
*/
- if (remainingPerms & ACL_INSERT && !ExecCheckRTEPermsModified(relOid,
- userid,
- rte->insertedCols,
- ACL_INSERT))
+ if (remainingPerms & ACL_INSERT &&
+ !ExecCheckPermissionsModified(relOid,
+ userid,
+ perminfo->insertedCols,
+ ACL_INSERT))
return false;
- if (remainingPerms & ACL_UPDATE && !ExecCheckRTEPermsModified(relOid,
- userid,
- rte->updatedCols,
- ACL_UPDATE))
+ if (remainingPerms & ACL_UPDATE &&
+ !ExecCheckPermissionsModified(relOid,
+ userid,
+ perminfo->updatedCols,
+ ACL_UPDATE))
return false;
}
return true;
}
/*
- * ExecCheckRTEPermsModified
- * Check INSERT or UPDATE access permissions for a single RTE (these
+ * ExecCheckPermissionsModified
+ * Check INSERT or UPDATE access permissions for a single relation (these
* are processed uniformly).
*/
static bool
-ExecCheckRTEPermsModified(Oid relOid, Oid userid, Bitmapset *modifiedCols,
- AclMode requiredPerms)
+ExecCheckPermissionsModified(Oid relOid, Oid userid, Bitmapset *modifiedCols,
+ AclMode requiredPerms)
{
int col = -1;
@@ -773,17 +768,14 @@ ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
* Fail if write permissions are requested in parallel mode for table
* (temp or non-temp), otherwise fail for any non-temp table.
*/
- foreach(l, plannedstmt->rtable)
+ foreach(l, plannedstmt->permInfos)
{
- RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
-
- if (rte->rtekind != RTE_RELATION)
- continue;
+ RTEPermissionInfo *perminfo = lfirst_node(RTEPermissionInfo, l);
- if ((rte->requiredPerms & (~ACL_SELECT)) == 0)
+ if ((perminfo->requiredPerms & (~ACL_SELECT)) == 0)
continue;
- if (isTempNamespace(get_rel_namespace(rte->relid)))
+ if (isTempNamespace(get_rel_namespace(perminfo->relid)))
continue;
PreventCommandIfReadOnly(CreateCommandName((Node *) plannedstmt));
@@ -815,9 +807,10 @@ InitPlan(QueryDesc *queryDesc, int eflags)
int i;
/*
- * Do permissions checks
+ * Do permissions checks and save the list for later use.
*/
- ExecCheckRTPerms(rangeTable, true);
+ ExecCheckPermissions(rangeTable, plannedstmt->permInfos, true);
+ estate->es_rteperminfos = plannedstmt->permInfos;
/*
* initialize the node's execution state
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index aca0c6f323f..a5b8e43ec51 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -185,6 +185,7 @@ ExecSerializePlan(Plan *plan, EState *estate)
pstmt->planTree = plan;
pstmt->partPruneInfos = estate->es_part_prune_infos;
pstmt->rtable = estate->es_range_table;
+ pstmt->permInfos = estate->es_rteperminfos;
pstmt->resultRelations = NIL;
pstmt->appendRelations = NIL;
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 572c87e4536..e296f44ebd9 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -57,6 +57,7 @@
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
+#include "parser/parse_relation.h"
#include "partitioning/partdesc.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -67,6 +68,7 @@
static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, int varno, TupleDesc tupdesc);
static void ShutdownExprContext(ExprContext *econtext, bool isCommit);
+static RTEPermissionInfo *GetResultRTEPermissionInfo(ResultRelInfo *relinfo, EState *estate);
/* ----------------------------------------------------------------
@@ -1296,72 +1298,48 @@ ExecGetRootToChildMap(ResultRelInfo *resultRelInfo, EState *estate)
Bitmapset *
ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
{
- /*
- * The columns are stored in the range table entry. If this ResultRelInfo
- * represents a partition routing target, and doesn't have an entry of its
- * own in the range table, fetch the parent's RTE and map the columns to
- * the order they are in the partition.
- */
- if (relinfo->ri_RangeTableIndex != 0)
- {
- RangeTblEntry *rte = exec_rt_fetch(relinfo->ri_RangeTableIndex, estate);
+ RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
- return rte->insertedCols;
- }
- else if (relinfo->ri_RootResultRelInfo)
+ if (perminfo == NULL)
+ return NULL;
+
+ /* Map the columns to child's attribute numbers if needed. */
+ if (relinfo->ri_RootResultRelInfo)
{
- ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
- RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
- if (map != NULL)
- return execute_attr_map_cols(map->attrMap, rte->insertedCols);
- else
- return rte->insertedCols;
- }
- else
- {
- /*
- * The relation isn't in the range table and it isn't a partition
- * routing target. This ResultRelInfo must've been created only for
- * firing triggers and the relation is not being inserted into. (See
- * ExecGetTriggerResultRel.)
- */
- return NULL;
+ if (map)
+ return execute_attr_map_cols(map->attrMap, perminfo->insertedCols);
}
+
+ return perminfo->insertedCols;
}
/* Return a bitmap representing columns being updated */
Bitmapset *
ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
{
- /* see ExecGetInsertedCols() */
- if (relinfo->ri_RangeTableIndex != 0)
- {
- RangeTblEntry *rte = exec_rt_fetch(relinfo->ri_RangeTableIndex, estate);
+ RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
- return rte->updatedCols;
- }
- else if (relinfo->ri_RootResultRelInfo)
+ if (perminfo == NULL)
+ return NULL;
+
+ /* Map the columns to child's attribute numbers if needed. */
+ if (relinfo->ri_RootResultRelInfo)
{
- ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
- RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
- if (map != NULL)
- return execute_attr_map_cols(map->attrMap, rte->updatedCols);
- else
- return rte->updatedCols;
+ if (map)
+ return execute_attr_map_cols(map->attrMap, perminfo->updatedCols);
}
- else
- return NULL;
+
+ return perminfo->updatedCols;
}
/* Return a bitmap representing generated columns being updated */
Bitmapset *
ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
{
- /* see ExecGetInsertedCols() */
if (relinfo->ri_RangeTableIndex != 0)
{
RangeTblEntry *rte = exec_rt_fetch(relinfo->ri_RangeTableIndex, estate);
@@ -1390,3 +1368,71 @@ ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
return bms_union(ExecGetUpdatedCols(relinfo, estate),
ExecGetExtraUpdatedCols(relinfo, estate));
}
+
+/*
+ * GetResultRTEPermissionInfo
+ * Looks up RTEPermissionInfo for ExecGet*Cols() routines
+ */
+static RTEPermissionInfo *
+GetResultRTEPermissionInfo(ResultRelInfo *relinfo, EState *estate)
+{
+ Index rti;
+ RangeTblEntry *rte;
+ RTEPermissionInfo *perminfo = NULL;
+
+ if (relinfo->ri_RootResultRelInfo)
+ {
+ /*
+ * For inheritance child result relations (a partition routing target
+ * of an INSERT or a child UPDATE target), this returns the root
+ * parent's RTE to fetch the RTEPermissionInfo because that's the only
+ * one that has one assigned.
+ */
+ rti = relinfo->ri_RootResultRelInfo->ri_RangeTableIndex;
+ }
+ else if (relinfo->ri_RangeTableIndex != 0)
+ {
+ /*
+ * Non-child result relation should have their own RTEPermissionInfo.
+ */
+ rti = relinfo->ri_RangeTableIndex;
+ }
+ else
+ {
+ /*
+ * The relation isn't in the range table and it isn't a partition
+ * routing target. This ResultRelInfo must've been created only for
+ * firing triggers and the relation is not being inserted into. (See
+ * ExecGetTriggerResultRel.)
+ */
+ rti = 0;
+ }
+
+ if (rti > 0)
+ {
+ rte = exec_rt_fetch(rti, estate);
+ perminfo = getRTEPermissionInfo(estate->es_rteperminfos, rte);
+ }
+
+ return perminfo;
+}
+
+/*
+ * GetResultRelCheckAsUser
+ * Returns the user to modify passed-in result relation as
+ *
+ * The user is chosen by looking up the relation's or, if a child table, its
+ * root parent's RTEPermissionInfo.
+ */
+Oid
+ExecGetResultRelCheckAsUser(ResultRelInfo *relInfo, EState *estate)
+{
+ RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relInfo, estate);
+
+ /* XXX - maybe ok to return GetUserId() in this case? */
+ if (perminfo == NULL)
+ elog(ERROR, "no RTEPermissionInfo found for result relation with OID %u",
+ RelationGetRelid(relInfo->ri_RelationDesc));
+
+ return perminfo->checkAsUser ? perminfo->checkAsUser : GetUserId();
+}