aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bin/pg_dump/pg_backup_archiver.c16
-rw-r--r--src/bin/pg_dump/pg_dump.c208
2 files changed, 182 insertions, 42 deletions
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index e466ef4e9d7..85c92b3d4a8 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -3498,9 +3498,14 @@ restore_toc_entries_parallel(ArchiveHandle *AH)
* Do all the early stuff in a single connection in the parent. There's no
* great point in running it in parallel, in fact it will actually run
* faster in a single connection because we avoid all the connection and
- * setup overhead. Also, pg_dump is not currently very good about showing
- * all the dependencies of SECTION_PRE_DATA items, so we do not risk
- * trying to process them out-of-order.
+ * setup overhead. Also, pre-9.2 pg_dump versions were not very good
+ * about showing all the dependencies of SECTION_PRE_DATA items, so we do
+ * not risk trying to process them out-of-order.
+ *
+ * Note: as of 9.2, it should be guaranteed that all PRE_DATA items appear
+ * before DATA items, and all DATA items before POST_DATA items. That is
+ * not certain to be true in older archives, though, so this loop is coded
+ * to not assume it.
*/
skipped_some = false;
for (next_work_item = AH->toc->next; next_work_item != AH->toc; next_work_item = next_work_item->next)
@@ -4162,8 +4167,9 @@ fix_dependencies(ArchiveHandle *AH)
/*
* Count the incoming dependencies for each item. Also, it is possible
- * that the dependencies list items that are not in the archive at all.
- * Subtract such items from the depCounts.
+ * that the dependencies list items that are not in the archive at all
+ * (that should not happen in 9.2 and later, but is highly likely in
+ * older archives). Subtract such items from the depCounts.
*/
for (te = AH->toc->next; te != AH->toc; te = te->next)
{
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 71cc3416bb9..afb28a870e6 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -210,6 +210,9 @@ static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
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,
@@ -769,6 +772,14 @@ main(int argc, char **argv)
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.
*
* Note: for non-plain-text output formats, the output file is written
@@ -1574,12 +1585,17 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo)
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);
@@ -2263,7 +2279,7 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
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 */
@@ -7197,7 +7213,7 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
dobj->name, NULL, NULL, "",
false, "BLOBS", SECTION_DATA,
"", "", NULL,
- dobj->dependencies, dobj->nDeps,
+ NULL, 0,
dumpBlobs, NULL);
break;
case DO_PRE_DATA_BOUNDARY:
@@ -7248,7 +7264,7 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
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 */
@@ -7366,7 +7382,7 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
"",
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 */
@@ -7514,7 +7530,7 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
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 */
@@ -7639,7 +7655,7 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
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 */
@@ -8021,7 +8037,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
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 */
@@ -8176,7 +8192,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
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 */
@@ -8383,7 +8399,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
tyinfo->rolname, false,
"TYPE", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
@@ -8555,7 +8571,7 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
stinfo->baseType->rolname, false,
"SHELL TYPE", SECTION_PRE_DATA,
q->data, "", NULL,
- stinfo->dobj.dependencies, stinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
destroyPQExpBuffer(q);
@@ -8729,7 +8745,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
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 */
@@ -9316,7 +9332,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
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 */
@@ -9486,7 +9502,7 @@ dumpCast(Archive *fout, CastInfo *cast)
"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 */
@@ -9720,7 +9736,7 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
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 */
@@ -10227,7 +10243,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
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 */
@@ -10540,7 +10556,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
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 */
@@ -10629,7 +10645,7 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
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 */
@@ -10728,7 +10744,7 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
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 */
@@ -10965,7 +10981,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
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 */
@@ -11063,7 +11079,7 @@ dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
"",
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 */
@@ -11150,7 +11166,7 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
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 */
@@ -11216,7 +11232,7 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
"",
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 */
@@ -11344,7 +11360,7 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
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 */
@@ -11418,7 +11434,7 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
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 */
@@ -11510,7 +11526,7 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
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 */
@@ -11694,7 +11710,7 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
daclinfo->defaclrole,
false, "DEFAULT ACL", SECTION_POST_DATA,
q->data, "", NULL,
- daclinfo->dobj.dependencies, daclinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
destroyPQExpBuffer(tag);
@@ -12693,7 +12709,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
(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);
@@ -12765,7 +12781,7 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
tbinfo->rolname,
false, "DEFAULT", SECTION_PRE_DATA,
q->data, delq->data, NULL,
- adinfo->dobj.dependencies, adinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
destroyPQExpBuffer(q);
@@ -12867,7 +12883,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
tbinfo->rolname, false,
"INDEX", SECTION_POST_DATA,
q->data, delq->data, NULL,
- indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
@@ -12988,7 +13004,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
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')
@@ -13021,7 +13037,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
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)
@@ -13056,7 +13072,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
tbinfo->rolname, false,
"CHECK CONSTRAINT", SECTION_POST_DATA,
q->data, delq->data, NULL,
- coninfo->dobj.dependencies, coninfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
}
@@ -13092,7 +13108,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
tyinfo->rolname, false,
"CHECK CONSTRAINT", SECTION_POST_DATA,
q->data, delq->data, NULL,
- coninfo->dobj.dependencies, coninfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
}
}
@@ -13354,7 +13370,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
tbinfo->rolname,
false, "SEQUENCE", SECTION_PRE_DATA,
query->data, delqry->data, NULL,
- tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
+ NULL, 0,
NULL, NULL);
/*
@@ -13620,7 +13636,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
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,
@@ -13741,7 +13757,7 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
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 */
@@ -14155,6 +14171,124 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
/*
+ * 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.
*