diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 8a31672247..0cc9eded24 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -17911,14 +17911,45 @@ getDependencies(Archive *fout) query = createPQExpBuffer(); /* + * Messy query to collect the dependency data we need. Note that we + * ignore the sub-object column, so that dependencies of or on a column + * look the same as dependencies of or on a whole table. + * * PIN dependencies aren't interesting, and EXTENSION dependencies were * already processed by getExtensionMembership. */ appendPQExpBufferStr(query, "SELECT " "classid, objid, refclassid, refobjid, deptype " "FROM pg_depend " - "WHERE deptype != 'p' AND deptype != 'e' " - "ORDER BY 1,2"); + "WHERE deptype != 'p' AND deptype != 'e'\n"); + + /* + * Since we don't treat pg_amop entries as separate DumpableObjects, we + * have to translate their dependencies into dependencies of their parent + * opfamily. Ignore internal dependencies though, as those will point to + * their parent opclass, which we needn't consider here (and if we did, + * it'd just result in circular dependencies). Also, "loose" opfamily + * entries will have dependencies on their parent opfamily, which we + * should drop since they'd likewise become useless self-dependencies. + * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.) + */ + appendPQExpBufferStr(query, "UNION ALL\n" + "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype " + "FROM pg_depend d, pg_amop o " + "WHERE deptype NOT IN ('p', 'e', 'i') AND " + "classid = 'pg_amop'::regclass AND objid = o.oid " + "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n"); + + /* Likewise for pg_amproc entries */ + appendPQExpBufferStr(query, "UNION ALL\n" + "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype " + "FROM pg_depend d, pg_amproc p " + "WHERE deptype NOT IN ('p', 'e', 'i') AND " + "classid = 'pg_amproc'::regclass AND objid = p.oid " + "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n"); + + /* Sort the output for efficiency below */ + appendPQExpBufferStr(query, "ORDER BY 1,2"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 7cbccee103..f064ea1063 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -1571,6 +1571,35 @@ my %tests = ( unlike => { exclude_dump_test_schema => 1, }, }, + # verify that a custom operator/opclass/range type is dumped in right order + 'CREATE OPERATOR CLASS dump_test.op_class_custom' => { + create_order => 74, + create_sql => 'CREATE OPERATOR dump_test.~~ ( + PROCEDURE = int4eq, + LEFTARG = int, + RIGHTARG = int); + CREATE OPERATOR CLASS dump_test.op_class_custom + FOR TYPE int USING btree AS + OPERATOR 3 dump_test.~~; + CREATE TYPE dump_test.range_type_custom AS RANGE ( + subtype = int, + subtype_opclass = dump_test.op_class_custom);', + regexp => qr/^ + \QCREATE OPERATOR dump_test.~~ (\E\n.+ + \QCREATE OPERATOR FAMILY dump_test.op_class_custom USING btree;\E\n.+ + \QCREATE OPERATOR CLASS dump_test.op_class_custom\E\n\s+ + \QFOR TYPE integer USING btree FAMILY dump_test.op_class_custom AS\E\n\s+ + \QOPERATOR 3 dump_test.~~(integer,integer);\E\n.+ + \QCREATE TYPE dump_test.range_type_custom AS RANGE (\E\n\s+ + \Qsubtype = integer,\E\n\s+ + \Qsubtype_opclass = dump_test.op_class_custom\E\n + \Q);\E + /xms, + like => + { %full_runs, %dump_test_schema_runs, section_pre_data => 1, }, + unlike => { exclude_dump_test_schema => 1, }, + }, + 'CREATE OPERATOR CLASS dump_test.op_class_empty' => { create_order => 89, create_sql => 'CREATE OPERATOR CLASS dump_test.op_class_empty