+/*
+ * createBoundaryObjects - create dummy DumpableObjects to represent
+ * dump section boundaries.
+ */
+static DumpableObject *
+createBoundaryObjects(void)
+{
+ DumpableObject *dobjs;
+
+ dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
+
+ dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
+ dobjs[0].catId = nilCatalogId;
+ AssignDumpId(dobjs + 0);
+ dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
+
+ dobjs[1].objType = DO_POST_DATA_BOUNDARY;
+ dobjs[1].catId = nilCatalogId;
+ AssignDumpId(dobjs + 1);
+ dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
+
+ return dobjs;
+}
+
+/*
+ * addBoundaryDependencies - add dependencies as needed to enforce the dump
+ * section boundaries.
+ */
+static void
+addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
+ DumpableObject *boundaryObjs)
+{
+ DumpableObject *preDataBound = boundaryObjs + 0;
+ DumpableObject *postDataBound = boundaryObjs + 1;
+ int i;
+
+ for (i = 0; i < numObjs; i++)
+ {
+ DumpableObject *dobj = dobjs[i];
+
+ /*
+ * The classification of object types here must match the SECTION_xxx
+ * values assigned during subsequent ArchiveEntry calls!
+ */
+ switch (dobj->objType)
+ {
+ case DO_NAMESPACE:
+ case DO_EXTENSION:
+ case DO_TYPE:
+ case DO_SHELL_TYPE:
+ case DO_FUNC:
+ case DO_AGG:
+ case DO_OPERATOR:
+ case DO_OPCLASS:
+ case DO_OPFAMILY:
+ case DO_COLLATION:
+ case DO_CONVERSION:
+ case DO_TABLE:
+ case DO_ATTRDEF:
+ case DO_PROCLANG:
+ case DO_CAST:
+ case DO_DUMMY_TYPE:
+ case DO_TSPARSER:
+ case DO_TSDICT:
+ case DO_TSTEMPLATE:
+ case DO_TSCONFIG:
+ case DO_FDW:
+ case DO_FOREIGN_SERVER:
+ case DO_BLOB:
+ /* Pre-data objects: must come before the pre-data boundary */
+ addObjectDependency(preDataBound, dobj->dumpId);
+ break;
+ case DO_TABLE_DATA:
+ case DO_BLOB_DATA:
+ /* Data objects: must come between the boundaries */
+ addObjectDependency(dobj, preDataBound->dumpId);
+ addObjectDependency(postDataBound, dobj->dumpId);
+ break;
+ case DO_INDEX:
+ case DO_REFRESH_MATVIEW:
+ case DO_TRIGGER:
+ case DO_EVENT_TRIGGER:
+ case DO_DEFAULT_ACL:
+ /* Post-data objects: must come after the post-data boundary */
+ addObjectDependency(dobj, postDataBound->dumpId);
+ break;
+ case DO_RULE:
+ /* Rules are post-data, but only if dumped separately */
+ if (((RuleInfo *) dobj)->separate)
+ addObjectDependency(dobj, postDataBound->dumpId);
+ break;
+ case DO_CONSTRAINT:
+ case DO_FK_CONSTRAINT:
+ /* Constraints are post-data, but only if dumped separately */
+ if (((ConstraintInfo *) dobj)->separate)
+ addObjectDependency(dobj, postDataBound->dumpId);
+ break;
+ case DO_PRE_DATA_BOUNDARY:
+ /* nothing to do */
+ break;
+ case DO_POST_DATA_BOUNDARY:
+ /* must come after the pre-data boundary */
+ addObjectDependency(dobj, preDataBound->dumpId);
+ break;
+ }
+ }
+}
+
+
+/*
+ * BuildArchiveDependencies - create dependency data for archive TOC entries
+ *
+ * The raw dependency data obtained by getDependencies() is not terribly
+ * useful in an archive dump, because in many cases there are dependency
+ * chains linking through objects that don't appear explicitly in the dump.
+ * For example, a view will depend on its _RETURN rule while the _RETURN rule
+ * will depend on other objects --- but the rule will not appear as a separate
+ * object in the dump. We need to adjust the view's dependencies to include
+ * whatever the rule depends on that is included in the dump.
+ *
+ * Just to make things more complicated, there are also "special" dependencies
+ * such as the dependency of a TABLE DATA item on its TABLE, which we must
+ * not rearrange because pg_restore knows that TABLE DATA only depends on
+ * its table. In these cases we must leave the dependencies strictly as-is
+ * even if they refer to not-to-be-dumped objects.
+ *
+ * To handle this, the convention is that "special" dependencies are created
+ * during ArchiveEntry calls, and an archive TOC item that has any such
+ * entries will not be touched here. Otherwise, we recursively search the
+ * DumpableObject data structures to build the correct dependencies for each
+ * archive TOC item.
+ */
+static void
+BuildArchiveDependencies(Archive *fout)
+{
+ ArchiveHandle *AH = (ArchiveHandle *) fout;
+ TocEntry *te;
+
+ /* Scan all TOC entries in the archive */
+ for (te = AH->toc->next; te != AH->toc; te = te->next)
+ {
+ DumpableObject *dobj;
+ DumpId *dependencies;
+ int nDeps;
+ int allocDeps;
+
+ /* No need to process entries that will not be dumped */
+ if (te->reqs == 0)
+ continue;
+ /* Ignore entries that already have "special" dependencies */
+ if (te->nDeps > 0)
+ continue;
+ /* Otherwise, look up the item's original DumpableObject, if any */
+ dobj = findObjectByDumpId(te->dumpId);
+ if (dobj == NULL)
+ continue;
+ /* No work if it has no dependencies */
+ if (dobj->nDeps <= 0)
+ continue;
+ /* Set up work array */
+ allocDeps = 64;
+ dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
+ nDeps = 0;
+ /* Recursively find all dumpable dependencies */
+ findDumpableDependencies(AH, dobj,
+ &dependencies, &nDeps, &allocDeps);
+ /* And save 'em ... */
+ if (nDeps > 0)
+ {
+ dependencies = (DumpId *) pg_realloc(dependencies,
+ nDeps * sizeof(DumpId));
+ te->dependencies = dependencies;
+ te->nDeps = nDeps;
+ }
+ else
+ free(dependencies);
+ }
+}
+
+/* Recursive search subroutine for BuildArchiveDependencies */
+static void
+findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
+ DumpId **dependencies, int *nDeps, int *allocDeps)
+{
+ int i;
+
+ /*
+ * Ignore section boundary objects: if we search through them, we'll
+ * report lots of bogus dependencies.
+ */
+ if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
+ dobj->objType == DO_POST_DATA_BOUNDARY)
+ return;
+
+ for (i = 0; i < dobj->nDeps; i++)
+ {
+ DumpId depid = dobj->dependencies[i];
+
+ if (TocIDRequired(AH, depid) != 0)
+ {
+ /* Object will be dumped, so just reference it as a dependency */
+ if (*nDeps >= *allocDeps)
+ {
+ *allocDeps *= 2;
+ *dependencies = (DumpId *) pg_realloc(*dependencies,
+ *allocDeps * sizeof(DumpId));
+ }
+ (*dependencies)[*nDeps] = depid;
+ (*nDeps)++;
+ }
+ else
+ {
+ /*
+ * Object will not be dumped, so recursively consider its deps. We
+ * rely on the assumption that sortDumpableObjects already broke
+ * any dependency loops, else we might recurse infinitely.
+ */
+ DumpableObject *otherdobj = findObjectByDumpId(depid);
+
+ if (otherdobj)
+ findDumpableDependencies(AH, otherdobj,
+ dependencies, nDeps, allocDeps);
+ }
+ }
+}
+
+