aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execMain.c
diff options
context:
space:
mode:
authorAndres Freund <andres@anarazel.de>2015-05-08 00:20:46 +0200
committerAndres Freund <andres@anarazel.de>2015-05-08 00:20:46 +0200
commit2c8f4836db058d0715bc30a30655d646287ba509 (patch)
tree31576f5fc453bd2dbc5642c1281640b5eb959307 /src/backend/executor/execMain.c
parentdb5f98ab4fa44bc563ec62d7b1aada4fc276d9b2 (diff)
downloadpostgresql-2c8f4836db058d0715bc30a30655d646287ba509.tar.gz
postgresql-2c8f4836db058d0715bc30a30655d646287ba509.zip
Represent columns requiring insert and update privileges indentently.
Previously, relation range table entries used a single Bitmapset field representing which columns required either UPDATE or INSERT privileges, despite the fact that INSERT and UPDATE privileges are separately cataloged, and may be independently held. As statements so far required either insert or update privileges but never both, that was sufficient. The required permission could be inferred from the top level statement run. The upcoming INSERT ... ON CONFLICT UPDATE feature needs to independently check for both privileges in one statement though, so that is not sufficient anymore. Bumps catversion as stored rules change. Author: Peter Geoghegan Reviewed-By: Andres Freund
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r--src/backend/executor/execMain.c124
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,