diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 00b86766336715f0a21e66110512f265ab1b5c3a..51b6d3ae77ed6dcfe8effd3e89e8d6b9d79e3351 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -158,6 +158,7 @@ static void dumpType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo); static void dumpBaseType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo); static void dumpEnumType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo); static void dumpRangeType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo); +static void dumpUndefinedType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo); static void dumpDomain(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo); static void dumpCompositeType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo); static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo); @@ -1329,11 +1330,6 @@ selectDumpableType(TypeInfo *tyinfo) /* dump only types in dumpable namespaces */ if (!tyinfo->dobj.namespace->dobj.dump) tyinfo->dobj.dump = false; - - /* skip undefined placeholder types */ - else if (!tyinfo->isDefined) - tyinfo->dobj.dump = false; - else tyinfo->dobj.dump = true; } @@ -3707,7 +3703,7 @@ getTypes(Archive *fout, int *numTypes) } } - if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined) + if (strlen(tyinfo[i].rolname) == 0) write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n", tyinfo[i].dobj.name); } @@ -8554,6 +8550,8 @@ dumpType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo) dumpEnumType(fout, dopt, tyinfo); else if (tyinfo->typtype == TYPTYPE_RANGE) dumpRangeType(fout, dopt, tyinfo); + else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined) + dumpUndefinedType(fout, dopt, tyinfo); else write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n", tyinfo->dobj.name); @@ -8820,6 +8818,73 @@ dumpRangeType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo) destroyPQExpBuffer(query); } +/* + * dumpUndefinedType + * writes out to fout the queries to recreate a !typisdefined type + * + * This is a shell type, but we use different terminology to distinguish + * this case from where we have to emit a shell type definition to break + * circular dependencies. An undefined type shouldn't ever have anything + * depending on it. + */ +static void +dumpUndefinedType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo) +{ + PQExpBuffer q = createPQExpBuffer(); + PQExpBuffer delq = createPQExpBuffer(); + PQExpBuffer labelq = createPQExpBuffer(); + char *qtypname; + + qtypname = pg_strdup(fmtId(tyinfo->dobj.name)); + + /* + * DROP must be fully qualified in case same name appears in pg_catalog. + */ + appendPQExpBuffer(delq, "DROP TYPE %s.", + fmtId(tyinfo->dobj.namespace->dobj.name)); + appendPQExpBuffer(delq, "%s;\n", + qtypname); + + if (dopt->binary_upgrade) + binary_upgrade_set_type_oids_by_type_oid(fout, + q, tyinfo->dobj.catId.oid); + + appendPQExpBuffer(q, "CREATE TYPE %s;\n", + qtypname); + + appendPQExpBuffer(labelq, "TYPE %s", qtypname); + + if (dopt->binary_upgrade) + binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data); + + ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, + tyinfo->dobj.name, + tyinfo->dobj.namespace->dobj.name, + NULL, + tyinfo->rolname, false, + "TYPE", SECTION_PRE_DATA, + q->data, delq->data, NULL, + NULL, 0, + NULL, NULL); + + /* Dump Type Comments and Security Labels */ + dumpComment(fout, dopt, labelq->data, + tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, + tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId); + dumpSecLabel(fout, dopt, labelq->data, + tyinfo->dobj.namespace->dobj.name, tyinfo->rolname, + tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId); + + dumpACL(fout, dopt, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE", + qtypname, NULL, tyinfo->dobj.name, + tyinfo->dobj.namespace->dobj.name, + tyinfo->rolname, tyinfo->typacl); + + destroyPQExpBuffer(q); + destroyPQExpBuffer(delq); + destroyPQExpBuffer(labelq); +} + /* * dumpBaseType * writes out to fout the queries to recreate a user-defined base type diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 009dba5c9d7966c4b61ab04f79dff471a49154fe..da7597ded1c177b755b36d08057056734fb5835c 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -127,7 +127,7 @@ typedef struct _typeInfo char typtype; /* 'b', 'c', etc */ bool isArray; /* true if auto-generated array type */ bool isDefined; /* true if typisdefined */ - /* If it's a dumpable base type, we create a "shell type" entry for it */ + /* If needed, we'll create a "shell type" entry for it; link that here: */ struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */ /* If it's a domain, we store links to its constraints here: */ int nDomChecks; diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out index b5af862ce5c14425f8e4b61c1aa07067966a51c4..7bdad4e9bb5e3c14d8807856fec2320aeaf43b00 100644 --- a/src/test/regress/expected/create_type.out +++ b/src/test/regress/expected/create_type.out @@ -29,6 +29,8 @@ ERROR: type "shell" already exists DROP TYPE shell; DROP TYPE shell; -- fail, type not exist ERROR: type "shell" does not exist +-- also, let's leave one around for purposes of pg_dump testing +CREATE TYPE myshell; -- -- Test type-related default values (broken in releases before PG 7.2) -- diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql index 29ba625b46ad1c4654562365106743d3fcd6a022..a1839ef9e7ff847dc5dfbd74d9249e517dd82255 100644 --- a/src/test/regress/sql/create_type.sql +++ b/src/test/regress/sql/create_type.sql @@ -31,6 +31,9 @@ CREATE TYPE shell; -- fail, type already present DROP TYPE shell; DROP TYPE shell; -- fail, type not exist +-- also, let's leave one around for purposes of pg_dump testing +CREATE TYPE myshell; + -- -- Test type-related default values (broken in releases before PG 7.2) --