/* flagInhTables -
* Fill in parent link fields of tables for which we need that information,
- * and mark parents of target tables as interesting
+ * mark parents of target tables as interesting, and create
+ * TableAttachInfo objects for partitioned tables with appropriate
+ * dependency links.
*
* Note that only direct ancestors of targets are marked interesting.
* This is sufficient; we don't much care whether they inherited their
for (j = 0; j < numParents; j++)
parents[j]->interesting = true;
}
+
+ /* Create TableAttachInfo object if needed */
+ if (tblinfo[i].dobj.dump && tblinfo[i].ispartition)
+ {
+ TableAttachInfo *attachinfo;
+
+ /* With partitions there can only be one parent */
+ if (tblinfo[i].numParents != 1)
+ fatal("invalid number of parents %d for table \"%s\"",
+ tblinfo[i].numParents,
+ tblinfo[i].dobj.name);
+
+ attachinfo = (TableAttachInfo *) palloc(sizeof(TableAttachInfo));
+ attachinfo->dobj.objType = DO_TABLE_ATTACH;
+ attachinfo->dobj.catId.tableoid = 0;
+ attachinfo->dobj.catId.oid = 0;
+ AssignDumpId(&attachinfo->dobj);
+ attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name);
+ attachinfo->dobj.namespace = tblinfo[i].dobj.namespace;
+ attachinfo->parentTbl = tblinfo[i].parents[0];
+ attachinfo->partitionTbl = &tblinfo[i];
+
+ /*
+ * We must state the DO_TABLE_ATTACH object's dependencies
+ * explicitly, since it will not match anything in pg_depend.
+ *
+ * Give it dependencies on both the partition table and the parent
+ * table, so that it will not be executed till both of those
+ * exist. (There's no need to care what order those are created
+ * in.)
+ */
+ addObjectDependency(&attachinfo->dobj, tblinfo[i].dobj.dumpId);
+ addObjectDependency(&attachinfo->dobj, tblinfo[i].parents[0]->dobj.dumpId);
+ }
}
}
dobj->name = NULL; /* must be set later */
dobj->namespace = NULL; /* may be set later */
dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
+ dobj->dump_contains = DUMP_COMPONENT_ALL; /* default assumption */
dobj->ext_member = false; /* default assumption */
dobj->depends_on_ext = false; /* default assumption */
dobj->dependencies = NULL;
static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
static void dumpTable(Archive *fout, TableInfo *tbinfo);
static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
+static void dumpTableAttach(Archive *fout, TableAttachInfo *tbinfo);
static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
static void dumpSequence(Archive *fout, TableInfo *tbinfo);
static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
case DO_TABLE:
dumpTable(fout, (TableInfo *) dobj);
break;
+ case DO_TABLE_ATTACH:
+ dumpTableAttach(fout, (TableAttachInfo *) dobj);
+ break;
case DO_ATTRDEF:
dumpAttrDef(fout, (AttrDefInfo *) dobj);
break;
if (dopt->binary_upgrade)
binary_upgrade_set_type_oids_by_type_oid(fout, q,
tyinfo->dobj.catId.oid,
- true, /* force array type */
+ true, /* force array type */
false); /* force multirange type */
qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
}
}
- /*
- * For partitioned tables, emit the ATTACH PARTITION clause. Note
- * that we always want to create partitions this way instead of using
- * CREATE TABLE .. PARTITION OF, mainly to preserve a possible column
- * layout discrepancy with the parent, but also to ensure it gets the
- * correct tablespace setting if it differs from the parent's.
- */
- if (tbinfo->ispartition)
- {
- /* With partitions there can only be one parent */
- if (tbinfo->numParents != 1)
- fatal("invalid number of parents %d for table \"%s\"",
- tbinfo->numParents, tbinfo->dobj.name);
-
- /* Perform ALTER TABLE on the parent */
- appendPQExpBuffer(q,
- "ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n",
- fmtQualifiedDumpable(parents[0]),
- qualrelname, tbinfo->partbound);
- }
-
/*
* In binary_upgrade mode, arrange to restore the old relfrozenxid and
* relminmxid of all vacuumable relations. (While vacuum.c processes
free(qualrelname);
}
+/*
+ * dumpTableAttach
+ * write to fout the commands to attach a child partition
+ *
+ * Child partitions are always made by creating them separately
+ * and then using ATTACH PARTITION, rather than using
+ * CREATE TABLE ... PARTITION OF. This is important for preserving
+ * any possible discrepancy in column layout, to allow assigning the
+ * correct tablespace if different, and so that it's possible to restore
+ * a partition without restoring its parent. (You'll get an error from
+ * the ATTACH PARTITION command, but that can be ignored, or skipped
+ * using "pg_restore -L" if you prefer.) The last point motivates
+ * treating ATTACH PARTITION as a completely separate ArchiveEntry
+ * rather than emitting it within the child partition's ArchiveEntry.
+ */
+static void
+dumpTableAttach(Archive *fout, TableAttachInfo *attachinfo)
+{
+ DumpOptions *dopt = fout->dopt;
+ PQExpBuffer q;
+
+ if (dopt->dataOnly)
+ return;
+
+ if (!(attachinfo->partitionTbl->dobj.dump & DUMP_COMPONENT_DEFINITION))
+ return;
+
+ q = createPQExpBuffer();
+
+ /* Perform ALTER TABLE on the parent */
+ appendPQExpBuffer(q,
+ "ALTER TABLE ONLY %s ",
+ fmtQualifiedDumpable(attachinfo->parentTbl));
+ appendPQExpBuffer(q,
+ "ATTACH PARTITION %s %s;\n",
+ fmtQualifiedDumpable(attachinfo->partitionTbl),
+ attachinfo->partitionTbl->partbound);
+
+ ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
+ ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
+ .namespace = attachinfo->dobj.namespace->dobj.name,
+ .owner = attachinfo->partitionTbl->rolname,
+ .description = "TABLE ATTACH",
+ .section = SECTION_PRE_DATA,
+ .createStmt = q->data));
+
+ destroyPQExpBuffer(q);
+}
+
/*
* dumpAttrDef --- dump an attribute's default-value declaration
*/
case DO_COLLATION:
case DO_CONVERSION:
case DO_TABLE:
+ case DO_TABLE_ATTACH:
case DO_ATTRDEF:
case DO_PROCLANG:
case DO_CAST:
PRIO_FDW,
PRIO_FOREIGN_SERVER,
PRIO_TABLE,
+ PRIO_TABLE_ATTACH,
PRIO_DUMMY_TYPE,
PRIO_ATTRDEF,
PRIO_BLOB,
PRIO_COLLATION, /* DO_COLLATION */
PRIO_CONVERSION, /* DO_CONVERSION */
PRIO_TABLE, /* DO_TABLE */
+ PRIO_TABLE_ATTACH, /* DO_TABLE_ATTACH */
PRIO_ATTRDEF, /* DO_ATTRDEF */
PRIO_INDEX, /* DO_INDEX */
PRIO_INDEX_ATTACH, /* DO_INDEX_ATTACH */
"TABLE %s (ID %d OID %u)",
obj->name, obj->dumpId, obj->catId.oid);
return;
+ case DO_TABLE_ATTACH:
+ snprintf(buf, bufsize,
+ "TABLE ATTACH %s (ID %d)",
+ obj->name, obj->dumpId);
+ return;
case DO_ATTRDEF:
snprintf(buf, bufsize,
"ATTRDEF %s.%s (ID %d OID %u)",