const char *acls);
static void getDependencies(Archive *fout);
+static void BuildArchiveDependencies(Archive *fout);
+static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
+ DumpId **dependencies, int *nDeps, int *allocDeps);
static DumpableObject *createBoundaryObjects(void);
static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
SetArchiveRestoreOptions(fout, ropt);
+ /*
+ * The archive's TOC entries are now marked as to which ones will
+ * actually be output, so we can set up their dependency lists properly.
+ * This isn't necessary for plain-text output, though.
+ */
+ if (!plainText)
+ BuildArchiveDependencies(fout);
+
/*
* And finally we can do the actual output.
*
copyStmt = NULL;
}
+ /*
+ * Note: although the TableDataInfo is a full DumpableObject, we treat its
+ * dependency on its table as "special" and pass it to ArchiveEntry now.
+ * See comments for BuildArchiveDependencies.
+ */
ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
NULL, tbinfo->rolname,
false, "TABLE DATA", SECTION_DATA,
"", "", copyStmt,
- tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
+ &(tbinfo->dobj.dumpId), 1,
dumpFn, tdinfo);
destroyPQExpBuffer(copyBuf);
binfo->rolname, false,
"BLOB", SECTION_PRE_DATA,
cquery->data, dquery->data, NULL,
- binfo->dobj.dependencies, binfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* set up tag for comment and/or ACL */
dobj->name, NULL, NULL, "",
false, "BLOBS", SECTION_DATA,
"", "", NULL,
- dobj->dependencies, dobj->nDeps,
+ NULL, 0,
dumpBlobs, NULL);
break;
case DO_PRE_DATA_BOUNDARY:
nspinfo->rolname,
false, "SCHEMA", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Schema Comments and Security Labels */
"",
false, "EXTENSION", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- extinfo->dobj.dependencies, extinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Extension Comments and Security Labels */
tyinfo->rolname, false,
"TYPE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Type Comments and Security Labels */
tyinfo->rolname, false,
"TYPE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Type Comments and Security Labels */
tyinfo->rolname, false,
"TYPE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Type Comments and Security Labels */
tyinfo->rolname, false,
"DOMAIN", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Domain Comments and Security Labels */
tyinfo->rolname, false,
"TYPE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
stinfo->baseType->rolname, false,
"SHELL TYPE", SECTION_PRE_DATA,
q->data, "", NULL,
- stinfo->dobj.dependencies, stinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
destroyPQExpBuffer(q);
lanschema, NULL, plang->lanowner,
false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
defqry->data, delqry->data, NULL,
- plang->dobj.dependencies, plang->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Proc Lang Comments and Security Labels */
finfo->rolname, false,
"FUNCTION", SECTION_PRE_DATA,
q->data, delqry->data, NULL,
- finfo->dobj.dependencies, finfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Function Comments and Security Labels */
"pg_catalog", NULL, "",
false, "CAST", SECTION_PRE_DATA,
defqry->data, delqry->data, NULL,
- cast->dobj.dependencies, cast->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Cast Comments */
oprinfo->rolname,
false, "OPERATOR", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Operator Comments */
opcinfo->rolname,
false, "OPERATOR CLASS", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Operator Class Comments */
opfinfo->rolname,
false, "OPERATOR FAMILY", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Operator Family Comments */
collinfo->rolname,
false, "COLLATION", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- collinfo->dobj.dependencies, collinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Collation Comments */
convinfo->rolname,
false, "CONVERSION", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- convinfo->dobj.dependencies, convinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Conversion Comments */
agginfo->aggfn.rolname,
false, "AGGREGATE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Aggregate Comments */
"",
false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Parser Comments */
dictinfo->rolname,
false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Dictionary Comments */
"",
false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Template Comments */
cfginfo->rolname,
false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump Configuration Comments */
fdwinfo->rolname,
false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Handle the ACL */
srvinfo->rolname,
false, "SERVER", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Handle the ACL */
daclinfo->defaclrole,
false, "DEFAULT ACL", SECTION_POST_DATA,
q->data, "", NULL,
- daclinfo->dobj.dependencies, daclinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
destroyPQExpBuffer(tag);
(strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
reltypename, SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
tbinfo->rolname,
false, "DEFAULT", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- adinfo->dobj.dependencies, adinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
destroyPQExpBuffer(q);
tbinfo->rolname, false,
"INDEX", SECTION_POST_DATA,
q->data, delq->data, NULL,
- indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
tbinfo->rolname, false,
"CONSTRAINT", SECTION_POST_DATA,
q->data, delq->data, NULL,
- coninfo->dobj.dependencies, coninfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
else if (coninfo->contype == 'f')
tbinfo->rolname, false,
"FK CONSTRAINT", SECTION_POST_DATA,
q->data, delq->data, NULL,
- coninfo->dobj.dependencies, coninfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
else if (coninfo->contype == 'c' && tbinfo)
tbinfo->rolname, false,
"CHECK CONSTRAINT", SECTION_POST_DATA,
q->data, delq->data, NULL,
- coninfo->dobj.dependencies, coninfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
}
tyinfo->rolname, false,
"CHECK CONSTRAINT", SECTION_POST_DATA,
q->data, delq->data, NULL,
- coninfo->dobj.dependencies, coninfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
}
tbinfo->rolname,
false, "SEQUENCE", SECTION_PRE_DATA,
query->data, delqry->data, NULL,
- tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/*
tbinfo->rolname, false,
"TRIGGER", SECTION_POST_DATA,
query->data, delqry->data, NULL,
- tginfo->dobj.dependencies, tginfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
dumpComment(fout, labelq->data,
tbinfo->rolname, false,
"RULE", SECTION_POST_DATA,
cmd->data, delcmd->data, NULL,
- rinfo->dobj.dependencies, rinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/* Dump rule comments */
}
+/*
+ * 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);
+ }
+ }
+}
+
+
/*
* selectSourceSchema - make the specified schema the active search path
* in the source database.