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 b3dd617136b4353f748ec69331e0c71bbecc138a..72ec981fcc505e97deb786f85da4736a9011340f 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 8f4c1cd9b9245aeb2d28afbf761a94c2fcde9b15..533bdd9c0b8f5cad926e875a7ba8e9acd18a3ab2 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 317646252c50cc2d4365769d09a9a3b533b9556c..4957ea9a14763e40aa697da99fee7266d92c7eac 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 b3d89a209112aa9e5a5214bea5220071fc0451dd..19b080488842daaa24c2b0f218443f549e6b4fa6 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,12 +364,34 @@ 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.
     */
@@ -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 c01ea6ad5ba2e1e41966eade57c91c1a57250ad6..9e38b0d43a3e6a98084ca90c064dfa171d0c795e 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 9b0dd312dad859a823cfecdfd0aadff1c701d0c0..eef86a25e57626ba04b5a02190017c5c974f47df 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"));