Fix pg_dump to dump shell types.
authorTom Lane
Tue, 4 Aug 2015 23:34:12 +0000 (19:34 -0400)
committerTom Lane
Tue, 4 Aug 2015 23:34:12 +0000 (19:34 -0400)
Per discussion, it really ought to do this.  The original choice to
exclude shell types was probably made in the dark ages before we made
it harder to accidentally create shell types; but that was in 7.3.

Also, cause the standard regression tests to leave a shell type behind,
for convenience in testing the case in pg_dump and pg_upgrade.

Back-patch to all supported branches.

src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/test/regress/expected/create_type.out
src/test/regress/sql/create_type.sql

index 4c38ece01d8358581add190722ea613c271f91fa..55ae2798908a5137f268235bbee8e3a4c6b26c58 100644 (file)
@@ -175,6 +175,7 @@ static void dumpType(Archive *fout, TypeInfo *tyinfo);
 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
+static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
@@ -1311,11 +1312,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;
 }
@@ -3425,7 +3421,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);
    }
@@ -8008,6 +8004,8 @@ dumpType(Archive *fout, TypeInfo *tyinfo)
        dumpEnumType(fout, tyinfo);
    else if (tyinfo->typtype == TYPTYPE_RANGE)
        dumpRangeType(fout, tyinfo);
+   else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
+       dumpUndefinedType(fout, tyinfo);
    else
        write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
                  tyinfo->dobj.name);
@@ -8275,6 +8273,73 @@ dumpRangeType(Archive *fout, 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, 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 (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 (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, labelq->data,
+               tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+               tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+   dumpSecLabel(fout, labelq->data,
+                tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+                tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+   dumpACL(fout, 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
index 97fd024927cc3f1f39521388cd87b9565af8d937..bf3ada719f9974d8684e666efd6fab902a0af4a4 100644 (file)
@@ -161,7 +161,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;
index 6dfe9169854dcbdf884e92b28faab2cbfebb359a..09459adc3fecc9e12e2acb2da13a268a888c177f 100644 (file)
@@ -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)
 --
index a4906b64e10bfd91b9f5b916fed3aeb932b4aa66..62bd53cfbae431cf75084323d745e4fa3fbceedd 100644 (file)
@@ -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)
 --