Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf50e888

Browse files
committed
Fix permission checks on constraint violation errors on partitions.
If a cross-partition UPDATE violates a constraint on the target partition,and the columns in the new partition are in different physical order thanin the parent, the error message can reveal columns that the user does nothave SELECT permission on. A similar bug was fixed earlier in commit804b6b6.The cause of the bug is that the callers of theExecBuildSlotValueDescription() function got confused when constructingthe list of modified columns. If the tuple was routed from a parent, weconverted the tuple to the parent's format, but the list of modifiedcolumns was grabbed directly from the child's RTE entry.ExecUpdateLockMode() had a similar issue. That lead to confusion on whichcolumns are key columns, leading to wrong tuple lock being taken on tablesreferenced by foreign keys, when a row is updated with INSERT ON CONFLICTUPDATE. A new isolation test is added for that corner case.With this patch, the ri_RangeTableIndex field is no longer set forpartitions that don't have an entry in the range table. Previously, it wasset to the RTE entry of the parent relation, but that was confusing.NOTE: This modifies the ResultRelInfo struct, replacing theri_PartitionRoot field with ri_RootResultRelInfo. That's a bit risky tobackpatch, because it breaks any extensions accessing the field. Thechange that ri_RangeTableIndex is not set for partitions could potentiallybreak extensions, too. The ResultRelInfos are visible to FDWs at least,and this patch required small changes to postgres_fdw. Nevertheless, thisseem like the least bad option. I don't think these fields widely used inextensions; I don't think there are FDWs out there that uses the FDW"direct update" API, other than postgres_fdw. If there is, you will get acompilation error, so hopefully it is caught quickly.Backpatch to 11, where support for both cross-partition UPDATEs, and uniqueindexes on partitioned tables, were added.Reviewed-by: Amit LangoteSecurity:CVE-2021-3393
1 parente474abd commitf50e888

File tree

17 files changed

+371
-88
lines changed

17 files changed

+371
-88
lines changed

‎contrib/postgres_fdw/postgres_fdw.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,7 +1934,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
19341934
PgFdwModifyState*fmstate;
19351935
ModifyTable*plan=castNode(ModifyTable,mtstate->ps.plan);
19361936
EState*estate=mtstate->ps.state;
1937-
IndexresultRelation=resultRelInfo->ri_RangeTableIndex;
1937+
IndexresultRelation;
19381938
Relationrel=resultRelInfo->ri_RelationDesc;
19391939
RangeTblEntry*rte;
19401940
TupleDesctupdesc=RelationGetDescr(rel);
@@ -1985,17 +1985,20 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
19851985
}
19861986

19871987
/*
1988-
* If the foreign table is a partition, we need to create a new RTE
1988+
* If the foreign table is a partition that doesn't have a corresponding
1989+
* RTE entry, we need to create a new RTE
19891990
* describing the foreign table for use by deparseInsertSql and
19901991
* create_foreign_modify() below, after first copying the parent's RTE and
19911992
* modifying some fields to describe the foreign partition to work on.
19921993
* However, if this is invoked by UPDATE, the existing RTE may already
19931994
* correspond to this partition if it is one of the UPDATE subplan target
19941995
* rels; in that case, we can just use the existing RTE as-is.
19951996
*/
1996-
rte=exec_rt_fetch(resultRelation,estate);
1997-
if (rte->relid!=RelationGetRelid(rel))
1997+
if (resultRelInfo->ri_RangeTableIndex==0)
19981998
{
1999+
ResultRelInfo*rootResultRelInfo=resultRelInfo->ri_RootResultRelInfo;
2000+
2001+
rte=exec_rt_fetch(rootResultRelInfo->ri_RangeTableIndex,estate);
19992002
rte=copyObject(rte);
20002003
rte->relid=RelationGetRelid(rel);
20012004
rte->relkind=RELKIND_FOREIGN_TABLE;
@@ -2007,8 +2010,15 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
20072010
* Vars contained in those expressions.
20082011
*/
20092012
if (plan&&plan->operation==CMD_UPDATE&&
2010-
resultRelation==plan->rootRelation)
2013+
rootResultRelInfo->ri_RangeTableIndex==plan->rootRelation)
20112014
resultRelation=mtstate->resultRelInfo[0].ri_RangeTableIndex;
2015+
else
2016+
resultRelation=rootResultRelInfo->ri_RangeTableIndex;
2017+
}
2018+
else
2019+
{
2020+
resultRelation=resultRelInfo->ri_RangeTableIndex;
2021+
rte=exec_rt_fetch(resultRelation,estate);
20122022
}
20132023

20142024
/* Construct the SQL command string. */

‎src/backend/access/common/tupconvert.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,59 @@ execute_attr_map_slot(AttrNumber *attrMap,
493493
returnout_slot;
494494
}
495495

496+
/*
497+
* Perform conversion of bitmap of columns according to the map.
498+
*
499+
* The input and output bitmaps are offset by
500+
* FirstLowInvalidHeapAttributeNumber to accommodate system cols, like the
501+
* column-bitmaps in RangeTblEntry.
502+
*/
503+
Bitmapset*
504+
execute_attr_map_cols(Bitmapset*in_cols,TupleConversionMap*map)
505+
{
506+
AttrNumber*attrMap=map->attrMap;
507+
intmaplen=map->outdesc->natts;
508+
Bitmapset*out_cols;
509+
intout_attnum;
510+
511+
/* fast path for the common trivial case */
512+
if (in_cols==NULL)
513+
returnNULL;
514+
515+
/*
516+
* For each output column, check which input column it corresponds to.
517+
*/
518+
out_cols=NULL;
519+
520+
for (out_attnum=FirstLowInvalidHeapAttributeNumber+1;
521+
out_attnum <=maplen;
522+
out_attnum++)
523+
{
524+
intin_attnum;
525+
526+
if (out_attnum<0)
527+
{
528+
/* System column. No mapping. */
529+
in_attnum=out_attnum;
530+
}
531+
elseif (out_attnum==0)
532+
continue;
533+
else
534+
{
535+
/* normal user column */
536+
in_attnum=attrMap[out_attnum-1];
537+
538+
if (in_attnum==0)
539+
continue;
540+
}
541+
542+
if (bms_is_member(in_attnum-FirstLowInvalidHeapAttributeNumber,in_cols))
543+
out_cols=bms_add_member(out_cols,out_attnum-FirstLowInvalidHeapAttributeNumber);
544+
}
545+
546+
returnout_cols;
547+
}
548+
496549
/*
497550
* Free a TupleConversionMap structure.
498551
*/

‎src/backend/commands/copy.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2858,6 +2858,7 @@ CopyFrom(CopyState cstate)
28582858
mtstate->ps.state=estate;
28592859
mtstate->operation=CMD_INSERT;
28602860
mtstate->resultRelInfo=estate->es_result_relations;
2861+
mtstate->rootResultRelInfo=estate->es_result_relations;
28612862

28622863
if (resultRelInfo->ri_FdwRoutine!=NULL&&
28632864
resultRelInfo->ri_FdwRoutine->BeginForeignInsert!=NULL)

‎src/backend/commands/explain.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3210,7 +3210,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
32103210
/* Should we explicitly label target relations? */
32113211
labeltargets= (mtstate->mt_nplans>1||
32123212
(mtstate->mt_nplans==1&&
3213-
mtstate->resultRelInfo->ri_RangeTableIndex!=node->nominalRelation));
3213+
mtstate->resultRelInfo[0].ri_RangeTableIndex!=node->nominalRelation));
32143214

32153215
if (labeltargets)
32163216
ExplainOpenGroup("Target Tables","Target Tables", false,es);

‎src/backend/commands/trigger.c

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,6 @@ intSessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
6969
/* How many levels deep into trigger execution are we? */
7070
staticintMyTriggerDepth=0;
7171

72-
/*
73-
* Note that similar macros also exist in executor/execMain.c. There does not
74-
* appear to be any good header to put them into, given the structures that
75-
* they use, so we let them be duplicated. Be sure to update all if one needs
76-
* to be changed, however.
77-
*/
78-
#defineGetAllUpdatedColumns(relinfo,estate) \
79-
(bms_union(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols, \
80-
exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->extraUpdatedCols))
81-
8272
/* Local function prototypes */
8373
staticvoidConvertTriggerToFK(CreateTrigStmt*stmt,Oidfuncoid);
8474
staticvoidSetTriggerFlags(TriggerDesc*trigdesc,Trigger*trigger);
@@ -2928,7 +2918,10 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
29282918
CMD_UPDATE))
29292919
return;
29302920

2931-
updatedCols=GetAllUpdatedColumns(relinfo,estate);
2921+
/* statement-level triggers operate on the parent table */
2922+
Assert(relinfo->ri_RootResultRelInfo==NULL);
2923+
2924+
updatedCols=ExecGetAllUpdatedCols(relinfo,estate);
29322925

29332926
LocTriggerData.type=T_TriggerData;
29342927
LocTriggerData.tg_event=TRIGGER_EVENT_UPDATE |
@@ -2974,10 +2967,13 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
29742967
{
29752968
TriggerDesc*trigdesc=relinfo->ri_TrigDesc;
29762969

2970+
/* statement-level triggers operate on the parent table */
2971+
Assert(relinfo->ri_RootResultRelInfo==NULL);
2972+
29772973
if (trigdesc&&trigdesc->trig_update_after_statement)
29782974
AfterTriggerSaveEvent(estate,relinfo,TRIGGER_EVENT_UPDATE,
29792975
false,NULL,NULL,NIL,
2980-
GetAllUpdatedColumns(relinfo,estate),
2976+
ExecGetAllUpdatedCols(relinfo,estate),
29812977
transition_capture);
29822978
}
29832979

@@ -3049,7 +3045,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
30493045
LocTriggerData.tg_relation=relinfo->ri_RelationDesc;
30503046
LocTriggerData.tg_oldtable=NULL;
30513047
LocTriggerData.tg_newtable=NULL;
3052-
updatedCols=GetAllUpdatedColumns(relinfo,estate);
3048+
updatedCols=ExecGetAllUpdatedCols(relinfo,estate);
30533049
for (i=0;i<trigdesc->numtriggers;i++)
30543050
{
30553051
Trigger*trigger=&trigdesc->triggers[i];
@@ -3149,7 +3145,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
31493145

31503146
AfterTriggerSaveEvent(estate,relinfo,TRIGGER_EVENT_UPDATE,
31513147
true,oldslot,newslot,recheckIndexes,
3152-
GetAllUpdatedColumns(relinfo,estate),
3148+
ExecGetAllUpdatedCols(relinfo,estate),
31533149
transition_capture);
31543150
}
31553151
}

‎src/backend/executor/execMain.c

Lines changed: 39 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -100,20 +100,6 @@ static char *ExecBuildSlotValueDescription(Oid reloid,
100100
intmaxfieldlen);
101101
staticvoidEvalPlanQualStart(EPQState*epqstate,Plan*planTree);
102102

103-
/*
104-
* Note that GetAllUpdatedColumns() also exists in commands/trigger.c. There does
105-
* not appear to be any good header to put it into, given the structures that
106-
* it uses, so we let them be duplicated. Be sure to update both if one needs
107-
* to be changed, however.
108-
*/
109-
#defineGetInsertedColumns(relinfo,estate) \
110-
(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->insertedCols)
111-
#defineGetUpdatedColumns(relinfo,estate) \
112-
(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols)
113-
#defineGetAllUpdatedColumns(relinfo,estate) \
114-
(bms_union(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols, \
115-
exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->extraUpdatedCols))
116-
117103
/* end of local decls */
118104

119105

@@ -1277,7 +1263,7 @@ void
12771263
InitResultRelInfo(ResultRelInfo*resultRelInfo,
12781264
RelationresultRelationDesc,
12791265
IndexresultRelationIndex,
1280-
Relationpartition_root,
1266+
ResultRelInfo*partition_root_rri,
12811267
intinstrument_options)
12821268
{
12831269
List*partition_check=NIL;
@@ -1342,7 +1328,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
13421328
partition_check=RelationGetPartitionQual(resultRelationDesc);
13431329

13441330
resultRelInfo->ri_PartitionCheck=partition_check;
1345-
resultRelInfo->ri_PartitionRoot=partition_root;
1331+
resultRelInfo->ri_RootResultRelInfo=partition_root_rri;
13461332
resultRelInfo->ri_PartitionInfo=NULL;/* may be set later */
13471333
resultRelInfo->ri_CopyMultiInsertBuffer=NULL;
13481334
}
@@ -1840,13 +1826,14 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
18401826
* back to the root table's rowtype so that val_desc in the error message
18411827
* matches the input tuple.
18421828
*/
1843-
if (resultRelInfo->ri_PartitionRoot)
1829+
if (resultRelInfo->ri_RootResultRelInfo)
18441830
{
1831+
ResultRelInfo*rootrel=resultRelInfo->ri_RootResultRelInfo;
18451832
TupleDescold_tupdesc;
18461833
AttrNumber*map;
18471834

1848-
root_relid=RelationGetRelid(resultRelInfo->ri_PartitionRoot);
1849-
tupdesc=RelationGetDescr(resultRelInfo->ri_PartitionRoot);
1835+
root_relid=RelationGetRelid(rootrel->ri_RelationDesc);
1836+
tupdesc=RelationGetDescr(rootrel->ri_RelationDesc);
18501837

18511838
old_tupdesc=RelationGetDescr(resultRelInfo->ri_RelationDesc);
18521839
/* a reverse map */
@@ -1860,16 +1847,17 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
18601847
if (map!=NULL)
18611848
slot=execute_attr_map_slot(map,slot,
18621849
MakeTupleTableSlot(tupdesc,&TTSOpsVirtual));
1850+
modifiedCols=bms_union(ExecGetInsertedCols(rootrel,estate),
1851+
ExecGetUpdatedCols(rootrel,estate));
18631852
}
18641853
else
18651854
{
18661855
root_relid=RelationGetRelid(resultRelInfo->ri_RelationDesc);
18671856
tupdesc=RelationGetDescr(resultRelInfo->ri_RelationDesc);
1857+
modifiedCols=bms_union(ExecGetInsertedCols(resultRelInfo,estate),
1858+
ExecGetUpdatedCols(resultRelInfo,estate));
18681859
}
18691860

1870-
modifiedCols=bms_union(GetInsertedColumns(resultRelInfo,estate),
1871-
GetUpdatedColumns(resultRelInfo,estate));
1872-
18731861
val_desc=ExecBuildSlotValueDescription(root_relid,
18741862
slot,
18751863
tupdesc,
@@ -1901,8 +1889,6 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
19011889
TupleDesctupdesc=RelationGetDescr(rel);
19021890
TupleConstr*constr=tupdesc->constr;
19031891
Bitmapset*modifiedCols;
1904-
Bitmapset*insertedCols;
1905-
Bitmapset*updatedCols;
19061892

19071893
Assert(constr||resultRelInfo->ri_PartitionCheck);
19081894

@@ -1928,12 +1914,12 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
19281914
* rowtype so that val_desc shown error message matches the
19291915
* input tuple.
19301916
*/
1931-
if (resultRelInfo->ri_PartitionRoot)
1917+
if (resultRelInfo->ri_RootResultRelInfo)
19321918
{
1919+
ResultRelInfo*rootrel=resultRelInfo->ri_RootResultRelInfo;
19331920
AttrNumber*map;
19341921

1935-
rel=resultRelInfo->ri_PartitionRoot;
1936-
tupdesc=RelationGetDescr(rel);
1922+
tupdesc=RelationGetDescr(rootrel->ri_RelationDesc);
19371923
/* a reverse map */
19381924
map=convert_tuples_by_name_map_if_req(orig_tupdesc,
19391925
tupdesc,
@@ -1946,11 +1932,13 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
19461932
if (map!=NULL)
19471933
slot=execute_attr_map_slot(map,slot,
19481934
MakeTupleTableSlot(tupdesc,&TTSOpsVirtual));
1935+
modifiedCols=bms_union(ExecGetInsertedCols(rootrel,estate),
1936+
ExecGetUpdatedCols(rootrel,estate));
1937+
rel=rootrel->ri_RelationDesc;
19491938
}
1950-
1951-
insertedCols=GetInsertedColumns(resultRelInfo,estate);
1952-
updatedCols=GetUpdatedColumns(resultRelInfo,estate);
1953-
modifiedCols=bms_union(insertedCols,updatedCols);
1939+
else
1940+
modifiedCols=bms_union(ExecGetInsertedCols(resultRelInfo,estate),
1941+
ExecGetUpdatedCols(resultRelInfo,estate));
19541942
val_desc=ExecBuildSlotValueDescription(RelationGetRelid(rel),
19551943
slot,
19561944
tupdesc,
@@ -1977,13 +1965,13 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
19771965
Relationorig_rel=rel;
19781966

19791967
/* See the comment above. */
1980-
if (resultRelInfo->ri_PartitionRoot)
1968+
if (resultRelInfo->ri_RootResultRelInfo)
19811969
{
1970+
ResultRelInfo*rootrel=resultRelInfo->ri_RootResultRelInfo;
19821971
TupleDescold_tupdesc=RelationGetDescr(rel);
19831972
AttrNumber*map;
19841973

1985-
rel=resultRelInfo->ri_PartitionRoot;
1986-
tupdesc=RelationGetDescr(rel);
1974+
tupdesc=RelationGetDescr(rootrel->ri_RelationDesc);
19871975
/* a reverse map */
19881976
map=convert_tuples_by_name_map_if_req(old_tupdesc,
19891977
tupdesc,
@@ -1996,11 +1984,13 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
19961984
if (map!=NULL)
19971985
slot=execute_attr_map_slot(map,slot,
19981986
MakeTupleTableSlot(tupdesc,&TTSOpsVirtual));
1987+
modifiedCols=bms_union(ExecGetInsertedCols(rootrel,estate),
1988+
ExecGetUpdatedCols(rootrel,estate));
1989+
rel=rootrel->ri_RelationDesc;
19991990
}
2000-
2001-
insertedCols=GetInsertedColumns(resultRelInfo,estate);
2002-
updatedCols=GetUpdatedColumns(resultRelInfo,estate);
2003-
modifiedCols=bms_union(insertedCols,updatedCols);
1991+
else
1992+
modifiedCols=bms_union(ExecGetInsertedCols(resultRelInfo,estate),
1993+
ExecGetUpdatedCols(resultRelInfo,estate));
20041994
val_desc=ExecBuildSlotValueDescription(RelationGetRelid(rel),
20051995
slot,
20061996
tupdesc,
@@ -2069,8 +2059,6 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
20692059
{
20702060
char*val_desc;
20712061
Bitmapset*modifiedCols;
2072-
Bitmapset*insertedCols;
2073-
Bitmapset*updatedCols;
20742062

20752063
switch (wco->kind)
20762064
{
@@ -2085,13 +2073,13 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
20852073
*/
20862074
caseWCO_VIEW_CHECK:
20872075
/* See the comment in ExecConstraints(). */
2088-
if (resultRelInfo->ri_PartitionRoot)
2076+
if (resultRelInfo->ri_RootResultRelInfo)
20892077
{
2078+
ResultRelInfo*rootrel=resultRelInfo->ri_RootResultRelInfo;
20902079
TupleDescold_tupdesc=RelationGetDescr(rel);
20912080
AttrNumber*map;
20922081

2093-
rel=resultRelInfo->ri_PartitionRoot;
2094-
tupdesc=RelationGetDescr(rel);
2082+
tupdesc=RelationGetDescr(rootrel->ri_RelationDesc);
20952083
/* a reverse map */
20962084
map=convert_tuples_by_name_map_if_req(old_tupdesc,
20972085
tupdesc,
@@ -2104,11 +2092,14 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
21042092
if (map!=NULL)
21052093
slot=execute_attr_map_slot(map,slot,
21062094
MakeTupleTableSlot(tupdesc,&TTSOpsVirtual));
2107-
}
21082095

2109-
insertedCols=GetInsertedColumns(resultRelInfo,estate);
2110-
updatedCols=GetUpdatedColumns(resultRelInfo,estate);
2111-
modifiedCols=bms_union(insertedCols,updatedCols);
2096+
modifiedCols=bms_union(ExecGetInsertedCols(rootrel,estate),
2097+
ExecGetUpdatedCols(rootrel,estate));
2098+
rel=rootrel->ri_RelationDesc;
2099+
}
2100+
else
2101+
modifiedCols=bms_union(ExecGetInsertedCols(resultRelInfo,estate),
2102+
ExecGetUpdatedCols(resultRelInfo,estate));
21122103
val_desc=ExecBuildSlotValueDescription(RelationGetRelid(rel),
21132104
slot,
21142105
tupdesc,
@@ -2322,7 +2313,7 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
23222313
* been modified, then we can use a weaker lock, allowing for better
23232314
* concurrency.
23242315
*/
2325-
updatedCols=GetAllUpdatedColumns(relinfo,estate);
2316+
updatedCols=ExecGetAllUpdatedCols(relinfo,estate);
23262317
keyCols=RelationGetIndexAttrBitmap(relinfo->ri_RelationDesc,
23272318
INDEX_ATTR_BITMAP_KEY);
23282319

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp