OSDN Git Service

Change pg_dump to use ALTER OWNER commands instead of SET SESSION
authorBruce Momjian <bruce@momjian.us>
Tue, 13 Jul 2004 03:00:17 +0000 (03:00 +0000)
committerBruce Momjian <bruce@momjian.us>
Tue, 13 Jul 2004 03:00:17 +0000 (03:00 +0000)
AUTHORIZATION commands by default.  Move all GRANT and REVOKE commands
to the end of the dump to avoid restore failures in several situations.
Bring back --use-set-session-authorization option to get previous SET
behaviour

Christopher Kings-Lyne

doc/src/sgml/ref/pg_dump.sgml
doc/src/sgml/ref/pg_restore.sgml
src/bin/pg_dump/pg_backup.h
src/bin/pg_dump/pg_backup_archiver.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_restore.c

index b3dd617..72ec981 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/pg_dump.sgml,v 1.72 2004/07/10 15:51:28 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/pg_dump.sgml,v 1.73 2004/07/13 02:59:49 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -464,10 +464,10 @@ PostgreSQL documentation
       <term><option>--use-set-session-authorization</></term>
       <listitem>
        <para>
-        This option is obsolete but still accepted for backwards
-        compatibility.
-        <application>pg_dump</application> now always behaves in the
-        way formerly selected by this option.
+       Output SQL standard SET SESSION AUTHORIZATION commands instead
+       of OWNER TO commands.  This makes the dump more standards compatible,
+       but depending on the history of the objects in the dump, may not
+       restore properly.
        </para>
       </listitem>
      </varlistentry>
index 8f4c1cd..533bdd9 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/pg_restore.sgml,v 1.46 2004/02/17 09:07:16 neilc Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/pg_restore.sgml,v 1.47 2004/07/13 02:59:49 momjian Exp $ -->
 
 <refentry id="APP-PGRESTORE">
  <refmeta>
       <term><option>--use-set-session-authorization</option></term>
       <listitem>
        <para>
-        This option is obsolete but still accepted for backwards
-       compatibility.
-        <application>pg_restore</application> now always behaves in the
-       way formerly selected by this option.
+       Output SQL standard SET SESSION AUTHORIZATION commands instead
+       of OWNER TO commands.  This makes the dump more standards compatible,
+       but depending on the history of the objects in the dump, may not
+       restore properly.
        </para>
       </listitem>
      </varlistentry>
index 3176462..4957ea9 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *             $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup.h,v 1.30 2004/04/22 02:39:09 momjian Exp $
+ *             $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup.h,v 1.31 2004/07/13 03:00:17 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,6 +73,7 @@ typedef struct _restoreOptions
        int                     noOwner;                /* Don't try to match original object owner */
        int                     disable_triggers;               /* disable triggers during
                                                                                 * data-only restore */
+       int                     use_setsessauth;        /* Use SET SESSION AUTHORIZATION commands instead of OWNER TO */
        char       *superuser;          /* Username to use as superuser */
        int                     dataOnly;
        int                     dropSchema;
index b3d89a2..19b0804 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *             $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.87 2004/05/19 21:21:26 momjian Exp $
+ *             $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.88 2004/07/13 03:00:17 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,7 +47,10 @@ static char *modulename = gettext_noop("archiver");
 
 static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
                 const int compression, ArchiveMode mode);
-static int     _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData);
+static char    *_getObjectFromDropStmt(const char *dropStmt, const char *type);
+static void    _printTocHeader(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData);
+static int     _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool ownerAndACL);
+
 
 static void fixPriorBlobRefs(ArchiveHandle *AH, TocEntry *blobte,
                                                         RestoreOptions *ropt);
@@ -59,7 +62,7 @@ static void _becomeUser(ArchiveHandle *AH, const char *user);
 static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
 static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
 
-static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt);
+static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool ownerAndACL);
 static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
 static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
 static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
@@ -181,7 +184,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
                impliedDataOnly = 1;
                while (te != AH->toc)
                {
-                       reqs = _tocEntryRequired(te, ropt);
+                       reqs = _tocEntryRequired(te, ropt, false);
                        if ((reqs & REQ_SCHEMA) != 0)
                        {                                       /* It's schema, and it's wanted */
                                impliedDataOnly = 0;
@@ -217,7 +220,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
                te = AH->toc->prev;
                while (te != AH->toc)
                {
-                       reqs = _tocEntryRequired(te, ropt);
+                       reqs = _tocEntryRequired(te, ropt, false);
                        if (((reqs & REQ_SCHEMA) != 0) && te->dropStmt)
                        {
                                /* We want the schema */
@@ -239,7 +242,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
        while (te != AH->toc)
        {
                /* Work out what, if anything, we want from this entry */
-               reqs = _tocEntryRequired(te, ropt);
+               reqs = _tocEntryRequired(te, ropt, false);
 
                /* Dump any relevant dump warnings to stderr */
                if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
@@ -256,7 +259,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
                {
                        ahlog(AH, 1, "creating %s %s\n", te->desc, te->tag);
 
-                       _printTocEntry(AH, te, ropt, false);
+                       _printTocEntry(AH, te, ropt, false, false);
                        defnDumped = true;
 
                        /* If we created a DB, connect to it... */
@@ -290,7 +293,7 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
                                                die_horribly(AH, modulename, "cannot restore from compressed archive (not configured for compression support)\n");
 #endif
 
-                                       _printTocEntry(AH, te, ropt, true);
+                                       _printTocEntry(AH, te, ropt, true, false);
 
                                        /*
                                         * Maybe we can't do BLOBS, so check if this node is
@@ -361,13 +364,35 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt)
                        {
                                /* If we haven't already dumped the defn part, do so now */
                                ahlog(AH, 1, "executing %s %s\n", te->desc, te->tag);
-                               _printTocEntry(AH, te, ropt, false);
+                               _printTocEntry(AH, te, ropt, false, false);
                        }
                }
                te = te->next;
        }               /* end loop over TOC entries */
 
        /*
+        * Scan TOC again to output ownership commands and ACLs
+        */
+       te = AH->toc->next;
+       while (te != AH->toc)
+       {
+               /* Work out what, if anything, we want from this entry */
+               reqs = _tocEntryRequired(te, ropt, true);
+
+               defnDumped = false;
+
+               if ((reqs & REQ_SCHEMA) != 0)   /* We want the schema */
+               {
+                       ahlog(AH, 1, "setting owner and acl for %s %s\n", te->desc, te->tag);
+
+                       _printTocEntry(AH, te, ropt, false, true);
+                       defnDumped = true;
+               }
+
+               te = te->next;
+       }
+
+       /*
         * Clean up & we're done.
         */
        if (ropt->filename || ropt->compression)
@@ -408,7 +433,7 @@ fixPriorBlobRefs(ArchiveHandle *AH, TocEntry *blobte, RestoreOptions *ropt)
                {
                        if (strcmp(te->desc, "TABLE DATA") == 0)
                        {
-                               reqs = _tocEntryRequired(te, ropt);
+                               reqs = _tocEntryRequired(te, ropt, false);
 
                                if ((reqs & REQ_DATA) != 0)             /* We loaded the data */
                                {
@@ -659,7 +684,7 @@ PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
 
        while (te != AH->toc)
        {
-               if (_tocEntryRequired(te, ropt) != 0)
+               if (_tocEntryRequired(te, ropt, false) != 0)
                        ahprintf(AH, "%d; %u %u %s %s %s\n", te->dumpId,
                                         te->catalogId.tableoid, te->catalogId.oid,
                                         te->desc, te->tag, te->owner);
@@ -1270,7 +1295,7 @@ TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
        if (!te)
                return 0;
 
-       return _tocEntryRequired(te, ropt);
+       return _tocEntryRequired(te, ropt, false);
 }
 
 size_t
@@ -1888,7 +1913,7 @@ ReadToc(ArchiveHandle *AH)
 }
 
 static teReqs
-_tocEntryRequired(TocEntry *te, RestoreOptions *ropt)
+_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool ownerAndACL)
 {
        teReqs          res = 3;                /* Schema = 1, Data = 2, Both = 3 */
 
@@ -1897,7 +1922,7 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt)
                return 0;
 
        /* If it's an ACL, maybe ignore it */
-       if (ropt->aclsSkip && strcmp(te->desc, "ACL") == 0)
+       if ((!ownerAndACL || ropt->aclsSkip) && strcmp(te->desc, "ACL") == 0)
                return 0;
 
        if (!ropt->create && strcmp(te->desc, "DATABASE") == 0)
@@ -2159,7 +2184,7 @@ _becomeUser(ArchiveHandle *AH, const char *user)
 static void
 _becomeOwner(ArchiveHandle *AH, TocEntry *te)
 {
-       if (AH->ropt && AH->ropt->noOwner)
+       if (AH->ropt && (AH->ropt->noOwner || !AH->ropt->use_setsessauth))
                return;
 
        _becomeUser(AH, te->owner);
@@ -2224,18 +2249,65 @@ _selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
 }
 
 
+/**
+ * Parses the dropStmt part of a TOC entry and returns
+ * a newly allocated string that is the object identifier
+ * The caller must free the result.
+ */
+static char *
+_getObjectFromDropStmt(const char *dropStmt, const char *type)
+{
+       /* Chop "DROP" off the front and make a copy */
+       char *first = strdup(dropStmt + 5);
+       char *last = first + strlen(first) - 1; /* Points to the last real char in extract */
+       char *buf = NULL;
+
+       /* Loop from the end of the string until last char is no longer '\n' or ';' */
+       while (last >= first && (*last == '\n' || *last == ';')) {
+               last--;
+       }
+
+       /* Insert end of string one place after last */
+       *(last + 1) = '\0';
 
-static int
-_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData)
+       /* Take off CASCADE if necessary.  Only TYPEs seem to have this, but may
+        * as well check for all */
+       if ((last - first) >= 8) {
+               if (strcmp(last - 7, " CASCADE") == 0)
+                       last -= 8;
+       }
+
+       /* Insert end of string one place after last */
+       *(last + 1) = '\0';
+
+       /* Special case VIEWs and SEQUENCEs.  They must use ALTER TABLE. */
+       if (strcmp(type, "VIEW") == 0 && (last - first) >= 5)
+       {
+               int len = 6 + strlen(first + 5) + 1;
+               buf = malloc(len);
+               snprintf(buf, len, "TABLE %s", first + 5);
+               free (first);
+       }
+       else if (strcmp(type, "SEQUENCE") == 0 && (last - first) >= 9)
+       {
+               int len = 6 + strlen(first + 9) + 1;
+               buf = malloc(len);
+               snprintf(buf, len, "TABLE %s", first + 9);
+               free (first);
+       }
+       else
+       {
+               buf = first;
+       }
+
+       return buf;
+}
+
+static void
+_printTocHeader(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData)
 {
        const char         *pfx;
 
-       /* Select owner and schema as necessary */
-       _becomeOwner(AH, te);
-       _selectOutputSchema(AH, te->namespace);
-       if (strcmp(te->desc, "TABLE") == 0)
-               _setWithOids(AH, te);
-
        if (isData)
                pfx = "Data for ";
        else
@@ -2263,21 +2335,60 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
        if (AH->PrintExtraTocPtr != NULL)
                (*AH->PrintExtraTocPtr) (AH, te);
        ahprintf(AH, "--\n\n");
+}
 
-       /*
-        * Really crude hack for suppressing AUTHORIZATION clause of CREATE SCHEMA
-        * when --no-owner mode is selected.  This is ugly, but I see no other
-        * good way ...
-        */
-       if (AH->ropt && AH->ropt->noOwner && strcmp(te->desc, "SCHEMA") == 0)
+static int
+_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool ownerAndACL)
+{
+       /* Select schema as necessary */
+       _becomeOwner(AH, te);
+       _selectOutputSchema(AH, te->namespace);
+       if (strcmp(te->desc, "TABLE") == 0 && !ownerAndACL)
+               _setWithOids(AH, te);
+
+       if (!ropt->noOwner && !ropt->use_setsessauth && ownerAndACL && strlen(te->owner) > 0 && strlen(te->dropStmt) > 0 && (
+                                                       strcmp(te->desc, "AGGREGATE") == 0 ||
+                                                       strcmp(te->desc, "CONVERSION") == 0 ||
+                                                       strcmp(te->desc, "DOMAIN") == 0 ||
+                                                       strcmp(te->desc, "FUNCTION") == 0 ||
+                                                       strcmp(te->desc, "OPERATOR") == 0 ||
+                                                       strcmp(te->desc, "OPERATOR CLASS") == 0 ||
+                                                       strcmp(te->desc, "TABLE") == 0 ||
+                                                       strcmp(te->desc, "TYPE") == 0 ||
+                                                       strcmp(te->desc, "VIEW") == 0 ||
+                                                       strcmp(te->desc, "SEQUENCE") == 0
+                                                       ))
        {
-               ahprintf(AH, "CREATE SCHEMA %s;\n\n\n", te->tag);
+               char *temp = _getObjectFromDropStmt(te->dropStmt, te->desc);
+               _printTocHeader(AH, te, ropt, isData);
+               ahprintf(AH, "ALTER %s OWNER TO %s;\n\n", temp, fmtId(te->owner));
+               free (temp);
+       } 
+       else if (ownerAndACL && strcmp(te->desc, "ACL") == 0)
+       {
+               _printTocHeader(AH, te, ropt, isData);
+               ahprintf(AH, "%s\n\n", te->defn);
        }
-       else
+       else if (!ownerAndACL && strlen(te->defn) > 0)
        {
-               /* normal case */
-               if (strlen(te->defn) > 0)
+               _printTocHeader(AH, te, ropt, isData);
+
+               /*
+                * Really crude hack for suppressing AUTHORIZATION clause of CREATE SCHEMA
+                * when --no-owner mode is selected.  This is ugly, but I see no other
+                * good way ...
+                */
+               if (AH->ropt && AH->ropt->noOwner && strcmp(te->desc, "SCHEMA") == 0)
+               {
+                       ahprintf(AH, "CREATE SCHEMA %s;\n\n\n", te->tag);
+               }
+               else
+               {
                        ahprintf(AH, "%s\n\n", te->defn);
+               }
+       }
+       else if (isData) {
+               _printTocHeader(AH, te, ropt, isData);
        }
 
        return 1;
index c01ea6a..9e38b0d 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.378 2004/07/12 05:37:53 tgl Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.379 2004/07/13 03:00:17 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -392,7 +392,7 @@ main(int argc, char **argv)
                                else if (strcmp(optarg, "disable-triggers") == 0)
                                        disable_triggers = 1;
                                else if (strcmp(optarg, "use-set-session-authorization") == 0)
-                                       /* no-op, still allowed for compatibility */ ;
+                                       use_setsessauth = 1;
                                else
                                {
                                        fprintf(stderr,
@@ -636,6 +636,7 @@ main(int argc, char **argv)
                ropt->create = outputCreate;
                ropt->noOwner = outputNoOwner;
                ropt->disable_triggers = disable_triggers;
+               ropt->use_setsessauth = use_setsessauth;
 
                if (compressLevel == -1)
                        ropt->compression = 0;
@@ -693,6 +694,9 @@ help(const char *progname)
                         "                           disable dollar quoting, use SQL standard quoting\n"));
        printf(_("  -X disable-triggers, --disable-triggers\n"
                         "                           disable triggers during data-only restore\n"));
+       printf(_("  -X use-set-session-authorization, --use-set-session-authorization\n"
+                        "                           use SESSION AUTHORIZATION commands instead of\n"
+                        "                           OWNER TO commands\n"));
 
        printf(_("\nConnection options:\n"));
        printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
index 9b0dd31..eef86a2 100644 (file)
@@ -34,7 +34,7 @@
  *
  *
  * IDENTIFICATION
- *             $PostgreSQL: pgsql/src/bin/pg_dump/pg_restore.c,v 1.58 2004/06/03 00:07:37 momjian Exp $
+ *             $PostgreSQL: pgsql/src/bin/pg_dump/pg_restore.c,v 1.59 2004/07/13 03:00:17 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -243,7 +243,7 @@ main(int argc, char **argv)
 
                        case 'X':
                                if (strcmp(optarg, "use-set-session-authorization") == 0)
-                                       /* no-op, still allowed for compatibility */ ;
+                                       use_setsessauth = 1;
                                else if (strcmp(optarg, "disable-triggers") == 0)
                                        disable_triggers = 1;
                                else
@@ -286,6 +286,7 @@ main(int argc, char **argv)
        }
 
        opts->disable_triggers = disable_triggers;
+       opts->use_setsessauth = use_setsessauth;
 
        if (opts->formatName)
        {
@@ -381,6 +382,9 @@ usage(const char *progname)
        printf(_("  -x, --no-privileges      skip restoration of access privileges (grant/revoke)\n"));
        printf(_("  -X disable-triggers, --disable-triggers\n"
                         "                           disable triggers during data-only restore\n"));
+       printf(_("  -X use-set-session-authorization, --use-set-session-authorization\n"
+                        "                           use SESSION AUTHORIZATION commands instead of\n"
+                        "                           OWNER TO commands\n"));
 
        printf(_("\nConnection options:\n"));
        printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));