diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index 2e30906..de139c3 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -698,6 +698,22 @@ PostgreSQL documentation + + + + + + Specifies the user identifier used by the dump session. This cause + pg_dump to issue a + SET ROLE TO rolename + command just after a successful database connection. It is useful in cases when + the logged in user specified by the -U option has not enough privileges needed by + pg_dump but can switch to a role with the needed rights. + The SET ROLE command is reserved in the archive because most of the time this + user identifier also needed for the restore to succeed. + + + diff --git a/doc/src/sgml/ref/pg_dumpall.sgml b/doc/src/sgml/ref/pg_dumpall.sgml index ec40890..16f3e0b 100644 --- a/doc/src/sgml/ref/pg_dumpall.sgml +++ b/doc/src/sgml/ref/pg_dumpall.sgml @@ -129,7 +129,7 @@ PostgreSQL documentation - + @@ -183,7 +183,7 @@ PostgreSQL documentation Do not output commands to set ownership of objects to match the original database. By default, pg_dumpall issues - ALTER OWNER or + ALTER OWNER or SET SESSION AUTHORIZATION statements to set ownership of created schema elements. These statements @@ -266,7 +266,7 @@ PostgreSQL documentation - + @@ -354,7 +354,7 @@ PostgreSQL documentation - + -l dbname --database=dbname @@ -397,7 +397,7 @@ PostgreSQL documentation Force pg_dumpall to prompt for a - password before connecting to a database. + password before connecting to a database. @@ -417,6 +417,21 @@ PostgreSQL documentation + + + + + + Specifies the user identifier used by the dump session. This option is passed + to pg_dump too and cause these applications to issue a + SET ROLE TO rolename + command just after a successful database connection. It is useful in cases when + the logged in user specified by the -U option has not enough privileges needed by + pg_dumpall but can switch to a role with the needed rights. + The SET ROLE command is reserved in the archive by pg_dump. + + + @@ -503,6 +518,6 @@ PostgreSQL documentation Check for details on possible error conditions. - + diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h index c57bb22..cbe4d46 100644 --- a/src/bin/pg_dump/pg_backup.h +++ b/src/bin/pg_dump/pg_backup.h @@ -70,6 +70,8 @@ typedef struct _Archive int encoding; /* libpq code for client_encoding */ bool std_strings; /* standard_conforming_strings */ + const char *rolename; /* role name */ + /* error handling */ bool exit_on_error; /* whether to exit on SQL errors... */ int n_errors; /* number of errors (if no die) */ diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 7bd44f2..6f6ed2f 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -56,6 +56,7 @@ static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName); static void _selectTablespace(ArchiveHandle *AH, const char *tablespace); static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te); static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te); +static void processRolenameEntry(ArchiveHandle *AH, TocEntry *te); static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls); static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt); static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt); @@ -1979,6 +1980,8 @@ ReadToc(ArchiveHandle *AH) processEncodingEntry(AH, te); else if (strcmp(te->desc, "STDSTRINGS") == 0) processStdStringsEntry(AH, te); + else if (strcmp(te->desc, "ROLENAME") == 0) + processRolenameEntry(AH, te); } } @@ -2026,15 +2029,39 @@ processStdStringsEntry(ArchiveHandle *AH, TocEntry *te) te->defn); } +static void +processRolenameEntry(ArchiveHandle *AH, TocEntry *te) +{ + /* te->defn should have the form SET role = 'foo'; */ + char *defn = strdup(te->defn); + char *ptr1; + char *ptr2 = NULL; + + ptr1 = strchr(defn, '\''); + if (ptr1) + ptr2 = strchr(++ptr1, '\''); + if (ptr2) + { + *ptr2 = '\0'; + AH->public.rolename = strdup(ptr1); + free(defn); + } + else + free(defn); + die_horribly(AH, modulename, "invalid ROLENAME item: %s\n", + te->defn); +} + static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls) { teReqs res = REQ_ALL; - /* ENCODING and STDSTRINGS items are dumped specially, so always reject */ + /* ENCODING, STDSTRINGS and ROLENAME items are dumped specially, so always reject */ if (strcmp(te->desc, "ENCODING") == 0 || - strcmp(te->desc, "STDSTRINGS") == 0) - return 0; + strcmp(te->desc, "STDSTRINGS") == 0 || + strcmp(te->desc, "ROLENAME") == 0) + return 0; /* If it's an ACL, maybe ignore it */ if ((!include_acls || ropt->aclsSkip) && strcmp(te->desc, "ACL") == 0) @@ -2146,6 +2173,11 @@ _doSetFixedOutputState(ArchiveHandle *AH) ahprintf(AH, "SET standard_conforming_strings = %s;\n", AH->public.std_strings ? "on" : "off"); + /* Select the role to be used during restore */ + if (AH->public.rolename) + ahprintf(AH, "SET role = %s;\n", + fmtId(AH->public.rolename)); + /* Make sure function checking is disabled */ ahprintf(AH, "SET check_function_bodies = false;\n"); diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 6c0f827..cd9ef9f 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -188,6 +188,7 @@ static int dumpBlobComments(Archive *AH, void *arg); static void dumpDatabase(Archive *AH); static void dumpEncoding(Archive *AH); static void dumpStdStrings(Archive *AH); +static void dumpRole(Archive *AH); static const char *getAttrName(int attrnum, TableInfo *tblInfo); static const char *fmtCopyColumnList(const TableInfo *ti); static void do_sql_command(PGconn *conn, const char *query); @@ -229,6 +230,10 @@ main(int argc, char **argv) static int outputNoTablespaces = 0; static int use_setsessauth = 0; + const char *pgrole = NULL; + PQExpBuffer roleQry; + PGresult *res; + static struct option long_options[] = { {"data-only", no_argument, NULL, 'a'}, {"blobs", no_argument, NULL, 'b'}, @@ -269,6 +274,7 @@ main(int argc, char **argv) {"lock-wait-timeout", required_argument, NULL, 2}, {"no-tablespaces", no_argument, &outputNoTablespaces, 1}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, + {"role", required_argument, NULL, 3}, {NULL, 0, NULL, 0} }; @@ -446,6 +452,10 @@ main(int argc, char **argv) lockWaitTimeout = optarg; break; + case 3: /* role */ + pgrole = optarg; + break; + default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); @@ -555,6 +565,20 @@ main(int argc, char **argv) } } + /* Set the role if requested */ + if (pgrole) + { + roleQry = createPQExpBuffer(); + appendPQExpBuffer(roleQry, "SET ROLE TO %s;\n", fmtId(pgrole)); + res = PQexec(g_conn, roleQry->data); + check_sql_result(res, g_conn, roleQry->data, PGRES_COMMAND_OK); + PQclear(res); + destroyPQExpBuffer(roleQry); + g_fout->rolename = pgrole; + } else { + g_fout->rolename = NULL; + } + /* * Get the active encoding and the standard_conforming_strings setting, so * we know how to escape strings. @@ -586,7 +610,7 @@ main(int argc, char **argv) */ if (g_fout->remoteVersion >= 70300) do_sql_command(g_conn, "SET statement_timeout = 0"); - + /* * Start serializable transaction to dump consistent data. */ @@ -715,6 +739,8 @@ main(int argc, char **argv) /* First the special ENCODING and STDSTRINGS entries. */ dumpEncoding(g_fout); dumpStdStrings(g_fout); + if (pgrole) + dumpRole(g_fout); /* The database item is always next, unless we don't want it at all */ if (include_everything && !dataOnly) @@ -800,6 +826,7 @@ help(const char *progname) printf(_(" --use-set-session-authorization\n" " use SESSION AUTHORIZATION commands instead of\n" " ALTER OWNER commands to set ownership\n")); + printf(_(" --role set role before dump\n")); printf(_("\nConnection options:\n")); printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); @@ -1800,6 +1827,32 @@ dumpStdStrings(Archive *AH) /* + * dumpRole: put the role change into the archive + */ +static void +dumpRole(Archive *AH) +{ + const char *rolename = AH->rolename; + PQExpBuffer qry = createPQExpBuffer(); + + if (g_verbose) + write_msg(NULL, "saving rolename = %s\n", rolename); + + appendPQExpBuffer(qry, "SET role = "); + appendStringLiteralAH(qry, rolename, AH); + appendPQExpBuffer(qry, ";\n"); + + ArchiveEntry(AH, nilCatalogId, createDumpId(), + "ROLENAME", NULL, NULL, "", + false, "ROLENAME", qry->data, "", NULL, + NULL, 0, + NULL, NULL); + + destroyPQExpBuffer(qry); +} + + +/* * hasBlobs: * Test whether database contains any large objects */ diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index b00fb5a..cb8b5a1 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -89,6 +89,9 @@ main(int argc, char *argv[]) int c, ret; + const char *pgrole = NULL; + PQExpBuffer roleQry; + static struct option long_options[] = { {"data-only", no_argument, NULL, 'a'}, {"clean", no_argument, NULL, 'c'}, @@ -121,6 +124,7 @@ main(int argc, char *argv[]) {"no-tablespaces", no_argument, &no_tablespaces, 1}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, {"lock-wait-timeout", required_argument, NULL, 2}, + {"role", required_argument, NULL, 3}, {NULL, 0, NULL, 0} }; @@ -289,7 +293,7 @@ main(int argc, char *argv[]) disable_dollar_quoting = 1; else if (strcmp(optarg, "disable-triggers") == 0) disable_triggers = 1; - else if (strcmp(optarg, "no-tablespaces") == 0) + else if (strcmp(optarg, "no-tablespaces") == 0) no_tablespaces = 1; else if (strcmp(optarg, "use-set-session-authorization") == 0) use_setsessauth = 1; @@ -311,6 +315,15 @@ main(int argc, char *argv[]) appendPQExpBuffer(pgdumpopts, optarg); break; + case 3: + pgrole = optarg; +#ifndef WIN32 + appendPQExpBuffer(pgdumpopts, " --role '%s'", optarg); +#else + appendPQExpBuffer(pgdumpopts, " --role \"%s\"", optarg); +#endif + break; + default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); @@ -426,6 +439,15 @@ main(int argc, char *argv[]) if (!std_strings) std_strings = "off"; + /* Set the role if requested */ + if (pgrole) + { + roleQry = createPQExpBuffer(); + appendPQExpBuffer(roleQry, "SET ROLE TO %s;\n", fmtId(pgrole)); + executeCommand(conn, roleQry->data); + destroyPQExpBuffer(roleQry); + } + fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n"); if (verbose) dumpTimestamp("Started on"); @@ -516,6 +538,7 @@ help(void) printf(_(" --use-set-session-authorization\n" " use SESSION AUTHORIZATION commands instead of\n" " OWNER TO commands\n")); + printf(_(" --role set role before dump\n")); printf(_("\nConnection options:\n")); printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); @@ -1527,3 +1550,4 @@ dumpTimestamp(char *msg) localtime(&now)) != 0) fprintf(OPF, "-- %s %s\n\n", msg, buf); } +