summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bin/pg_dump/common.c19
-rw-r--r--src/bin/pg_dump/pg_dump.c79
-rw-r--r--src/bin/pg_dump/pg_dump.h6
-rw-r--r--src/bin/pg_dump/pg_dump_sort.c227
-rw-r--r--src/test/regress/expected/publication.out8
-rw-r--r--src/test/regress/sql/publication.sql9
6 files changed, 309 insertions, 39 deletions
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index c68b86bc766..59f00740bfb 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -17,6 +17,7 @@
#include <ctype.h>
+#include "catalog/pg_am_d.h"
#include "catalog/pg_class_d.h"
#include "fe_utils/string_utils.h"
#include "pg_backup_archiver.h"
@@ -49,6 +50,7 @@ static DumpableObject **tblinfoindex;
static DumpableObject **typinfoindex;
static DumpableObject **funinfoindex;
static DumpableObject **oprinfoindex;
+static DumpableObject **aminfoindex;
static DumpableObject **collinfoindex;
static DumpableObject **nspinfoindex;
static DumpableObject **extinfoindex;
@@ -57,6 +59,7 @@ static int numTables;
static int numTypes;
static int numFuncs;
static int numOperators;
+static int numAccessMethods;
static int numCollations;
static int numNamespaces;
static int numExtensions;
@@ -92,6 +95,7 @@ getSchemaData(Archive *fout, int *numTablesPtr)
TypeInfo *typinfo;
FuncInfo *funinfo;
OprInfo *oprinfo;
+ AccessMethodInfo *aminfo;
CollInfo *collinfo;
NamespaceInfo *nspinfo;
ExtensionInfo *extinfo;
@@ -103,7 +107,6 @@ getSchemaData(Archive *fout, int *numTablesPtr)
int numProcLangs;
int numCasts;
int numTransforms;
- int numAccessMethods;
int numOpclasses;
int numOpfamilies;
int numConversions;
@@ -166,7 +169,8 @@ getSchemaData(Archive *fout, int *numTablesPtr)
oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
pg_log_info("reading user-defined access methods");
- getAccessMethods(fout, &numAccessMethods);
+ aminfo = getAccessMethods(fout, &numAccessMethods);
+ aminfoindex = buildIndexArray(aminfo, numAccessMethods, sizeof(AccessMethodInfo));
pg_log_info("reading user-defined operator classes");
getOpclasses(fout, &numOpclasses);
@@ -891,6 +895,17 @@ findOprByOid(Oid oid)
}
/*
+ * findAccessMethodByOid
+ * finds the DumpableObject for the access method with the given oid
+ * returns NULL if not found
+ */
+AccessMethodInfo *
+findAccessMethodByOid(Oid oid)
+{
+ return (AccessMethodInfo *) findObjectByOid(oid, aminfoindex, numAccessMethods);
+}
+
+/*
* findCollationByOid
* finds the entry (in collinfo) of the collation with the given oid
* returns NULL if not found
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 4b13669f450..29d37158a38 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1767,6 +1767,13 @@ selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
static void
selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
{
+ /* see getAccessMethods() comment about v9.6. */
+ if (fout->remoteVersion < 90600)
+ {
+ method->dobj.dump = DUMP_COMPONENT_NONE;
+ return;
+ }
+
if (checkExtensionMembership(&method->dobj, fout))
return; /* extension membership overrides all else */
@@ -5325,6 +5332,8 @@ getOperators(Archive *fout, int *numOprs)
int i_oprnamespace;
int i_rolname;
int i_oprkind;
+ int i_oprleft;
+ int i_oprright;
int i_oprcode;
/*
@@ -5336,6 +5345,8 @@ getOperators(Archive *fout, int *numOprs)
"oprnamespace, "
"(%s oprowner) AS rolname, "
"oprkind, "
+ "oprleft, "
+ "oprright, "
"oprcode::oid AS oprcode "
"FROM pg_operator",
username_subquery);
@@ -5353,6 +5364,8 @@ getOperators(Archive *fout, int *numOprs)
i_oprnamespace = PQfnumber(res, "oprnamespace");
i_rolname = PQfnumber(res, "rolname");
i_oprkind = PQfnumber(res, "oprkind");
+ i_oprleft = PQfnumber(res, "oprleft");
+ i_oprright = PQfnumber(res, "oprright");
i_oprcode = PQfnumber(res, "oprcode");
for (i = 0; i < ntups; i++)
@@ -5367,6 +5380,8 @@ getOperators(Archive *fout, int *numOprs)
atooid(PQgetvalue(res, i, i_oprnamespace)));
oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
+ oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
+ oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
/* Decide whether we want to dump it */
@@ -5407,6 +5422,7 @@ getCollations(Archive *fout, int *numCollations)
int i_collname;
int i_collnamespace;
int i_rolname;
+ int i_collencoding;
/* Collations didn't exist pre-9.1 */
if (fout->remoteVersion < 90100)
@@ -5424,7 +5440,8 @@ getCollations(Archive *fout, int *numCollations)
appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
"collnamespace, "
- "(%s collowner) AS rolname "
+ "(%s collowner) AS rolname, "
+ "collencoding "
"FROM pg_collation",
username_subquery);
@@ -5440,6 +5457,7 @@ getCollations(Archive *fout, int *numCollations)
i_collname = PQfnumber(res, "collname");
i_collnamespace = PQfnumber(res, "collnamespace");
i_rolname = PQfnumber(res, "rolname");
+ i_collencoding = PQfnumber(res, "collencoding");
for (i = 0; i < ntups; i++)
{
@@ -5452,6 +5470,7 @@ getCollations(Archive *fout, int *numCollations)
findNamespace(fout,
atooid(PQgetvalue(res, i, i_collnamespace)));
collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
+ collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
/* Decide whether we want to dump it */
selectDumpableObject(&(collinfo[i].dobj), fout);
@@ -5561,19 +5580,28 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
int i_amhandler;
int i_amtype;
- /* Before 9.6, there are no user-defined access methods */
- if (fout->remoteVersion < 90600)
- {
- *numAccessMethods = 0;
- return NULL;
- }
-
query = createPQExpBuffer();
- /* Select all access methods from pg_am table */
- appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
- "amhandler::pg_catalog.regproc AS amhandler "
- "FROM pg_am");
+ /*
+ * Select all access methods from pg_am table. v9.6 introduced CREATE
+ * ACCESS METHOD, so earlier versions usually have only built-in access
+ * methods. v9.6 also changed the access method API, replacing dozens of
+ * pg_am columns with amhandler. Even if a user created an access method
+ * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
+ * columns to a v9.6+ CREATE ACCESS METHOD. Hence, before v9.6, read
+ * pg_am just to facilitate findAccessMethodByOid() providing the
+ * OID-to-name mapping.
+ */
+ appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
+ if (fout->remoteVersion >= 90600)
+ appendPQExpBufferStr(query,
+ "amtype, "
+ "amhandler::pg_catalog.regproc AS amhandler ");
+ else
+ appendPQExpBufferStr(query,
+ "'i'::pg_catalog.\"char\" AS amtype, "
+ "'-'::pg_catalog.regproc AS amhandler ");
+ appendPQExpBufferStr(query, "FROM pg_am");
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -5631,6 +5659,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
OpclassInfo *opcinfo;
int i_tableoid;
int i_oid;
+ int i_opcmethod;
int i_opcname;
int i_opcnamespace;
int i_rolname;
@@ -5640,11 +5669,20 @@ getOpclasses(Archive *fout, int *numOpclasses)
* system-defined opclasses at dump-out time.
*/
- appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
- "opcnamespace, "
- "(%s opcowner) AS rolname "
- "FROM pg_opclass",
- username_subquery);
+ if (fout->remoteVersion >= 80300)
+ appendPQExpBuffer(query, "SELECT tableoid, oid, "
+ "opcmethod, opcname, "
+ "opcnamespace, "
+ "(%s opcowner) AS rolname "
+ "FROM pg_opclass",
+ username_subquery);
+ else
+ appendPQExpBuffer(query, "SELECT tableoid, oid, "
+ "opcamid AS opcmethod, opcname, "
+ "opcnamespace, "
+ "(%s opcowner) AS rolname "
+ "FROM pg_opclass",
+ username_subquery);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -5655,6 +5693,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
i_tableoid = PQfnumber(res, "tableoid");
i_oid = PQfnumber(res, "oid");
+ i_opcmethod = PQfnumber(res, "opcmethod");
i_opcname = PQfnumber(res, "opcname");
i_opcnamespace = PQfnumber(res, "opcnamespace");
i_rolname = PQfnumber(res, "rolname");
@@ -5669,6 +5708,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
opcinfo[i].dobj.namespace =
findNamespace(fout,
atooid(PQgetvalue(res, i, i_opcnamespace)));
+ opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
/* Decide whether we want to dump it */
@@ -5706,6 +5746,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
OpfamilyInfo *opfinfo;
int i_tableoid;
int i_oid;
+ int i_opfmethod;
int i_opfname;
int i_opfnamespace;
int i_rolname;
@@ -5724,7 +5765,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
* system-defined opfamilies at dump-out time.
*/
- appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
+ appendPQExpBuffer(query, "SELECT tableoid, oid, opfmethod, opfname, "
"opfnamespace, "
"(%s opfowner) AS rolname "
"FROM pg_opfamily",
@@ -5740,6 +5781,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
i_tableoid = PQfnumber(res, "tableoid");
i_oid = PQfnumber(res, "oid");
i_opfname = PQfnumber(res, "opfname");
+ i_opfmethod = PQfnumber(res, "opfmethod");
i_opfnamespace = PQfnumber(res, "opfnamespace");
i_rolname = PQfnumber(res, "rolname");
@@ -5753,6 +5795,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
opfinfo[i].dobj.namespace =
findNamespace(fout,
atooid(PQgetvalue(res, i, i_opfnamespace)));
+ opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
/* Decide whether we want to dump it */
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 552e9e1da16..7fcc544b2dc 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -219,6 +219,8 @@ typedef struct _oprInfo
DumpableObject dobj;
char *rolname;
char oprkind;
+ Oid oprleft;
+ Oid oprright;
Oid oprcode;
} OprInfo;
@@ -232,12 +234,14 @@ typedef struct _accessMethodInfo
typedef struct _opclassInfo
{
DumpableObject dobj;
+ Oid opcmethod;
char *rolname;
} OpclassInfo;
typedef struct _opfamilyInfo
{
DumpableObject dobj;
+ Oid opfmethod;
char *rolname;
} OpfamilyInfo;
@@ -245,6 +249,7 @@ typedef struct _collInfo
{
DumpableObject dobj;
char *rolname;
+ int collencoding;
} CollInfo;
typedef struct _convInfo
@@ -662,6 +667,7 @@ extern TableInfo *findTableByOid(Oid oid);
extern TypeInfo *findTypeByOid(Oid oid);
extern FuncInfo *findFuncByOid(Oid oid);
extern OprInfo *findOprByOid(Oid oid);
+extern AccessMethodInfo *findAccessMethodByOid(Oid oid);
extern CollInfo *findCollationByOid(Oid oid);
extern NamespaceInfo *findNamespaceByOid(Oid oid);
extern ExtensionInfo *findExtensionByOid(Oid oid);
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 51e6be90737..892eda73420 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -104,6 +104,8 @@ static DumpId postDataBoundId;
static int DOTypeNameCompare(const void *p1, const void *p2);
+static int pgTypeNameCompare(Oid typid1, Oid typid2);
+static int accessMethodNameCompare(Oid am1, Oid am2);
static bool TopoSort(DumpableObject **objs,
int numObjs,
DumpableObject **ordering,
@@ -171,12 +173,39 @@ DOTypeNameCompare(const void *p1, const void *p2)
else if (obj2->namespace)
return 1;
- /* Sort by name */
+ /*
+ * Sort by name. With a few exceptions, names here are single catalog
+ * columns. To get a fuller picture, grep pg_dump.c for "dobj.name = ".
+ * Names here don't match "Name:" in plain format output, which is a
+ * _tocEntry.tag. For example, DumpableObject.name of a constraint is
+ * pg_constraint.conname, but _tocEntry.tag of a constraint is relname and
+ * conname joined with a space.
+ */
cmpval = strcmp(obj1->name, obj2->name);
if (cmpval != 0)
return cmpval;
- /* To have a stable sort order, break ties for some object types */
+ /*
+ * Sort by type. This helps types that share a type priority without
+ * sharing a unique name constraint, e.g. opclass and opfamily.
+ */
+ cmpval = obj1->objType - obj2->objType;
+ if (cmpval != 0)
+ return cmpval;
+
+ /*
+ * To have a stable sort order, break ties for some object types. Most
+ * catalogs have a natural key, e.g. pg_proc_proname_args_nsp_index. Where
+ * the above "namespace" and "name" comparisons don't cover all natural
+ * key columns, compare the rest here.
+ *
+ * The natural key usually refers to other catalogs by surrogate keys.
+ * Hence, this translates each of those references to the natural key of
+ * the referenced catalog. That may descend through multiple levels of
+ * catalog references. For example, to sort by pg_proc.proargtypes,
+ * descend to each pg_type and then further to its pg_namespace, for an
+ * overall sort by (nspname, typname).
+ */
if (obj1->objType == DO_FUNC || obj1->objType == DO_AGG)
{
FuncInfo *fobj1 = *(FuncInfo *const *) p1;
@@ -189,22 +218,10 @@ DOTypeNameCompare(const void *p1, const void *p2)
return cmpval;
for (i = 0; i < fobj1->nargs; i++)
{
- TypeInfo *argtype1 = findTypeByOid(fobj1->argtypes[i]);
- TypeInfo *argtype2 = findTypeByOid(fobj2->argtypes[i]);
-
- if (argtype1 && argtype2)
- {
- if (argtype1->dobj.namespace && argtype2->dobj.namespace)
- {
- cmpval = strcmp(argtype1->dobj.namespace->dobj.name,
- argtype2->dobj.namespace->dobj.name);
- if (cmpval != 0)
- return cmpval;
- }
- cmpval = strcmp(argtype1->dobj.name, argtype2->dobj.name);
- if (cmpval != 0)
- return cmpval;
- }
+ cmpval = pgTypeNameCompare(fobj1->argtypes[i],
+ fobj2->argtypes[i]);
+ if (cmpval != 0)
+ return cmpval;
}
}
else if (obj1->objType == DO_OPERATOR)
@@ -216,6 +233,57 @@ DOTypeNameCompare(const void *p1, const void *p2)
cmpval = (oobj2->oprkind - oobj1->oprkind);
if (cmpval != 0)
return cmpval;
+ /* Within an oprkind, sort by argument type names */
+ cmpval = pgTypeNameCompare(oobj1->oprleft, oobj2->oprleft);
+ if (cmpval != 0)
+ return cmpval;
+ cmpval = pgTypeNameCompare(oobj1->oprright, oobj2->oprright);
+ if (cmpval != 0)
+ return cmpval;
+ }
+ else if (obj1->objType == DO_OPCLASS)
+ {
+ OpclassInfo *opcobj1 = *(OpclassInfo *const *) p1;
+ OpclassInfo *opcobj2 = *(OpclassInfo *const *) p2;
+
+ /* Sort by access method name, per pg_opclass_am_name_nsp_index */
+ cmpval = accessMethodNameCompare(opcobj1->opcmethod,
+ opcobj2->opcmethod);
+ if (cmpval != 0)
+ return cmpval;
+ }
+ else if (obj1->objType == DO_OPFAMILY)
+ {
+ OpfamilyInfo *opfobj1 = *(OpfamilyInfo *const *) p1;
+ OpfamilyInfo *opfobj2 = *(OpfamilyInfo *const *) p2;
+
+ /* Sort by access method name, per pg_opfamily_am_name_nsp_index */
+ cmpval = accessMethodNameCompare(opfobj1->opfmethod,
+ opfobj2->opfmethod);
+ if (cmpval != 0)
+ return cmpval;
+ }
+ else if (obj1->objType == DO_COLLATION)
+ {
+ CollInfo *cobj1 = *(CollInfo *const *) p1;
+ CollInfo *cobj2 = *(CollInfo *const *) p2;
+
+ /*
+ * Sort by encoding, per pg_collation_name_enc_nsp_index. Technically,
+ * this is not necessary, because wherever this changes dump order,
+ * restoring the dump fails anyway. CREATE COLLATION can't create a
+ * tie for this to break, because it imposes restrictions to make
+ * (nspname, collname) uniquely identify a collation within a given
+ * DatabaseEncoding. While pg_import_system_collations() can create a
+ * tie, pg_dump+restore fails after
+ * pg_import_system_collations('my_schema') does so. However, there's
+ * little to gain by ignoring one natural key column on the basis of
+ * those limitations elsewhere, so respect the full natural key like
+ * we do for other object types.
+ */
+ cmpval = cobj1->collencoding - cobj2->collencoding;
+ if (cmpval != 0)
+ return cmpval;
}
else if (obj1->objType == DO_ATTRDEF)
{
@@ -260,11 +328,132 @@ DOTypeNameCompare(const void *p1, const void *p2)
if (cmpval != 0)
return cmpval;
}
+ else if (obj1->objType == DO_CONSTRAINT)
+ {
+ ConstraintInfo *robj1 = *(ConstraintInfo *const *) p1;
+ ConstraintInfo *robj2 = *(ConstraintInfo *const *) p2;
+
+ /*
+ * Sort domain constraints before table constraints, for consistency
+ * with our decision to sort CREATE DOMAIN before CREATE TABLE.
+ */
+ if (robj1->condomain)
+ {
+ if (robj2->condomain)
+ {
+ /* Sort by domain name (domain namespace was considered) */
+ cmpval = strcmp(robj1->condomain->dobj.name,
+ robj2->condomain->dobj.name);
+ if (cmpval != 0)
+ return cmpval;
+ }
+ else
+ return dbObjectTypePriority[DO_TYPE] - dbObjectTypePriority[DO_TABLE];
+ }
+ else if (robj2->condomain)
+ return dbObjectTypePriority[DO_TABLE] - dbObjectTypePriority[DO_TYPE];
+ else
+ {
+ /* Sort by table name (table namespace was considered already) */
+ cmpval = strcmp(robj1->contable->dobj.name,
+ robj2->contable->dobj.name);
+ if (cmpval != 0)
+ return cmpval;
+ }
+ }
+ else if (obj1->objType == DO_PUBLICATION_REL)
+ {
+ PublicationRelInfo *probj1 = *(PublicationRelInfo *const *) p1;
+ PublicationRelInfo *probj2 = *(PublicationRelInfo *const *) p2;
+
+ /* Sort by publication name, since (namespace, name) match the rel */
+ cmpval = strcmp(probj1->publication->dobj.name,
+ probj2->publication->dobj.name);
+ if (cmpval != 0)
+ return cmpval;
+ }
- /* Usually shouldn't get here, but if we do, sort by OID */
+ /*
+ * Shouldn't get here except after catalog corruption, but if we do, sort
+ * by OID. This may make logically-identical databases differ in the
+ * order of objects in dump output. Users will get spurious schema diffs.
+ * Expect flaky failures of 002_pg_upgrade.pl test 'dump outputs from
+ * original and restored regression databases match' if the regression
+ * database contains objects allowing that test to reach here. That's a
+ * consequence of the test using "pg_restore -j", which doesn't fully
+ * constrain OID assignment order.
+ */
+ Assert(false);
return oidcmp(obj1->catId.oid, obj2->catId.oid);
}
+/* Compare two OID-identified pg_type values by nspname, then by typname. */
+static int
+pgTypeNameCompare(Oid typid1, Oid typid2)
+{
+ TypeInfo *typobj1;
+ TypeInfo *typobj2;
+ int cmpval;
+
+ if (typid1 == typid2)
+ return 0;
+
+ typobj1 = findTypeByOid(typid1);
+ typobj2 = findTypeByOid(typid2);
+
+ if (!typobj1 || !typobj2)
+ {
+ /*
+ * getTypes() didn't find some OID. Assume catalog corruption, e.g.
+ * an oprright value without the corresponding OID in a pg_type row.
+ * Report as "equal", so the caller uses the next available basis for
+ * comparison, e.g. the next function argument.
+ *
+ * Unary operators have InvalidOid in oprleft (if oprkind='r') or in
+ * oprright (if oprkind='l'). Caller already sorted by oprkind,
+ * calling us only for like-kind operators. Hence, "typid1 == typid2"
+ * took care of InvalidOid. (v14 removed postfix operator support.
+ * Hence, when dumping from v14+, only oprleft can be InvalidOid.)
+ */
+ Assert(false);
+ return 0;
+ }
+
+ if (!typobj1->dobj.namespace || !typobj2->dobj.namespace)
+ Assert(false); /* catalog corruption */
+ else
+ {
+ cmpval = strcmp(typobj1->dobj.namespace->dobj.name,
+ typobj2->dobj.namespace->dobj.name);
+ if (cmpval != 0)
+ return cmpval;
+ }
+ return strcmp(typobj1->dobj.name, typobj2->dobj.name);
+}
+
+/* Compare two OID-identified pg_am values by amname. */
+static int
+accessMethodNameCompare(Oid am1, Oid am2)
+{
+ AccessMethodInfo *amobj1;
+ AccessMethodInfo *amobj2;
+
+ if (am1 == am2)
+ return 0;
+
+ amobj1 = findAccessMethodByOid(am1);
+ amobj2 = findAccessMethodByOid(am2);
+
+ if (!amobj1 || !amobj2)
+ {
+ /* catalog corruption: handle like pgTypeNameCompare() does */
+ Assert(false);
+ return 0;
+ }
+
+ return strcmp(amobj1->dobj.name, amobj2->dobj.name);
+}
+
/*
* Sort the given objects into a safe dump order using dependency
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index b7ce080424f..35595fb1427 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -344,3 +344,11 @@ NOTICE: drop cascades to table pub_test.testpub_nopk
RESET SESSION AUTHORIZATION;
DROP ROLE regress_publication_user, regress_publication_user2;
DROP ROLE regress_publication_user_dummy;
+-- stage objects for pg_dump tests
+CREATE SCHEMA pubme CREATE TABLE t0 (c int, d int) CREATE TABLE t1 (c int);
+SET client_min_messages = 'ERROR';
+CREATE PUBLICATION dump_pub_1ct FOR TABLE ONLY pubme.t0;
+CREATE PUBLICATION dump_pub_2ct FOR TABLE ONLY pubme.t0, pubme.t1;
+CREATE PUBLICATION dump_pub_all FOR TABLE ONLY pubme.t0, pubme.t1
+ WITH (publish_via_partition_root = true);
+RESET client_min_messages;
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 7d5c9373845..021d4e2cb24 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -218,3 +218,12 @@ DROP SCHEMA pub_test CASCADE;
RESET SESSION AUTHORIZATION;
DROP ROLE regress_publication_user, regress_publication_user2;
DROP ROLE regress_publication_user_dummy;
+
+-- stage objects for pg_dump tests
+CREATE SCHEMA pubme CREATE TABLE t0 (c int, d int) CREATE TABLE t1 (c int);
+SET client_min_messages = 'ERROR';
+CREATE PUBLICATION dump_pub_1ct FOR TABLE ONLY pubme.t0;
+CREATE PUBLICATION dump_pub_2ct FOR TABLE ONLY pubme.t0, pubme.t1;
+CREATE PUBLICATION dump_pub_all FOR TABLE ONLY pubme.t0, pubme.t1
+ WITH (publish_via_partition_root = true);
+RESET client_min_messages;