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
3434static void help (void );
3535
36+ static void dropRoles (PGconn * conn );
3637static void dumpRoles (PGconn * conn );
3738static void dumpRoleMembership (PGconn * conn );
3839static void dumpGroups (PGconn * conn );
40+ static void dropTablespaces (PGconn * conn );
3941static void dumpTablespaces (PGconn * conn );
42+ static void dropDBs (PGconn * conn );
4043static void dumpCreateDB (PGconn * conn );
4144static void dumpDatabaseConfig (PGconn * conn ,const char * dbname );
4245static void dumpUserConfig (PGconn * conn ,const char * username );
@@ -54,7 +57,6 @@ static void executeCommand(PGconn *conn, const char *query);
5457
5558static char pg_dump_bin [MAXPGPATH ];
5659static PQExpBuffer pgdumpopts ;
57- static bool output_clean = false;
5860static bool skip_acls = false;
5961static bool verbose = false;
6062
@@ -82,6 +84,7 @@ main(int argc, char *argv[])
8284enum trivalue prompt_password = TRI_DEFAULT ;
8385bool data_only = false;
8486bool globals_only = false;
87+ bool output_clean = false;
8588bool roles_only = false;
8689bool tablespaces_only = false;
8790bool schema_only = false;
@@ -90,8 +93,9 @@ main(int argc, char *argv[])
9093const char * std_strings ;
9194int c ,
9295ret ;
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-
135137set_pglocale_pgservice (argv [0 ],PG_TEXTDOMAIN ("pg_dump" ));
136138
137139progname = get_progname (argv [0 ]);
@@ -442,16 +444,41 @@ main(int argc, char *argv[])
442444
443445fprintf (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+
445455if (!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+ */
455482if (!tablespaces_only )
456483{
457484/* Dump roles (users) */
@@ -492,7 +519,6 @@ main(int argc, char *argv[])
492519}
493520
494521
495-
496522static void
497523help (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
638706resetPQExpBuffer (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 */
649715appendPQExpBuffer (buf ,"CREATE ROLE %s;\n" ,fmtId (rolename ));
650716appendPQExpBuffer (buf ,"ALTER ROLE %s WITH" ,fmtId (rolename ));
@@ -834,6 +900,40 @@ dumpGroups(PGconn *conn)
834900fprintf (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() */
881981fspcname = strdup (fmtId (spcname ));
882982
883- if (output_clean )
884- appendPQExpBuffer (buf ,"DROP TABLESPACE %s;\n" ,fspcname );
885-
886983appendPQExpBuffer (buf ,"CREATE TABLESPACE %s" ,fspcname );
887984appendPQExpBuffer (buf ," OWNER %s" ,fmtId (spcowner ));
888985
@@ -917,6 +1014,53 @@ dumpTablespaces(PGconn *conn)
9171014fprintf (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)
10331177if (strcmp (dbname ,"template1" )!= 0 &&
10341178strcmp (dbname ,"postgres" )!= 0 )
10351179{
1036- if (output_clean )
1037- appendPQExpBuffer (buf ,"DROP DATABASE %s;\n" ,fdbname );
1038-
10391180appendPQExpBuffer (buf ,"CREATE DATABASE %s" ,fdbname );
10401181
10411182appendPQExpBuffer (buf ," WITH TEMPLATE = template0" );
@@ -1120,7 +1261,6 @@ dumpCreateDB(PGconn *conn)
11201261}
11211262
11221263
1123-
11241264/*
11251265 * Dump database-specific configuration
11261266 */