Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e1e17e2

Browse files
committed
Fix pg_dumpall so that when --clean is specified, it drops roles and
tablespaces in an order that has some chance of working. Per a complaint from Kevin Bailey. This is a pre-existing bug, but given the lack of prior complaints I'm not sure it's worth back-patching. In most cases failure of the DROP commands wouldn't be that important anyway. In passing, fix syntax errors in dumpCreateDB()'s queries for old servers; these were apparently introduced in recent binary_upgrade patch.
1 parent 088ac58 commit e1e17e2

File tree

1 file changed

+168
-28
lines changed

1 file changed

+168
-28
lines changed

src/bin/pg_dump/pg_dumpall.c

+168-28
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1994, Regents of the University of California
77
*
88
*
9-
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.123 2009/04/08 19:02:37 heikki Exp $
9+
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.124 2009/04/11 20:23:05 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -33,10 +33,13 @@ static const char *progname;
3333

3434
static void help(void);
3535

36+
static void dropRoles(PGconn *conn);
3637
static void dumpRoles(PGconn *conn);
3738
static void dumpRoleMembership(PGconn *conn);
3839
static void dumpGroups(PGconn *conn);
40+
static void dropTablespaces(PGconn *conn);
3941
static void dumpTablespaces(PGconn *conn);
42+
static void dropDBs(PGconn *conn);
4043
static void dumpCreateDB(PGconn *conn);
4144
static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
4245
static void dumpUserConfig(PGconn *conn, const char *username);
@@ -54,7 +57,6 @@ static void executeCommand(PGconn *conn, const char *query);
5457

5558
static char pg_dump_bin[MAXPGPATH];
5659
static PQExpBuffer pgdumpopts;
57-
static bool output_clean = false;
5860
static bool skip_acls = false;
5961
static bool verbose = false;
6062

@@ -82,6 +84,7 @@ main(int argc, char *argv[])
8284
enum trivalue prompt_password = TRI_DEFAULT;
8385
bool data_only = false;
8486
bool globals_only = false;
87+
bool output_clean = false;
8588
bool roles_only = false;
8689
bool tablespaces_only = false;
8790
bool schema_only = false;
@@ -90,8 +93,9 @@ main(int argc, char *argv[])
9093
const char *std_strings;
9194
int c,
9295
ret;
96+
int optindex;
9397

94-
struct option long_options[] = {
98+
static struct option long_options[] = {
9599
{"data-only", no_argument, NULL, 'a'},
96100
{"clean", no_argument, NULL, 'c'},
97101
{"file", required_argument, NULL, 'f'},
@@ -130,8 +134,6 @@ main(int argc, char *argv[])
130134
{NULL, 0, NULL, 0}
131135
};
132136

133-
int optindex;
134-
135137
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
136138

137139
progname = get_progname(argv[0]);
@@ -442,16 +444,41 @@ main(int argc, char *argv[])
442444

443445
fprintf(OPF, "\\connect postgres\n\n");
444446

447+
/* Replicate encoding and std_strings in output */
448+
fprintf(OPF, "SET client_encoding = '%s';\n",
449+
pg_encoding_to_char(encoding));
450+
fprintf(OPF, "SET standard_conforming_strings = %s;\n", std_strings);
451+
if (strcmp(std_strings, "off") == 0)
452+
fprintf(OPF, "SET escape_string_warning = off;\n");
453+
fprintf(OPF, "\n");
454+
445455
if (!data_only)
446456
{
447-
/* Replicate encoding and std_strings in output */
448-
fprintf(OPF, "SET client_encoding = '%s';\n",
449-
pg_encoding_to_char(encoding));
450-
fprintf(OPF, "SET standard_conforming_strings = %s;\n", std_strings);
451-
if (strcmp(std_strings, "off") == 0)
452-
fprintf(OPF, "SET escape_string_warning = 'off';\n");
453-
fprintf(OPF, "\n");
457+
/*
458+
* If asked to --clean, do that first. We can avoid detailed
459+
* dependency analysis because databases never depend on each other,
460+
* and tablespaces never depend on each other. Roles could have
461+
* grants to each other, but DROP ROLE will clean those up silently.
462+
*/
463+
if (output_clean)
464+
{
465+
if (!globals_only && !roles_only && !tablespaces_only)
466+
dropDBs(conn);
454467

468+
if (!roles_only && !no_tablespaces)
469+
{
470+
if (server_version >= 80000)
471+
dropTablespaces(conn);
472+
}
473+
474+
if (!tablespaces_only)
475+
dropRoles(conn);
476+
}
477+
478+
/*
479+
* Now create objects as requested. Be careful that option logic
480+
* here is the same as for drops above.
481+
*/
455482
if (!tablespaces_only)
456483
{
457484
/* Dump roles (users) */
@@ -492,7 +519,6 @@ main(int argc, char *argv[])
492519
}
493520

494521

495-
496522
static void
497523
help(void)
498524
{
@@ -541,6 +567,48 @@ help(void)
541567
}
542568

543569

570+
/*
571+
* Drop roles
572+
*/
573+
static void
574+
dropRoles(PGconn *conn)
575+
{
576+
PGresult *res;
577+
int i_rolname;
578+
int i;
579+
580+
if (server_version >= 80100)
581+
res = executeQuery(conn,
582+
"SELECT rolname "
583+
"FROM pg_authid "
584+
"ORDER BY 1");
585+
else
586+
res = executeQuery(conn,
587+
"SELECT usename as rolname "
588+
"FROM pg_shadow "
589+
"UNION "
590+
"SELECT groname as rolname "
591+
"FROM pg_group "
592+
"ORDER BY 1");
593+
594+
i_rolname = PQfnumber(res, "rolname");
595+
596+
if (PQntuples(res) > 0)
597+
fprintf(OPF, "--\n-- Drop roles\n--\n\n");
598+
599+
for (i = 0; i < PQntuples(res); i++)
600+
{
601+
const char *rolename;
602+
603+
rolename = PQgetvalue(res, i, i_rolname);
604+
605+
fprintf(OPF, "DROP ROLE %s;\n", fmtId(rolename));
606+
}
607+
608+
PQclear(res);
609+
610+
fprintf(OPF, "\n\n");
611+
}
544612

545613
/*
546614
* Dump roles
@@ -637,14 +705,12 @@ dumpRoles(PGconn *conn)
637705

638706
resetPQExpBuffer(buf);
639707

640-
if (output_clean)
641-
appendPQExpBuffer(buf, "DROP ROLE %s;\n", fmtId(rolename));
642-
643708
/*
644709
* We dump CREATE ROLE followed by ALTER ROLE to ensure that the role
645-
* will acquire the right properties even if it already exists. (The
646-
* above DROP may therefore seem redundant, but it isn't really,
647-
* because this technique doesn't get rid of role memberships.)
710+
* will acquire the right properties even if it already exists (ie,
711+
* it won't hurt for the CREATE to fail). This is particularly
712+
* important for the role we are connected as, since even with --clean
713+
* we will have failed to drop it.
648714
*/
649715
appendPQExpBuffer(buf, "CREATE ROLE %s;\n", fmtId(rolename));
650716
appendPQExpBuffer(buf, "ALTER ROLE %s WITH", fmtId(rolename));
@@ -834,6 +900,40 @@ dumpGroups(PGconn *conn)
834900
fprintf(OPF, "\n\n");
835901
}
836902

903+
904+
/*
905+
* Drop tablespaces.
906+
*/
907+
static void
908+
dropTablespaces(PGconn *conn)
909+
{
910+
PGresult *res;
911+
int i;
912+
913+
/*
914+
* Get all tablespaces except built-in ones (which we assume are named
915+
* pg_xxx)
916+
*/
917+
res = executeQuery(conn, "SELECT spcname "
918+
"FROM pg_catalog.pg_tablespace "
919+
"WHERE spcname !~ '^pg_' "
920+
"ORDER BY 1");
921+
922+
if (PQntuples(res) > 0)
923+
fprintf(OPF, "--\n-- Drop tablespaces\n--\n\n");
924+
925+
for (i = 0; i < PQntuples(res); i++)
926+
{
927+
char *spcname = PQgetvalue(res, i, 0);
928+
929+
fprintf(OPF, "DROP TABLESPACE %s;\n", fmtId(spcname));
930+
}
931+
932+
PQclear(res);
933+
934+
fprintf(OPF, "\n\n");
935+
}
936+
837937
/*
838938
* Dump tablespaces.
839939
*/
@@ -880,9 +980,6 @@ dumpTablespaces(PGconn *conn)
880980
/* needed for buildACLCommands() */
881981
fspcname = strdup(fmtId(spcname));
882982

883-
if (output_clean)
884-
appendPQExpBuffer(buf, "DROP TABLESPACE %s;\n", fspcname);
885-
886983
appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
887984
appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
888985

@@ -917,6 +1014,53 @@ dumpTablespaces(PGconn *conn)
9171014
fprintf(OPF, "\n\n");
9181015
}
9191016

1017+
1018+
/*
1019+
* Dump commands to drop each database.
1020+
*
1021+
* This should match the set of databases targeted by dumpCreateDB().
1022+
*/
1023+
static void
1024+
dropDBs(PGconn *conn)
1025+
{
1026+
PGresult *res;
1027+
int i;
1028+
1029+
if (server_version >= 70100)
1030+
res = executeQuery(conn,
1031+
"SELECT datname "
1032+
"FROM pg_database d "
1033+
"WHERE datallowconn ORDER BY 1");
1034+
else
1035+
res = executeQuery(conn,
1036+
"SELECT datname "
1037+
"FROM pg_database d "
1038+
"ORDER BY 1");
1039+
1040+
if (PQntuples(res) > 0)
1041+
fprintf(OPF, "--\n-- Drop databases\n--\n\n");
1042+
1043+
for (i = 0; i < PQntuples(res); i++)
1044+
{
1045+
char *dbname = PQgetvalue(res, i, 0);
1046+
1047+
/*
1048+
* Skip "template1" and "postgres"; the restore script is almost
1049+
* certainly going to be run in one or the other, and we don't know
1050+
* which. This must agree with dumpCreateDB's choices!
1051+
*/
1052+
if (strcmp(dbname, "template1") != 0 &&
1053+
strcmp(dbname, "postgres") != 0)
1054+
{
1055+
fprintf(OPF, "DROP DATABASE %s;\n", fmtId(dbname));
1056+
}
1057+
}
1058+
1059+
PQclear(res);
1060+
1061+
fprintf(OPF, "\n\n");
1062+
}
1063+
9201064
/*
9211065
* Dump commands to create each database.
9221066
*
@@ -984,7 +1128,7 @@ dumpCreateDB(PGconn *conn)
9841128
"(select usename from pg_shadow where usesysid=datdba), "
9851129
"(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
9861130
"pg_encoding_to_char(d.encoding), "
987-
"null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid"
1131+
"null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, "
9881132
"datistemplate, '' as datacl, -1 as datconnlimit, "
9891133
"'pg_default' AS dattablespace "
9901134
"FROM pg_database d "
@@ -999,7 +1143,7 @@ dumpCreateDB(PGconn *conn)
9991143
"SELECT datname, "
10001144
"(select usename from pg_shadow where usesysid=datdba), "
10011145
"pg_encoding_to_char(d.encoding), "
1002-
"null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid"
1146+
"null::text AS datcollate, null::text AS datctype, 0 AS datfrozenxid, "
10031147
"'f' as datistemplate, "
10041148
"'' as datacl, -1 as datconnlimit, "
10051149
"'pg_default' AS dattablespace "
@@ -1033,9 +1177,6 @@ dumpCreateDB(PGconn *conn)
10331177
if (strcmp(dbname, "template1") != 0 &&
10341178
strcmp(dbname, "postgres") != 0)
10351179
{
1036-
if (output_clean)
1037-
appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname);
1038-
10391180
appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
10401181

10411182
appendPQExpBuffer(buf, " WITH TEMPLATE = template0");
@@ -1120,7 +1261,6 @@ dumpCreateDB(PGconn *conn)
11201261
}
11211262

11221263

1123-
11241264
/*
11251265
* Dump database-specific configuration
11261266
*/

0 commit comments

Comments
 (0)