Fix up pg_dump's --binary-upgrade option so that it behaves properly with
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Jul 2009 21:34:32 +0000 (21:34 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Jul 2009 21:34:32 +0000 (21:34 +0000)
inherited columns and check constraints.  Per my recent trouble report.

src/bin/pg_dump/pg_dump.c

index ad1086d169a5ec20a284fa2353b102ca9bc321cb..c1ab56283654af9a86ef07f29add9fffa00b659e 100644 (file)
@@ -12,7 +12,7 @@
  * by PostgreSQL
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.539 2009/06/11 14:49:07 momjian Exp $
+ *   $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.540 2009/07/02 21:34:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -233,7 +233,7 @@ main(int argc, char **argv)
    static int  outputNoTablespaces = 0;
    static int  use_setsessauth = 0;
 
-   struct option long_options[] = {
+   static struct option long_options[] = {
        {"data-only", no_argument, NULL, 'a'},
        {"blobs", no_argument, NULL, 'b'},
        {"clean", no_argument, NULL, 'c'},
@@ -1733,7 +1733,7 @@ dumpDatabase(Archive *AH)
    if (binary_upgrade)
    {
        appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
-       appendPQExpBuffer(creaQry, "UPDATE pg_database\n"
+       appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
                          "SET datfrozenxid = '%u'\n"
                          "WHERE    datname = ",
                          frozenxid);
@@ -4712,8 +4712,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
            appendPQExpBuffer(q, "SELECT a.attnum, a.attname, "
                           "a.atttypmod, -1 AS attstattarget, a.attstorage, "
                              "t.typstorage, a.attnotnull, a.atthasdef, "
-                             "false AS attisdropped, 0 AS attlen, "
-                             "' ' AS attalign, false AS attislocal, "
+                             "false AS attisdropped, a.attlen, "
+                             "a.attalign, false AS attislocal, "
                              "format_type(t.oid,a.atttypmod) AS atttypname "
                              "FROM pg_attribute a LEFT JOIN pg_type t "
                              "ON a.atttypid = t.oid "
@@ -4729,7 +4729,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                              "-1 AS attstattarget, attstorage, "
                              "attstorage AS typstorage, "
                              "attnotnull, atthasdef, false AS attisdropped, "
-                             "0 AS attlen, ' ' AS attalign, "
+                             "attlen, attalign, "
                              "false AS attislocal, "
                              "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname "
                              "FROM pg_attribute a "
@@ -4806,20 +4806,6 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 
        PQclear(res);
 
-
-       /*
-        * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid, so we set the
-        * column data type to 'TEXT;  we will later drop the column.
-        */
-       if (binary_upgrade)
-       {
-           for (j = 0; j < ntups; j++)
-           {
-               if (tbinfo->attisdropped[j])
-                   tbinfo->atttypnames[j] = strdup("TEXT");
-           }
-       }
-
        /*
         * Get info about column defaults
         */
@@ -9783,19 +9769,35 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
        actual_atts = 0;
        for (j = 0; j < tbinfo->numatts; j++)
        {
-           /* Is this one of the table's own attrs, and not dropped ? */
-           if (!tbinfo->inhAttrs[j] &&
-               (!tbinfo->attisdropped[j] || binary_upgrade))
+           /*
+            * Normally, dump if it's one of the table's own attrs, and not
+            * dropped.  But for binary upgrade, dump all the columns.
+            */
+           if ((!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j]) ||
+               binary_upgrade)
            {
                /* Format properly if not first attr */
                if (actual_atts > 0)
                    appendPQExpBuffer(q, ",");
                appendPQExpBuffer(q, "\n    ");
+               actual_atts++;
 
                /* Attribute name */
                appendPQExpBuffer(q, "%s ",
                                  fmtId(tbinfo->attnames[j]));
 
+               if (tbinfo->attisdropped[j])
+               {
+                   /*
+                    * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
+                    * so we will not have gotten a valid type name; insert
+                    * INTEGER as a stopgap.  We'll clean things up later.
+                    */
+                   appendPQExpBuffer(q, "INTEGER /* dummy */");
+                   /* Skip all the rest, too */
+                   continue;
+               }
+
                /* Attribute type */
                if (g_fout->remoteVersion >= 70100)
                {
@@ -9811,22 +9813,23 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                }
 
                /*
-                * Default value --- suppress if inherited or to be printed
-                * separately.
+                * Default value --- suppress if inherited (except in
+                * binary-upgrade case, where we're not doing normal
+                * inheritance) or if it's to be printed separately.
                 */
                if (tbinfo->attrdefs[j] != NULL &&
-                   !tbinfo->inhAttrDef[j] &&
+                   (!tbinfo->inhAttrDef[j] || binary_upgrade) &&
                    !tbinfo->attrdefs[j]->separate)
                    appendPQExpBuffer(q, " DEFAULT %s",
                                      tbinfo->attrdefs[j]->adef_expr);
 
                /*
-                * Not Null constraint --- suppress if inherited
+                * Not Null constraint --- suppress if inherited, except
+                * in binary-upgrade case.
                 */
-               if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
+               if (tbinfo->notnull[j] &&
+                   (!tbinfo->inhNotNull[j] || binary_upgrade))
                    appendPQExpBuffer(q, " NOT NULL");
-
-               actual_atts++;
            }
        }
 
@@ -9852,7 +9855,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 
        appendPQExpBuffer(q, "\n)");
 
-       if (numParents > 0)
+       if (numParents > 0 && !binary_upgrade)
        {
            appendPQExpBuffer(q, "\nINHERITS (");
            for (k = 0; k < numParents; k++)
@@ -9892,8 +9895,16 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
        appendPQExpBuffer(q, ";\n");
 
        /*
-        * For binary-compatible heap files, we create dropped columns above
-        * and drop them here.
+        * To create binary-compatible heap files, we have to ensure the
+        * same physical column order, including dropped columns, as in the
+        * original.  Therefore, we create dropped columns above and drop
+        * them here, also updating their attlen/attalign values so that
+        * the dropped column can be skipped properly.  (We do not bother
+        * with restoring the original attbyval setting.)  Also, inheritance
+        * relationships are set up by doing ALTER INHERIT rather than using
+        * an INHERITS clause --- the latter would possibly mess up the
+        * column order.  That also means we have to take care about setting
+        * attislocal correctly, plus fix up any inherited CHECK constraints.
         */
        if (binary_upgrade)
        {
@@ -9901,50 +9912,82 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
            {
                if (tbinfo->attisdropped[j])
                {
+                   appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
+                   appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
+                                     "SET attlen = %d, "
+                                     "attalign = '%c', attbyval = false\n"
+                                     "WHERE attname = ",
+                                     tbinfo->attlen[j],
+                                     tbinfo->attalign[j]);
+                   appendStringLiteralAH(q, tbinfo->attnames[j], fout);
+                   appendPQExpBuffer(q, "\n  AND attrelid = ");
+                   appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
+                   appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
+
                    appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
                                      fmtId(tbinfo->dobj.name));
                    appendPQExpBuffer(q, "DROP COLUMN %s;\n",
                                      fmtId(tbinfo->attnames[j]));
+               }
+               else if (!tbinfo->attislocal[j])
+               {
+                   appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
+                   appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
+                                     "SET attislocal = false\n"
+                                     "WHERE attname = ");
+                   appendStringLiteralAH(q, tbinfo->attnames[j], fout);
+                   appendPQExpBuffer(q, "\n  AND attrelid = ");
+                   appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
+                   appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
+               }
+           }
 
-                   /*
-                    * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
-                    * so we have to set pg_attribute.attlen and
-                    * pg_attribute.attalign values because that is what is
-                    * used to skip over dropped columns in the heap tuples.
-                    * We have atttypmod, but it seems impossible to know the
-                    * correct data type that will yield pg_attribute values
-                    * that match the old installation. See comment in
-                    * backend/catalog/heap.c::RemoveAttributeById()
-                    */
-                   appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column's length and alignment.\n");
-                   appendPQExpBuffer(q, "UPDATE pg_attribute\n"
-                                     "SET attlen = %d, "
-                                     "attalign = '%c'\n"
-                                     "WHERE    attname = '%s'\n"
-                                     " AND attrelid = \n"
-                                     " (\n"
-                                     "     SELECT oid\n"
-                                     "     FROM pg_class\n"
-                                     "     WHERE   relnamespace = "
-                                     "(SELECT oid FROM pg_namespace "
-                                     "WHERE nspname = CURRENT_SCHEMA)\n"
-                                     "         AND relname = ",
-                                     tbinfo->attlen[j],
-                                     tbinfo->attalign[j],
-                                     tbinfo->attnames[j]);
-                   appendStringLiteralAH(q, tbinfo->dobj.name, fout);
-                   appendPQExpBuffer(q, "\n    );\n");
+           for (k = 0; k < tbinfo->ncheck; k++)
+           {
+               ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
+
+               if (constr->separate || constr->conislocal)
+                   continue;
+
+               appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
+               appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
+                                 fmtId(tbinfo->dobj.name));
+               appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
+                                 fmtId(constr->dobj.name));
+               appendPQExpBuffer(q, "%s;\n", constr->condef);
+               appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
+                                 "SET conislocal = false\n"
+                                 "WHERE contype = 'c' AND conname = ");
+               appendStringLiteralAH(q, constr->dobj.name, fout);
+               appendPQExpBuffer(q, "\n  AND conrelid = ");
+               appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
+               appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
+           }
+
+           if (numParents > 0)
+           {
+               appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
+               for (k = 0; k < numParents; k++)
+               {
+                   TableInfo  *parentRel = parents[k];
+
+                   appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
+                                     fmtId(tbinfo->dobj.name));
+                   if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
+                       appendPQExpBuffer(q, "%s.",
+                                         fmtId(parentRel->dobj.namespace->dobj.name));
+                   appendPQExpBuffer(q, "%s;\n",
+                                     fmtId(parentRel->dobj.name));
                }
            }
+
            appendPQExpBuffer(q, "\n-- For binary upgrade, set relfrozenxid.\n");
-           appendPQExpBuffer(q, "UPDATE pg_class\n"
+           appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
                              "SET relfrozenxid = '%u'\n"
-                             "WHERE    relname = ",
+                             "WHERE oid = ",
                              tbinfo->frozenxid);
-           appendStringLiteralAH(q, tbinfo->dobj.name, fout);
-           appendPQExpBuffer(q, "\n    AND relnamespace = "
-                             "(SELECT oid FROM pg_namespace "
-                             "WHERE nspname = CURRENT_SCHEMA);\n");
+           appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
+           appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
        }
 
        /* Loop dumping statistics and storage statements */
@@ -10051,8 +10094,8 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
    if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
        return;
 
-   /* Don't print inherited defaults, either */
-   if (tbinfo->inhAttrDef[adnum - 1])
+   /* Don't print inherited defaults, either, except for binary upgrade */
+   if (tbinfo->inhAttrDef[adnum - 1] && !binary_upgrade)
        return;
 
    q = createPQExpBuffer();