diff options
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r-- | src/backend/executor/execMain.c | 124 |
1 files changed, 79 insertions, 45 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 26793eecf48..4272d9bc155 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -82,6 +82,9 @@ static void ExecutePlan(EState *estate, PlanState *planstate, ScanDirection direction, DestReceiver *dest); static bool ExecCheckRTEPerms(RangeTblEntry *rte); +static bool ExecCheckRTEPermsModified(Oid relOid, Oid userid, + Bitmapset *modifiedCols, + AclMode requiredPerms); static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt); static char *ExecBuildSlotValueDescription(Oid reloid, TupleTableSlot *slot, @@ -92,13 +95,15 @@ static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree); /* - * Note that this macro also exists in commands/trigger.c. There does not - * appear to be any good header to put it into, given the structures that + * Note that GetUpdatedColumns() also exists in commands/trigger.c. There does + * not appear to be any good header to put it into, given the structures that * it uses, so we let them be duplicated. Be sure to update both if one needs * to be changed, however. */ -#define GetModifiedColumns(relinfo, estate) \ - (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->modifiedCols) +#define GetInsertedColumns(relinfo, estate) \ + (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->insertedCols) +#define GetUpdatedColumns(relinfo, estate) \ + (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols) /* end of local decls */ @@ -571,7 +576,6 @@ ExecCheckRTEPerms(RangeTblEntry *rte) AclMode remainingPerms; Oid relOid; Oid userid; - int col; /* * Only plain-relation RTEs need to be checked here. Function RTEs are @@ -609,6 +613,8 @@ ExecCheckRTEPerms(RangeTblEntry *rte) remainingPerms = requiredPerms & ~relPerms; if (remainingPerms != 0) { + int col = -1; + /* * If we lack any permissions that exist only as relation permissions, * we can fail straight away. @@ -637,7 +643,6 @@ ExecCheckRTEPerms(RangeTblEntry *rte) return false; } - col = -1; while ((col = bms_next_member(rte->selectedCols, col)) >= 0) { /* bit #s are offset by FirstLowInvalidHeapAttributeNumber */ @@ -660,43 +665,63 @@ ExecCheckRTEPerms(RangeTblEntry *rte) } /* - * Basically the same for the mod columns, with either INSERT or - * UPDATE privilege as specified by remainingPerms. + * Basically the same for the mod columns, for both INSERT and UPDATE + * privilege as specified by remainingPerms. */ - remainingPerms &= ~ACL_SELECT; - if (remainingPerms != 0) - { - /* - * When the query doesn't explicitly change any columns, allow the - * query if we have permission on any column of the rel. This is - * to handle SELECT FOR UPDATE as well as possible corner cases in - * INSERT and UPDATE. - */ - if (bms_is_empty(rte->modifiedCols)) - { - if (pg_attribute_aclcheck_all(relOid, userid, remainingPerms, - ACLMASK_ANY) != ACLCHECK_OK) - return false; - } + if (remainingPerms & ACL_INSERT && !ExecCheckRTEPermsModified(relOid, + userid, + rte->insertedCols, + ACL_INSERT)) + return false; - col = -1; - while ((col = bms_next_member(rte->modifiedCols, col)) >= 0) - { - /* bit #s are offset by FirstLowInvalidHeapAttributeNumber */ - AttrNumber attno = col + FirstLowInvalidHeapAttributeNumber; + if (remainingPerms & ACL_UPDATE && !ExecCheckRTEPermsModified(relOid, + userid, + rte->updatedCols, + ACL_UPDATE)) + return false; + } + return true; +} - if (attno == InvalidAttrNumber) - { - /* whole-row reference can't happen here */ - elog(ERROR, "whole-row update is not implemented"); - } - else - { - if (pg_attribute_aclcheck(relOid, attno, userid, - remainingPerms) != ACLCHECK_OK) - return false; - } - } +/* + * ExecCheckRTEPermsModified + * Check INSERT or UPDATE access permissions for a single RTE (these + * are processed uniformly). + */ +static bool +ExecCheckRTEPermsModified(Oid relOid, Oid userid, Bitmapset *modifiedCols, + AclMode requiredPerms) +{ + int col = -1; + + /* + * When the query doesn't explicitly update any columns, allow the + * query if we have permission on any column of the rel. This is + * to handle SELECT FOR UPDATE as well as possible corner cases in + * UPDATE. + */ + if (bms_is_empty(modifiedCols)) + { + if (pg_attribute_aclcheck_all(relOid, userid, requiredPerms, + ACLMASK_ANY) != ACLCHECK_OK) + return false; + } + + while ((col = bms_next_member(modifiedCols, col)) >= 0) + { + /* bit #s are offset by FirstLowInvalidHeapAttributeNumber */ + AttrNumber attno = col + FirstLowInvalidHeapAttributeNumber; + + if (attno == InvalidAttrNumber) + { + /* whole-row reference can't happen here */ + elog(ERROR, "whole-row update is not implemented"); + } + else + { + if (pg_attribute_aclcheck(relOid, attno, userid, + requiredPerms) != ACLCHECK_OK) + return false; } } return true; @@ -1633,6 +1658,9 @@ ExecConstraints(ResultRelInfo *resultRelInfo, Relation rel = resultRelInfo->ri_RelationDesc; TupleDesc tupdesc = RelationGetDescr(rel); TupleConstr *constr = tupdesc->constr; + Bitmapset *modifiedCols; + Bitmapset *insertedCols; + Bitmapset *updatedCols; Assert(constr); @@ -1647,9 +1675,10 @@ ExecConstraints(ResultRelInfo *resultRelInfo, slot_attisnull(slot, attrChk)) { char *val_desc; - Bitmapset *modifiedCols; - modifiedCols = GetModifiedColumns(resultRelInfo, estate); + insertedCols = GetInsertedColumns(resultRelInfo, estate); + updatedCols = GetUpdatedColumns(resultRelInfo, estate); + modifiedCols = bms_union(insertedCols, updatedCols); val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel), slot, tupdesc, @@ -1673,9 +1702,10 @@ ExecConstraints(ResultRelInfo *resultRelInfo, if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL) { char *val_desc; - Bitmapset *modifiedCols; - modifiedCols = GetModifiedColumns(resultRelInfo, estate); + insertedCols = GetInsertedColumns(resultRelInfo, estate); + updatedCols = GetUpdatedColumns(resultRelInfo, estate); + modifiedCols = bms_union(insertedCols, updatedCols); val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel), slot, tupdesc, @@ -1746,6 +1776,8 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, { char *val_desc; Bitmapset *modifiedCols; + Bitmapset *insertedCols; + Bitmapset *updatedCols; switch (wco->kind) { @@ -1758,7 +1790,9 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, * as that depends on the USING policy. */ case WCO_VIEW_CHECK: - modifiedCols = GetModifiedColumns(resultRelInfo, estate); + insertedCols = GetInsertedColumns(resultRelInfo, estate); + updatedCols = GetUpdatedColumns(resultRelInfo, estate); + modifiedCols = bms_union(insertedCols, updatedCols); val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel), slot, tupdesc, |