Skip to content

Commit 5707f35

Browse files
committed
Fix unsafe order of operations in foreign-table DDL commands.
When updating or deleting a system catalog tuple, it's necessary to acquire RowExclusiveLock on the catalog before looking up the tuple; otherwise a concurrent VACUUM FULL on the catalog might move the tuple to a different TID before we can apply the update. Coding patterns that find the tuple via a table scan aren't at risk here, but when obtaining the tuple from a catalog cache, correct ordering is important; and several routines in foreigncmds.c got it wrong. Noted while running the regression tests in parallel with VACUUM FULL of assorted system catalogs. For consistency I moved all the heap_open calls to the starts of their functions, including a couple for which there was no actual bug. Back-patch to 8.4 where foreigncmds.c was added.
1 parent 739cbdd commit 5707f35

File tree

1 file changed

+14
-17
lines changed

1 file changed

+14
-17
lines changed

src/backend/commands/foreigncmds.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
202202
Oid fdwId;
203203
Form_pg_foreign_data_wrapper form;
204204

205+
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
206+
205207
/* Must be a superuser to change a FDW owner */
206208
if (!superuser())
207209
ereport(ERROR,
@@ -218,8 +220,6 @@ AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
218220
name),
219221
errhint("The owner of a foreign-data wrapper must be a superuser.")));
220222

221-
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
222-
223223
tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(name));
224224

225225
if (!HeapTupleIsValid(tup))
@@ -340,6 +340,8 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
340340
Datum fdwoptions;
341341
Oid ownerId;
342342

343+
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
344+
343345
/* Must be super user */
344346
if (!superuser())
345347
ereport(ERROR,
@@ -363,8 +365,6 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
363365
/*
364366
* Insert tuple into pg_foreign_data_wrapper.
365367
*/
366-
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
367-
368368
memset(values, 0, sizeof(values));
369369
memset(nulls, false, sizeof(nulls));
370370

@@ -435,6 +435,8 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
435435
Datum datum;
436436
Oid fdwvalidator;
437437

438+
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
439+
438440
/* Must be super user */
439441
if (!superuser())
440442
ereport(ERROR,
@@ -513,9 +515,6 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
513515
}
514516

515517
/* Everything looks good - update the tuple */
516-
517-
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
518-
519518
tp = heap_modify_tuple(tp, RelationGetDescr(rel),
520519
repl_val, repl_null, repl_repl);
521520

@@ -613,6 +612,8 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
613612
ObjectAddress referenced;
614613
ForeignDataWrapper *fdw;
615614

615+
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
616+
616617
/* For now the owner cannot be specified on create. Use effective user ID. */
617618
ownerId = GetUserId();
618619

@@ -638,8 +639,6 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
638639
/*
639640
* Insert tuple into pg_foreign_server.
640641
*/
641-
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
642-
643642
memset(values, 0, sizeof(values));
644643
memset(nulls, false, sizeof(nulls));
645644

@@ -714,6 +713,8 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
714713
Oid srvId;
715714
Form_pg_foreign_server srvForm;
716715

716+
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
717+
717718
tp = SearchSysCacheCopy1(FOREIGNSERVERNAME,
718719
CStringGetDatum(stmt->servername));
719720

@@ -779,9 +780,6 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
779780
}
780781

781782
/* Everything looks good - update the tuple */
782-
783-
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
784-
785783
tp = heap_modify_tuple(tp, RelationGetDescr(rel),
786784
repl_val, repl_null, repl_repl);
787785

@@ -901,6 +899,8 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
901899
ForeignServer *srv;
902900
ForeignDataWrapper *fdw;
903901

902+
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
903+
904904
useId = GetUserOidFromMapping(stmt->username, false);
905905

906906
/* Check that the server exists. */
@@ -926,8 +926,6 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
926926
/*
927927
* Insert tuple into pg_user_mapping.
928928
*/
929-
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
930-
931929
memset(values, 0, sizeof(values));
932930
memset(nulls, false, sizeof(nulls));
933931

@@ -986,6 +984,8 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
986984
Oid umId;
987985
ForeignServer *srv;
988986

987+
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
988+
989989
useId = GetUserOidFromMapping(stmt->username, false);
990990
srv = GetForeignServerByName(stmt->servername, false);
991991

@@ -1043,9 +1043,6 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
10431043
}
10441044

10451045
/* Everything looks good - update the tuple */
1046-
1047-
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
1048-
10491046
tp = heap_modify_tuple(tp, RelationGetDescr(rel),
10501047
repl_val, repl_null, repl_repl);
10511048

0 commit comments

Comments
 (0)