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

Commit2d43c30

Browse files
committed
Avoid trying to restore table ACLs and per-column ACLs in parallel.
Parallel pg_restore has always supposed that ACL items for differentobjects are independent and can be restored in parallel withoutconflicts. However, there is one case where this fails: becauseREVOKE on a table is defined to also revoke the privilege(s) atcolumn level, we can't restore per-column ACLs till after we restoreany table-level privileges on their table. Failure to honor thisrestriction can lead to "tuple concurrently updated" errors duringparallel restore, or even to the per-column ACLs silently disappearingbecause the table-level REVOKE is executed afterwards.To fix, add a dependency from each column-level ACL item to its table'sACL item, if there is one. Note that this doesn't fix the hazardfor pre-existing archive files, only for ones made with a correctedpg_dump. Given that the bug's been there quite awhile withoutfield reports, I think this is acceptable.This requires changing the API of pg_dump's dumpACL() function.To keep its argument list from getting even longer, I removed the"CatalogId objCatId" argument, which has been unused for ages.Per report from Justin Pryzby. Back-patch to all supported branches.Discussion:https://postgr.es/m/20200706050129.GW4107@telsasoft.com
1 parentda76f05 commit2d43c30

File tree

3 files changed

+58
-29
lines changed

3 files changed

+58
-29
lines changed

‎src/bin/pg_dump/common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
*/
3131
staticDumpableObject**dumpIdMap=NULL;
3232
staticintallocedDumpIds=0;
33-
staticDumpIdlastDumpId=0;
33+
staticDumpIdlastDumpId=0;/* Note: 0 is InvalidDumpId */
3434

3535
/*
3636
* Variables for mapping CatalogId to DumpableObject

‎src/bin/pg_dump/pg_backup.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,12 @@ typedef struct
231231

232232
typedefintDumpId;
233233

234+
#defineInvalidDumpId 0
235+
236+
/*
237+
* Function pointer prototypes for assorted callback methods.
238+
*/
239+
234240
typedefint (*DataDumperPtr) (Archive*AH,void*userArg);
235241

236242
typedefvoid (*SetupWorkerPtrType) (Archive*AH);

‎src/bin/pg_dump/pg_dump.c

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ static void dumpUserMappings(Archive *fout,
216216
const char *owner, CatalogId catalogId, DumpId dumpId);
217217
static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
218218

219-
staticvoid dumpACL(Archive *fout,CatalogId objCatId, DumpIdobjDumpId,
219+
staticDumpId dumpACL(Archive *fout,DumpId objDumpId, DumpIdaltDumpId,
220220
const char *type, const char *name, const char *subname,
221221
const char *nspname, const char *owner,
222222
const char *acls, const char *racls,
@@ -3080,7 +3080,7 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
30803080

30813081
/* Dump ACL if any */
30823082
if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3083-
dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3083+
dumpACL(fout, binfo->dobj.dumpId, InvalidDumpId, "LARGE OBJECT",
30843084
binfo->dobj.name, NULL,
30853085
NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
30863086
binfo->initblobacl, binfo->initrblobacl);
@@ -9571,7 +9571,7 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
95719571
nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
95729572

95739573
if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9574-
dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9574+
dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
95759575
qnspname, NULL, NULL,
95769576
nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
95779577
nspinfo->initnspacl, nspinfo->initrnspacl);
@@ -9851,7 +9851,7 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
98519851
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
98529852

98539853
if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
9854-
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
9854+
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
98559855
qtypname, NULL,
98569856
tyinfo->dobj.namespace->dobj.name,
98579857
tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
@@ -9977,7 +9977,7 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
99779977
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
99789978

99799979
if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
9980-
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
9980+
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
99819981
qtypname, NULL,
99829982
tyinfo->dobj.namespace->dobj.name,
99839983
tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
@@ -10049,7 +10049,7 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
1004910049
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
1005010050

1005110051
if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10052-
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10052+
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
1005310053
qtypname, NULL,
1005410054
tyinfo->dobj.namespace->dobj.name,
1005510055
tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
@@ -10327,7 +10327,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
1032710327
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
1032810328

1032910329
if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10330-
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10330+
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
1033110331
qtypname, NULL,
1033210332
tyinfo->dobj.namespace->dobj.name,
1033310333
tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
@@ -10483,7 +10483,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
1048310483
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
1048410484

1048510485
if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10486-
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10486+
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
1048710487
qtypname, NULL,
1048810488
tyinfo->dobj.namespace->dobj.name,
1048910489
tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
@@ -10705,7 +10705,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
1070510705
tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
1070610706

1070710707
if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10708-
dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10708+
dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
1070910709
qtypname, NULL,
1071010710
tyinfo->dobj.namespace->dobj.name,
1071110711
tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
@@ -11000,7 +11000,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
1100011000
plang->dobj.catId, 0, plang->dobj.dumpId);
1100111001

1100211002
if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11003-
dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11003+
dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
1100411004
qlanname, NULL, NULL,
1100511005
plang->lanowner, plang->lanacl, plang->rlanacl,
1100611006
plang->initlanacl, plang->initrlanacl);
@@ -11645,7 +11645,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
1164511645
finfo->dobj.catId, 0, finfo->dobj.dumpId);
1164611646

1164711647
if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
11648-
dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
11648+
dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, "FUNCTION",
1164911649
funcsig, NULL,
1165011650
finfo->dobj.namespace->dobj.name,
1165111651
finfo->rolname, finfo->proacl, finfo->rproacl,
@@ -13580,7 +13580,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
1358013580
aggsig = format_function_signature(fout, &agginfo->aggfn, true);
1358113581

1358213582
if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
13583-
dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
13583+
dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
1358413584
"FUNCTION", aggsig, NULL,
1358513585
agginfo->aggfn.dobj.namespace->dobj.name,
1358613586
agginfo->aggfn.rolname, agginfo->aggfn.proacl,
@@ -13984,7 +13984,7 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
1398413984

1398513985
/* Handle the ACL */
1398613986
if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
13987-
dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
13987+
dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
1398813988
"FOREIGN DATA WRAPPER", qfdwname, NULL,
1398913989
NULL, fdwinfo->rolname,
1399013990
fdwinfo->fdwacl, fdwinfo->rfdwacl,
@@ -14075,7 +14075,7 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
1407514075

1407614076
/* Handle the ACL */
1407714077
if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14078-
dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14078+
dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
1407914079
"FOREIGN SERVER", qsrvname, NULL,
1408014080
NULL, srvinfo->rolname,
1408114081
srvinfo->srvacl, srvinfo->rsrvacl,
@@ -14277,8 +14277,9 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
1427714277
/*----------
1427814278
* Write out grant/revoke information
1427914279
*
14280-
* 'objCatId' is the catalog ID of the underlying object.
1428114280
* 'objDumpId' is the dump ID of the underlying object.
14281+
* 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
14282+
*or InvalidDumpId if there is no need for a second dependency.
1428214283
* 'type' must be one of
1428314284
*TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
1428414285
*FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
@@ -14301,25 +14302,29 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
1430114302
* NB: initacls/initracls are needed because extensions can set privileges on
1430214303
* an object during the extension's script file and we record those into
1430314304
* pg_init_privs as that object's initial privileges.
14305+
*
14306+
* Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
14307+
* no ACL entry was created.
1430414308
*----------
1430514309
*/
14306-
staticvoid
14307-
dumpACL(Archive *fout,CatalogId objCatId, DumpIdobjDumpId,
14310+
staticDumpId
14311+
dumpACL(Archive *fout,DumpId objDumpId, DumpIdaltDumpId,
1430814312
const char *type, const char *name, const char *subname,
1430914313
const char *nspname, const char *owner,
1431014314
const char *acls, const char *racls,
1431114315
const char *initacls, const char *initracls)
1431214316
{
14317+
DumpIdaclDumpId = InvalidDumpId;
1431314318
DumpOptions *dopt = fout->dopt;
1431414319
PQExpBuffer sql;
1431514320

1431614321
/* Do nothing if ACL dump is not enabled */
1431714322
if (dopt->aclsSkip)
14318-
return;
14323+
return InvalidDumpId;
1431914324

1432014325
/* --data-only skips ACLs *except* BLOB ACLs */
1432114326
if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14322-
return;
14327+
return InvalidDumpId;
1432314328

1432414329
sql = createPQExpBuffer();
1432514330

@@ -14353,24 +14358,35 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
1435314358
if (sql->len > 0)
1435414359
{
1435514360
PQExpBuffer tag = createPQExpBuffer();
14361+
DumpIdaclDeps[2];
14362+
intnDeps = 0;
1435614363

1435714364
if (subname)
1435814365
appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
1435914366
else
1436014367
appendPQExpBuffer(tag, "%s %s", type, name);
1436114368

14362-
ArchiveEntry(fout, nilCatalogId, createDumpId(),
14369+
aclDeps[nDeps++] = objDumpId;
14370+
if (altDumpId != InvalidDumpId)
14371+
aclDeps[nDeps++] = altDumpId;
14372+
14373+
aclDumpId = createDumpId();
14374+
14375+
ArchiveEntry(fout, nilCatalogId, aclDumpId,
1436314376
tag->data, nspname,
1436414377
NULL,
1436514378
owner ? owner : "",
1436614379
false, "ACL", SECTION_NONE,
1436714380
sql->data, "", NULL,
14368-
&(objDumpId), 1,
14381+
aclDeps, nDeps,
1436914382
NULL, NULL);
14383+
1437014384
destroyPQExpBuffer(tag);
1437114385
}
1437214386

1437314387
destroyPQExpBuffer(sql);
14388+
14389+
return aclDumpId;
1437414390
}
1437514391

1437614392
/*
@@ -14692,6 +14708,7 @@ static void
1469214708
dumpTable(Archive *fout, TableInfo *tbinfo)
1469314709
{
1469414710
DumpOptions *dopt = fout->dopt;
14711+
DumpIdtableAclDumpId = InvalidDumpId;
1469514712
char *namecopy;
1469614713

1469714714
/*
@@ -14713,11 +14730,12 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
1471314730
const char *objtype =
1471414731
(tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
1471514732

14716-
dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
14717-
objtype, namecopy, NULL,
14718-
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14719-
tbinfo->relacl, tbinfo->rrelacl,
14720-
tbinfo->initrelacl, tbinfo->initrrelacl);
14733+
tableAclDumpId =
14734+
dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
14735+
objtype, namecopy, NULL,
14736+
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14737+
tbinfo->relacl, tbinfo->rrelacl,
14738+
tbinfo->initrelacl, tbinfo->initrrelacl);
1472114739
}
1472214740

1472314741
/*
@@ -14801,8 +14819,13 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
1480114819
char *attnamecopy;
1480214820

1480314821
attnamecopy = pg_strdup(fmtId(attname));
14804-
/* Column's GRANT type is always TABLE */
14805-
dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
14822+
14823+
/*
14824+
* Column's GRANT type is always TABLE. Each column ACL depends
14825+
* on the table-level ACL, since we can restore column ACLs in
14826+
* parallel but the table-level ACL has to be done first.
14827+
*/
14828+
dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
1480614829
"TABLE", namecopy, attnamecopy,
1480714830
tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
1480814831
attacl, rattacl, initattacl, initrattacl);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp