Skip to content

Commit 9a4c0e3

Browse files
committed
Dump ALTER TABLE ... ATTACH PARTITION as a separate ArchiveEntry.
Previously, we emitted the ATTACH PARTITION command as part of the child table's ArchiveEntry. This was a poor choice since it complicates restoring the partition as a standalone table; you have to ignore the error from the ATTACH, which isn't even an option when restoring direct-to-database with pg_restore. (pg_restore will issue the whole ArchiveEntry as one PQexec, so that any error rolls back the table creation as well.) Hence, separate it out as its own ArchiveEntry, as indeed we already did for index ATTACH PARTITION commands. Justin Pryzby Discussion: https://postgr.es/m/20201023052940.GE9241@telsasoft.com
1 parent d5ab79d commit 9a4c0e3

File tree

4 files changed

+109
-24
lines changed

4 files changed

+109
-24
lines changed

src/bin/pg_dump/common.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,9 @@ getSchemaData(Archive *fout, int *numTablesPtr)
261261

262262
/* flagInhTables -
263263
* Fill in parent link fields of tables for which we need that information,
264-
* and mark parents of target tables as interesting
264+
* mark parents of target tables as interesting, and create
265+
* TableAttachInfo objects for partitioned tables with appropriate
266+
* dependency links.
265267
*
266268
* Note that only direct ancestors of targets are marked interesting.
267269
* This is sufficient; we don't much care whether they inherited their
@@ -320,6 +322,40 @@ flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
320322
for (j = 0; j < numParents; j++)
321323
parents[j]->interesting = true;
322324
}
325+
326+
/* Create TableAttachInfo object if needed */
327+
if (tblinfo[i].dobj.dump && tblinfo[i].ispartition)
328+
{
329+
TableAttachInfo *attachinfo;
330+
331+
/* With partitions there can only be one parent */
332+
if (tblinfo[i].numParents != 1)
333+
fatal("invalid number of parents %d for table \"%s\"",
334+
tblinfo[i].numParents,
335+
tblinfo[i].dobj.name);
336+
337+
attachinfo = (TableAttachInfo *) palloc(sizeof(TableAttachInfo));
338+
attachinfo->dobj.objType = DO_TABLE_ATTACH;
339+
attachinfo->dobj.catId.tableoid = 0;
340+
attachinfo->dobj.catId.oid = 0;
341+
AssignDumpId(&attachinfo->dobj);
342+
attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name);
343+
attachinfo->dobj.namespace = tblinfo[i].dobj.namespace;
344+
attachinfo->parentTbl = tblinfo[i].parents[0];
345+
attachinfo->partitionTbl = &tblinfo[i];
346+
347+
/*
348+
* We must state the DO_TABLE_ATTACH object's dependencies
349+
* explicitly, since it will not match anything in pg_depend.
350+
*
351+
* Give it dependencies on both the partition table and the parent
352+
* table, so that it will not be executed till both of those
353+
* exist. (There's no need to care what order those are created
354+
* in.)
355+
*/
356+
addObjectDependency(&attachinfo->dobj, tblinfo[i].dobj.dumpId);
357+
addObjectDependency(&attachinfo->dobj, tblinfo[i].parents[0]->dobj.dumpId);
358+
}
323359
}
324360
}
325361

@@ -548,6 +584,7 @@ AssignDumpId(DumpableObject *dobj)
548584
dobj->name = NULL; /* must be set later */
549585
dobj->namespace = NULL; /* may be set later */
550586
dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
587+
dobj->dump_contains = DUMP_COMPONENT_ALL; /* default assumption */
551588
dobj->ext_member = false; /* default assumption */
552589
dobj->depends_on_ext = false; /* default assumption */
553590
dobj->dependencies = NULL;

src/bin/pg_dump/pg_dump.c

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
202202
static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
203203
static void dumpTable(Archive *fout, TableInfo *tbinfo);
204204
static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
205+
static void dumpTableAttach(Archive *fout, TableAttachInfo *tbinfo);
205206
static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
206207
static void dumpSequence(Archive *fout, TableInfo *tbinfo);
207208
static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
@@ -10176,6 +10177,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
1017610177
case DO_TABLE:
1017710178
dumpTable(fout, (TableInfo *) dobj);
1017810179
break;
10180+
case DO_TABLE_ATTACH:
10181+
dumpTableAttach(fout, (TableAttachInfo *) dobj);
10182+
break;
1017910183
case DO_ATTRDEF:
1018010184
dumpAttrDef(fout, (AttrDefInfo *) dobj);
1018110185
break;
@@ -11183,7 +11187,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
1118311187
if (dopt->binary_upgrade)
1118411188
binary_upgrade_set_type_oids_by_type_oid(fout, q,
1118511189
tyinfo->dobj.catId.oid,
11186-
true, /* force array type */
11190+
true, /* force array type */
1118711191
false); /* force multirange type */
1118811192

1118911193
qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
@@ -16133,27 +16137,6 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
1613316137
}
1613416138
}
1613516139

16136-
/*
16137-
* For partitioned tables, emit the ATTACH PARTITION clause. Note
16138-
* that we always want to create partitions this way instead of using
16139-
* CREATE TABLE .. PARTITION OF, mainly to preserve a possible column
16140-
* layout discrepancy with the parent, but also to ensure it gets the
16141-
* correct tablespace setting if it differs from the parent's.
16142-
*/
16143-
if (tbinfo->ispartition)
16144-
{
16145-
/* With partitions there can only be one parent */
16146-
if (tbinfo->numParents != 1)
16147-
fatal("invalid number of parents %d for table \"%s\"",
16148-
tbinfo->numParents, tbinfo->dobj.name);
16149-
16150-
/* Perform ALTER TABLE on the parent */
16151-
appendPQExpBuffer(q,
16152-
"ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n",
16153-
fmtQualifiedDumpable(parents[0]),
16154-
qualrelname, tbinfo->partbound);
16155-
}
16156-
1615716140
/*
1615816141
* In binary_upgrade mode, arrange to restore the old relfrozenxid and
1615916142
* relminmxid of all vacuumable relations. (While vacuum.c processes
@@ -16383,6 +16366,55 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
1638316366
free(qualrelname);
1638416367
}
1638516368

16369+
/*
16370+
* dumpTableAttach
16371+
* write to fout the commands to attach a child partition
16372+
*
16373+
* Child partitions are always made by creating them separately
16374+
* and then using ATTACH PARTITION, rather than using
16375+
* CREATE TABLE ... PARTITION OF. This is important for preserving
16376+
* any possible discrepancy in column layout, to allow assigning the
16377+
* correct tablespace if different, and so that it's possible to restore
16378+
* a partition without restoring its parent. (You'll get an error from
16379+
* the ATTACH PARTITION command, but that can be ignored, or skipped
16380+
* using "pg_restore -L" if you prefer.) The last point motivates
16381+
* treating ATTACH PARTITION as a completely separate ArchiveEntry
16382+
* rather than emitting it within the child partition's ArchiveEntry.
16383+
*/
16384+
static void
16385+
dumpTableAttach(Archive *fout, TableAttachInfo *attachinfo)
16386+
{
16387+
DumpOptions *dopt = fout->dopt;
16388+
PQExpBuffer q;
16389+
16390+
if (dopt->dataOnly)
16391+
return;
16392+
16393+
if (!(attachinfo->partitionTbl->dobj.dump & DUMP_COMPONENT_DEFINITION))
16394+
return;
16395+
16396+
q = createPQExpBuffer();
16397+
16398+
/* Perform ALTER TABLE on the parent */
16399+
appendPQExpBuffer(q,
16400+
"ALTER TABLE ONLY %s ",
16401+
fmtQualifiedDumpable(attachinfo->parentTbl));
16402+
appendPQExpBuffer(q,
16403+
"ATTACH PARTITION %s %s;\n",
16404+
fmtQualifiedDumpable(attachinfo->partitionTbl),
16405+
attachinfo->partitionTbl->partbound);
16406+
16407+
ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16408+
ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16409+
.namespace = attachinfo->dobj.namespace->dobj.name,
16410+
.owner = attachinfo->partitionTbl->rolname,
16411+
.description = "TABLE ATTACH",
16412+
.section = SECTION_PRE_DATA,
16413+
.createStmt = q->data));
16414+
16415+
destroyPQExpBuffer(q);
16416+
}
16417+
1638616418
/*
1638716419
* dumpAttrDef --- dump an attribute's default-value declaration
1638816420
*/
@@ -18344,6 +18376,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
1834418376
case DO_COLLATION:
1834518377
case DO_CONVERSION:
1834618378
case DO_TABLE:
18379+
case DO_TABLE_ATTACH:
1834718380
case DO_ATTRDEF:
1834818381
case DO_PROCLANG:
1834918382
case DO_CAST:

src/bin/pg_dump/pg_dump.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ typedef enum
5050
DO_COLLATION,
5151
DO_CONVERSION,
5252
DO_TABLE,
53+
DO_TABLE_ATTACH,
5354
DO_ATTRDEF,
5455
DO_INDEX,
5556
DO_INDEX_ATTACH,
@@ -338,6 +339,13 @@ typedef struct _tableInfo
338339
struct _triggerInfo *triggers; /* array of TriggerInfo structs */
339340
} TableInfo;
340341

342+
typedef struct _tableAttachInfo
343+
{
344+
DumpableObject dobj;
345+
TableInfo *parentTbl; /* link to partitioned table */
346+
TableInfo *partitionTbl; /* link to partition */
347+
} TableAttachInfo;
348+
341349
typedef struct _attrDefInfo
342350
{
343351
DumpableObject dobj; /* note: dobj.name is name of table */
@@ -367,7 +375,7 @@ typedef struct _indxInfo
367375
int indnattrs; /* total number of index attributes */
368376
Oid *indkeys; /* In spite of the name 'indkeys' this field
369377
* contains both key and nonkey attributes */
370-
char *inddependcollnames; /* FQ names of depended-on collations */
378+
char *inddependcollnames; /* FQ names of depended-on collations */
371379
char *inddependcollversions; /* versions of the above */
372380
bool indisclustered;
373381
bool indisreplident;

src/bin/pg_dump/pg_dump_sort.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ enum dbObjectTypePriorities
6363
PRIO_FDW,
6464
PRIO_FOREIGN_SERVER,
6565
PRIO_TABLE,
66+
PRIO_TABLE_ATTACH,
6667
PRIO_DUMMY_TYPE,
6768
PRIO_ATTRDEF,
6869
PRIO_BLOB,
@@ -103,6 +104,7 @@ static const int dbObjectTypePriority[] =
103104
PRIO_COLLATION, /* DO_COLLATION */
104105
PRIO_CONVERSION, /* DO_CONVERSION */
105106
PRIO_TABLE, /* DO_TABLE */
107+
PRIO_TABLE_ATTACH, /* DO_TABLE_ATTACH */
106108
PRIO_ATTRDEF, /* DO_ATTRDEF */
107109
PRIO_INDEX, /* DO_INDEX */
108110
PRIO_INDEX_ATTACH, /* DO_INDEX_ATTACH */
@@ -1324,6 +1326,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
13241326
"TABLE %s (ID %d OID %u)",
13251327
obj->name, obj->dumpId, obj->catId.oid);
13261328
return;
1329+
case DO_TABLE_ATTACH:
1330+
snprintf(buf, bufsize,
1331+
"TABLE ATTACH %s (ID %d)",
1332+
obj->name, obj->dumpId);
1333+
return;
13271334
case DO_ATTRDEF:
13281335
snprintf(buf, bufsize,
13291336
"ATTRDEF %s.%s (ID %d OID %u)",

0 commit comments

Comments
 (0)