aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/copy.c2
-rw-r--r--src/backend/commands/createas.c2
-rw-r--r--src/backend/commands/trigger.c30
-rw-r--r--src/backend/executor/execMain.c124
-rw-r--r--src/backend/nodes/copyfuncs.c3
-rw-r--r--src/backend/nodes/equalfuncs.c3
-rw-r--r--src/backend/nodes/outfuncs.c3
-rw-r--r--src/backend/nodes/readfuncs.c3
-rw-r--r--src/backend/optimizer/plan/setrefs.c6
-rw-r--r--src/backend/optimizer/prep/prepsecurity.c6
-rw-r--r--src/backend/optimizer/prep/prepunion.c8
-rw-r--r--src/backend/parser/analyze.c4
-rw-r--r--src/backend/parser/parse_relation.c21
-rw-r--r--src/backend/rewrite/rewriteHandler.c52
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/nodes/parsenodes.h14
16 files changed, 171 insertions, 112 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 0d3721a96da..aa8ae4b9bcd 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -847,7 +847,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
FirstLowInvalidHeapAttributeNumber;
if (is_from)
- rte->modifiedCols = bms_add_member(rte->modifiedCols, attno);
+ rte->insertedCols = bms_add_member(rte->insertedCols, attno);
else
rte->selectedCols = bms_add_member(rte->selectedCols, attno);
}
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index 54b2f382ea0..e8f0d793b67 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -433,7 +433,7 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
rte->requiredPerms = ACL_INSERT;
for (attnum = 1; attnum <= intoRelationDesc->rd_att->natts; attnum++)
- rte->modifiedCols = bms_add_member(rte->modifiedCols,
+ rte->insertedCols = bms_add_member(rte->insertedCols,
attnum - FirstLowInvalidHeapAttributeNumber);
ExecCheckRTPerms(list_make1(rte), true);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 098893f4944..222e7fce854 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -66,13 +66,13 @@ int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
static int MyTriggerDepth = 0;
/*
- * Note that this macro also exists in executor/execMain.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.
+ * Note that similar macros also exists in executor/execMain.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 GetUpdatedColumns(relinfo, estate) \
+ (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols)
/* Local function prototypes */
static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid);
@@ -2347,7 +2347,7 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
TriggerDesc *trigdesc;
int i;
TriggerData LocTriggerData;
- Bitmapset *modifiedCols;
+ Bitmapset *updatedCols;
trigdesc = relinfo->ri_TrigDesc;
@@ -2356,7 +2356,7 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
if (!trigdesc->trig_update_before_statement)
return;
- modifiedCols = GetModifiedColumns(relinfo, estate);
+ updatedCols = GetUpdatedColumns(relinfo, estate);
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
@@ -2377,7 +2377,7 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
TRIGGER_TYPE_UPDATE))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
- modifiedCols, NULL, NULL))
+ updatedCols, NULL, NULL))
continue;
LocTriggerData.tg_trigger = trigger;
@@ -2402,7 +2402,7 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
if (trigdesc && trigdesc->trig_update_after_statement)
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
false, NULL, NULL, NIL,
- GetModifiedColumns(relinfo, estate));
+ GetUpdatedColumns(relinfo, estate));
}
TupleTableSlot *
@@ -2420,7 +2420,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
HeapTuple oldtuple;
TupleTableSlot *newSlot;
int i;
- Bitmapset *modifiedCols;
+ Bitmapset *updatedCols;
Bitmapset *keyCols;
LockTupleMode lockmode;
@@ -2429,10 +2429,10 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
* been modified, then we can use a weaker lock, allowing for better
* concurrency.
*/
- modifiedCols = GetModifiedColumns(relinfo, estate);
+ updatedCols = GetUpdatedColumns(relinfo, estate);
keyCols = RelationGetIndexAttrBitmap(relinfo->ri_RelationDesc,
INDEX_ATTR_BITMAP_KEY);
- if (bms_overlap(keyCols, modifiedCols))
+ if (bms_overlap(keyCols, updatedCols))
lockmode = LockTupleExclusive;
else
lockmode = LockTupleNoKeyExclusive;
@@ -2486,7 +2486,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
TRIGGER_TYPE_UPDATE))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
- modifiedCols, trigtuple, newtuple))
+ updatedCols, trigtuple, newtuple))
continue;
LocTriggerData.tg_trigtuple = trigtuple;
@@ -2556,7 +2556,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
true, trigtuple, newtuple, recheckIndexes,
- GetModifiedColumns(relinfo, estate));
+ GetUpdatedColumns(relinfo, estate));
if (trigtuple != fdw_trigtuple)
heap_freetuple(trigtuple);
}
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,
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 805045d15e6..1b02be287ce 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2042,7 +2042,8 @@ _copyRangeTblEntry(const RangeTblEntry *from)
COPY_SCALAR_FIELD(requiredPerms);
COPY_SCALAR_FIELD(checkAsUser);
COPY_BITMAPSET_FIELD(selectedCols);
- COPY_BITMAPSET_FIELD(modifiedCols);
+ COPY_BITMAPSET_FIELD(insertedCols);
+ COPY_BITMAPSET_FIELD(updatedCols);
COPY_NODE_FIELD(securityQuals);
return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 578ead54632..1b9a83b93ed 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2352,7 +2352,8 @@ _equalRangeTblEntry(const RangeTblEntry *a, const RangeTblEntry *b)
COMPARE_SCALAR_FIELD(requiredPerms);
COMPARE_SCALAR_FIELD(checkAsUser);
COMPARE_BITMAPSET_FIELD(selectedCols);
- COMPARE_BITMAPSET_FIELD(modifiedCols);
+ COMPARE_BITMAPSET_FIELD(insertedCols);
+ COMPARE_BITMAPSET_FIELD(updatedCols);
COMPARE_NODE_FIELD(securityQuals);
return true;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index f9f948e39bb..d5ddd0b3592 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2475,7 +2475,8 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
WRITE_UINT_FIELD(requiredPerms);
WRITE_OID_FIELD(checkAsUser);
WRITE_BITMAPSET_FIELD(selectedCols);
- WRITE_BITMAPSET_FIELD(modifiedCols);
+ WRITE_BITMAPSET_FIELD(insertedCols);
+ WRITE_BITMAPSET_FIELD(updatedCols);
WRITE_NODE_FIELD(securityQuals);
}
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index b0cd95da063..d1ced0cc4b3 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1256,7 +1256,8 @@ _readRangeTblEntry(void)
READ_UINT_FIELD(requiredPerms);
READ_OID_FIELD(checkAsUser);
READ_BITMAPSET_FIELD(selectedCols);
- READ_BITMAPSET_FIELD(modifiedCols);
+ READ_BITMAPSET_FIELD(insertedCols);
+ READ_BITMAPSET_FIELD(updatedCols);
READ_NODE_FIELD(securityQuals);
READ_DONE();
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 69ed2a574e5..b7d6ff11223 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -373,9 +373,9 @@ flatten_rtes_walker(Node *node, PlannerGlobal *glob)
*
* In the flat rangetable, we zero out substructure pointers that are not
* needed by the executor; this reduces the storage space and copying cost
- * for cached plans. We keep only the alias and eref Alias fields, which
- * are needed by EXPLAIN, and the selectedCols and modifiedCols bitmaps,
- * which are needed for executor-startup permissions checking and for
+ * for cached plans. We keep only the alias and eref Alias fields, which are
+ * needed by EXPLAIN, and the selectedCols, insertedCols and updatedCols
+ * bitmaps, which are needed for executor-startup permissions checking and for
* trigger event checking.
*/
static void
diff --git a/src/backend/optimizer/prep/prepsecurity.c b/src/backend/optimizer/prep/prepsecurity.c
index 0be44c1c2f7..c4b61df3003 100644
--- a/src/backend/optimizer/prep/prepsecurity.c
+++ b/src/backend/optimizer/prep/prepsecurity.c
@@ -125,7 +125,8 @@ expand_security_quals(PlannerInfo *root, List *tlist)
rte->requiredPerms = 0;
rte->checkAsUser = InvalidOid;
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* For the most part, Vars referencing the original relation
@@ -224,7 +225,8 @@ expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
rte->requiredPerms = 0;
rte->checkAsUser = InvalidOid;
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* Now deal with any PlanRowMark on this RTE by requesting a lock
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 51b3da21b30..5859748df8e 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1368,14 +1368,16 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
* if this is the parent table, leave copyObject's result alone.
*
* Note: we need to do this even though the executor won't run any
- * permissions checks on the child RTE. The modifiedCols bitmap may
- * be examined for trigger-firing purposes.
+ * permissions checks on the child RTE. The insertedCols/updatedCols
+ * bitmaps may be examined for trigger-firing purposes.
*/
if (childOID != parentOID)
{
childrte->selectedCols = translate_col_privs(rte->selectedCols,
appinfo->translated_vars);
- childrte->modifiedCols = translate_col_privs(rte->modifiedCols,
+ childrte->insertedCols = translate_col_privs(rte->insertedCols,
+ appinfo->translated_vars);
+ childrte->updatedCols = translate_col_privs(rte->updatedCols,
appinfo->translated_vars);
}
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 4a5a5205391..2d320d100b8 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -733,7 +733,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
false);
qry->targetList = lappend(qry->targetList, tle);
- rte->modifiedCols = bms_add_member(rte->modifiedCols,
+ rte->insertedCols = bms_add_member(rte->insertedCols,
attr_num - FirstLowInvalidHeapAttributeNumber);
icols = lnext(icols);
@@ -2002,7 +2002,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
origTarget->location);
/* Mark the target column as requiring update permissions */
- target_rte->modifiedCols = bms_add_member(target_rte->modifiedCols,
+ target_rte->updatedCols = bms_add_member(target_rte->updatedCols,
attrno - FirstLowInvalidHeapAttributeNumber);
origTargetList = lnext(origTargetList);
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index ca560ccee1b..562c2f54f92 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1218,7 +1218,8 @@ addRangeTableEntry(ParseState *pstate,
rte->requiredPerms = ACL_SELECT;
rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
@@ -1272,7 +1273,8 @@ addRangeTableEntryForRelation(ParseState *pstate,
rte->requiredPerms = ACL_SELECT;
rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
@@ -1351,7 +1353,8 @@ addRangeTableEntryForSubquery(ParseState *pstate,
rte->requiredPerms = 0;
rte->checkAsUser = InvalidOid;
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
@@ -1606,7 +1609,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
rte->requiredPerms = 0;
rte->checkAsUser = InvalidOid;
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
@@ -1679,7 +1683,8 @@ addRangeTableEntryForValues(ParseState *pstate,
rte->requiredPerms = 0;
rte->checkAsUser = InvalidOid;
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
@@ -1748,7 +1753,8 @@ addRangeTableEntryForJoin(ParseState *pstate,
rte->requiredPerms = 0;
rte->checkAsUser = InvalidOid;
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
@@ -1849,7 +1855,8 @@ addRangeTableEntryForCTE(ParseState *pstate,
rte->requiredPerms = 0;
rte->checkAsUser = InvalidOid;
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* Add completed RTE to pstate's range table list, but not to join list
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 60c60caf396..0fc47cb786c 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -1403,7 +1403,8 @@ ApplyRetrieveRule(Query *parsetree,
rte->requiredPerms = 0;
rte->checkAsUser = InvalidOid;
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* For the most part, Vars referencing the view should remain as
@@ -1466,12 +1467,14 @@ ApplyRetrieveRule(Query *parsetree,
subrte->requiredPerms = rte->requiredPerms;
subrte->checkAsUser = rte->checkAsUser;
subrte->selectedCols = rte->selectedCols;
- subrte->modifiedCols = rte->modifiedCols;
+ subrte->insertedCols = rte->insertedCols;
+ subrte->updatedCols = rte->updatedCols;
rte->requiredPerms = 0; /* no permission check on subquery itself */
rte->checkAsUser = InvalidOid;
rte->selectedCols = NULL;
- rte->modifiedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
/*
* If FOR [KEY] UPDATE/SHARE of view, mark all the contained tables as
@@ -2621,9 +2624,9 @@ rewriteTargetView(Query *parsetree, Relation view)
/*
* For INSERT/UPDATE the modified columns must all be updatable. Note that
* we get the modified columns from the query's targetlist, not from the
- * result RTE's modifiedCols set, since rewriteTargetListIU may have added
- * additional targetlist entries for view defaults, and these must also be
- * updatable.
+ * result RTE's insertedCols and/or updatedCols set, since
+ * rewriteTargetListIU may have added additional targetlist entries for
+ * view defaults, and these must also be updatable.
*/
if (parsetree->commandType != CMD_DELETE)
{
@@ -2760,28 +2763,33 @@ rewriteTargetView(Query *parsetree, Relation view)
*
* Initially, new_rte contains selectedCols permission check bits for all
* base-rel columns referenced by the view, but since the view is a SELECT
- * query its modifiedCols is empty. We set modifiedCols to include all
- * the columns the outer query is trying to modify, adjusting the column
- * numbers as needed. But we leave selectedCols as-is, so the view owner
- * must have read permission for all columns used in the view definition,
- * even if some of them are not read by the outer query. We could try to
- * limit selectedCols to only columns used in the transformed query, but
- * that does not correspond to what happens in ordinary SELECT usage of a
- * view: all referenced columns must have read permission, even if
- * optimization finds that some of them can be discarded during query
- * transformation. The flattening we're doing here is an optional
- * optimization, too. (If you are unpersuaded and want to change this,
- * note that applying adjust_view_column_set to view_rte->selectedCols is
- * clearly *not* the right answer, since that neglects base-rel columns
- * used in the view's WHERE quals.)
+ * query its insertedCols/updatedCols is empty. We set insertedCols and
+ * updatedCols to include all the columns the outer query is trying to
+ * modify, adjusting the column numbers as needed. But we leave
+ * selectedCols as-is, so the view owner must have read permission for all
+ * columns used in the view definition, even if some of them are not read
+ * by the outer query. We could try to limit selectedCols to only columns
+ * used in the transformed query, but that does not correspond to what
+ * happens in ordinary SELECT usage of a view: all referenced columns must
+ * have read permission, even if optimization finds that some of them can
+ * be discarded during query transformation. The flattening we're doing
+ * here is an optional optimization, too. (If you are unpersuaded and want
+ * to change this, note that applying adjust_view_column_set to
+ * view_rte->selectedCols is clearly *not* the right answer, since that
+ * neglects base-rel columns used in the view's WHERE quals.)
*
* This step needs the modified view targetlist, so we have to do things
* in this order.
*/
- Assert(bms_is_empty(new_rte->modifiedCols));
- new_rte->modifiedCols = adjust_view_column_set(view_rte->modifiedCols,
+ Assert(bms_is_empty(new_rte->insertedCols) &&
+ bms_is_empty(new_rte->updatedCols));
+
+ new_rte->insertedCols = adjust_view_column_set(view_rte->insertedCols,
view_targetlist);
+ new_rte->updatedCols = adjust_view_column_set(view_rte->updatedCols,
+ view_targetlist);
+
/*
* Move any security barrier quals from the view RTE onto the new target
* RTE. Any such quals should now apply to the new target RTE and will
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 2444e543a70..3d2c5b2a293 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201505071
+#define CATALOG_VERSION_NO 201505081
#endif
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 852eb4fbdc9..7d15ef2847b 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -735,11 +735,12 @@ typedef struct XmlSerialize
* For SELECT/INSERT/UPDATE permissions, if the user doesn't have
* table-wide permissions then it is sufficient to have the permissions
* on all columns identified in selectedCols (for SELECT) and/or
- * modifiedCols (for INSERT/UPDATE; we can tell which from the query type).
- * selectedCols and modifiedCols are bitmapsets, which cannot have negative
- * integer members, so we subtract FirstLowInvalidHeapAttributeNumber from
- * column numbers before storing them in these fields. A whole-row Var
- * reference is represented by setting the bit for InvalidAttrNumber.
+ * insertedCols and/or updatedCols (INSERT with ON CONFLICT UPDATE may
+ * have all 3). selectedCols, insertedCols and updatedCols are
+ * bitmapsets, which cannot have negative integer members, so we subtract
+ * FirstLowInvalidHeapAttributeNumber from column numbers before storing
+ * them in these fields. A whole-row Var reference is represented by
+ * setting the bit for InvalidAttrNumber.
*--------------------
*/
typedef enum RTEKind
@@ -834,7 +835,8 @@ typedef struct RangeTblEntry
AclMode requiredPerms; /* bitmask of required access permissions */
Oid checkAsUser; /* if valid, check access as this role */
Bitmapset *selectedCols; /* columns needing SELECT permission */
- Bitmapset *modifiedCols; /* columns needing INSERT/UPDATE permission */
+ Bitmapset *insertedCols; /* columns needing INSERT permission */
+ Bitmapset *updatedCols; /* columns needing UPDATE permission */
List *securityQuals; /* any security barrier quals to apply */
} RangeTblEntry;