diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index b3dd617136..72ec981fcc 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -1,5 +1,5 @@ @@ -464,10 +464,10 @@ PostgreSQL documentation - This option is obsolete but still accepted for backwards - compatibility. - pg_dump 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. diff --git a/doc/src/sgml/ref/pg_restore.sgml b/doc/src/sgml/ref/pg_restore.sgml index 8f4c1cd9b9..533bdd9c0b 100644 --- a/doc/src/sgml/ref/pg_restore.sgml +++ b/doc/src/sgml/ref/pg_restore.sgml @@ -1,4 +1,4 @@ - + @@ -337,10 +337,10 @@ - This option is obsolete but still accepted for backwards - compatibility. - pg_restore 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. diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h index 317646252c..4957ea9a14 100644 --- a/src/bin/pg_dump/pg_backup.h +++ b/src/bin/pg_dump/pg_backup.h @@ -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; diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index b3d89a2091..19b0804888 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -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; -static int -_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData) + /* 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'; + + /* 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; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index c01ea6ad5b..9e38b0d43a 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -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")); diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c index 9b0dd312da..eef86a25e5 100644 --- a/src/bin/pg_dump/pg_restore.c +++ b/src/bin/pg_dump/pg_restore.c @@ -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"));