Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * pg_dumpall.c
4 : : * pg_dumpall dumps all databases and global objects (roles and
5 : : * tablespaces) from a PostgreSQL cluster.
6 : : *
7 : : * For text format output, globals are written directly and pg_dump is
8 : : * invoked for each database, with all output going to stdout or a file.
9 : : *
10 : : * For non-text formats (custom, directory, tar), a directory is created
11 : : * containing a toc.glo file with global objects, a map.dat file mapping
12 : : * database OIDs to names, and a databases/ subdirectory with individual
13 : : * pg_dump archives for each database.
14 : : *
15 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
16 : : * Portions Copyright (c) 1994, Regents of the University of California
17 : : *
18 : : * src/bin/pg_dump/pg_dumpall.c
19 : : *
20 : : *-------------------------------------------------------------------------
21 : : */
22 : :
23 : : #include "postgres_fe.h"
24 : :
25 : : #include <time.h>
26 : : #include <unistd.h>
27 : :
28 : : #include "catalog/pg_authid_d.h"
29 : : #include "common/connect.h"
30 : : #include "common/file_perm.h"
31 : : #include "common/file_utils.h"
32 : : #include "common/hashfn_unstable.h"
33 : : #include "common/logging.h"
34 : : #include "common/string.h"
35 : : #include "connectdb.h"
36 : : #include "dumputils.h"
37 : : #include "fe_utils/option_utils.h"
38 : : #include "fe_utils/string_utils.h"
39 : : #include "filter.h"
40 : : #include "getopt_long.h"
41 : : #include "pg_backup_archiver.h"
42 : :
43 : : /* version string we expect back from pg_dump */
44 : : #define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
45 : :
46 : : typedef struct
47 : : {
48 : : uint32 status;
49 : : uint32 hashval;
50 : : char *rolename;
51 : : } RoleNameEntry;
52 : :
53 : : #define SH_PREFIX rolename
54 : : #define SH_ELEMENT_TYPE RoleNameEntry
55 : : #define SH_KEY_TYPE char *
56 : : #define SH_KEY rolename
57 : : #define SH_HASH_KEY(tb, key) hash_string(key)
58 : : #define SH_EQUAL(tb, a, b) (strcmp(a, b) == 0)
59 : : #define SH_STORE_HASH
60 : : #define SH_GET_HASH(tb, a) (a)->hashval
61 : : #define SH_SCOPE static inline
62 : : #define SH_RAW_ALLOCATOR pg_malloc0
63 : : #define SH_DECLARE
64 : : #define SH_DEFINE
65 : : #include "lib/simplehash.h"
66 : :
67 : : static void help(void);
68 : :
69 : : static void dropRoles(PGconn *conn);
70 : : static void dumpRoles(PGconn *conn);
71 : : static void dumpRoleMembership(PGconn *conn);
72 : : static void dumpRoleGUCPrivs(PGconn *conn);
73 : : static void dropTablespaces(PGconn *conn);
74 : : static void dumpTablespaces(PGconn *conn);
75 : : static void dropDBs(PGconn *conn);
76 : : static void dumpUserConfig(PGconn *conn, const char *username);
77 : : static void dumpDatabases(PGconn *conn);
78 : : static void dumpTimestamp(const char *msg);
79 : : static int runPgDump(const char *dbname, const char *create_opts, char *dbfile);
80 : : static void buildShSecLabels(PGconn *conn,
81 : : const char *catalog_name, Oid objectId,
82 : : const char *objtype, const char *objname,
83 : : PQExpBuffer buffer);
84 : : static void executeCommand(PGconn *conn, const char *query);
85 : : static void check_for_invalid_global_names(PGconn *conn,
86 : : SimpleStringList *database_exclude_names);
87 : : static void expand_dbname_patterns(PGconn *conn, SimpleStringList *patterns,
88 : : SimpleStringList *names);
89 : : static void read_dumpall_filters(const char *filename, SimpleStringList *pattern);
90 : : static ArchiveFormat parseDumpFormat(const char *format);
91 : : static int createDumpId(void);
92 : :
93 : : static char pg_dump_bin[MAXPGPATH];
94 : : static PQExpBuffer pgdumpopts;
95 : : static const char *connstr = "";
96 : : static bool output_clean = false;
97 : : static bool skip_acls = false;
98 : : static bool verbose = false;
99 : : static bool dosync = true;
100 : :
101 : : static int binary_upgrade = 0;
102 : : static int column_inserts = 0;
103 : : static int disable_dollar_quoting = 0;
104 : : static int disable_triggers = 0;
105 : : static int if_exists = 0;
106 : : static int inserts = 0;
107 : : static int no_table_access_method = 0;
108 : : static int no_tablespaces = 0;
109 : : static int use_setsessauth = 0;
110 : : static int no_comments = 0;
111 : : static int no_policies = 0;
112 : : static int no_publications = 0;
113 : : static int no_security_labels = 0;
114 : : static int no_data = 0;
115 : : static int no_schema = 0;
116 : : static int no_statistics = 0;
117 : : static int no_subscriptions = 0;
118 : : static int no_toast_compression = 0;
119 : : static int no_unlogged_table_data = 0;
120 : : static int no_role_passwords = 0;
121 : : static int with_statistics = 0;
122 : : static int server_version;
123 : : static int load_via_partition_root = 0;
124 : : static int on_conflict_do_nothing = 0;
125 : : static int statistics_only = 0;
126 : : static int sequence_data = 0;
127 : :
128 : : static char role_catalog[10];
129 : : #define PG_AUTHID "pg_authid"
130 : : #define PG_ROLES "pg_roles "
131 : :
132 : : static FILE *OPF;
133 : : static char *filename = NULL;
134 : :
135 : : static SimpleStringList database_exclude_patterns = {NULL, NULL};
136 : : static SimpleStringList database_exclude_names = {NULL, NULL};
137 : :
138 : : static char *restrict_key;
139 : : static Archive *fout = NULL;
140 : : static int dumpIdVal = 0;
141 : : static ArchiveFormat archDumpFormat = archNull;
142 : : static const CatalogId nilCatalogId = {0, 0};
143 : :
144 : : int
8601 peter_e@gmx.net 145 :CBC 82 : main(int argc, char *argv[])
146 : : {
147 : : static struct option long_options[] = {
148 : : {"data-only", no_argument, NULL, 'a'},
149 : : {"clean", no_argument, NULL, 'c'},
150 : : {"encoding", required_argument, NULL, 'E'},
151 : : {"file", required_argument, NULL, 'f'},
152 : : {"globals-only", no_argument, NULL, 'g'},
153 : : {"host", required_argument, NULL, 'h'},
154 : : {"dbname", required_argument, NULL, 'd'},
155 : : {"database", required_argument, NULL, 'l'},
156 : : {"no-owner", no_argument, NULL, 'O'},
157 : : {"port", required_argument, NULL, 'p'},
158 : : {"roles-only", no_argument, NULL, 'r'},
159 : : {"schema-only", no_argument, NULL, 's'},
160 : : {"superuser", required_argument, NULL, 'S'},
161 : : {"tablespaces-only", no_argument, NULL, 't'},
162 : : {"username", required_argument, NULL, 'U'},
163 : : {"verbose", no_argument, NULL, 'v'},
164 : : {"no-password", no_argument, NULL, 'w'},
165 : : {"password", no_argument, NULL, 'W'},
166 : : {"no-privileges", no_argument, NULL, 'x'},
167 : : {"no-acl", no_argument, NULL, 'x'},
168 : : {"format", required_argument, NULL, 'F'},
169 : :
170 : : /*
171 : : * the following options don't have an equivalent short option letter
172 : : */
173 : : {"attribute-inserts", no_argument, &column_inserts, 1},
174 : : {"binary-upgrade", no_argument, &binary_upgrade, 1},
175 : : {"column-inserts", no_argument, &column_inserts, 1},
176 : : {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
177 : : {"disable-triggers", no_argument, &disable_triggers, 1},
178 : : {"exclude-database", required_argument, NULL, 6},
179 : : {"extra-float-digits", required_argument, NULL, 5},
180 : : {"if-exists", no_argument, &if_exists, 1},
181 : : {"inserts", no_argument, &inserts, 1},
182 : : {"lock-wait-timeout", required_argument, NULL, 2},
183 : : {"no-table-access-method", no_argument, &no_table_access_method, 1},
184 : : {"no-tablespaces", no_argument, &no_tablespaces, 1},
185 : : {"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
186 : : {"load-via-partition-root", no_argument, &load_via_partition_root, 1},
187 : : {"role", required_argument, NULL, 3},
188 : : {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
189 : : {"no-comments", no_argument, &no_comments, 1},
190 : : {"no-data", no_argument, &no_data, 1},
191 : : {"no-policies", no_argument, &no_policies, 1},
192 : : {"no-publications", no_argument, &no_publications, 1},
193 : : {"no-role-passwords", no_argument, &no_role_passwords, 1},
194 : : {"no-schema", no_argument, &no_schema, 1},
195 : : {"no-security-labels", no_argument, &no_security_labels, 1},
196 : : {"no-subscriptions", no_argument, &no_subscriptions, 1},
197 : : {"no-statistics", no_argument, &no_statistics, 1},
198 : : {"no-sync", no_argument, NULL, 4},
199 : : {"no-toast-compression", no_argument, &no_toast_compression, 1},
200 : : {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
201 : : {"on-conflict-do-nothing", no_argument, &on_conflict_do_nothing, 1},
202 : : {"rows-per-insert", required_argument, NULL, 7},
203 : : {"statistics", no_argument, &with_statistics, 1},
204 : : {"statistics-only", no_argument, &statistics_only, 1},
205 : : {"filter", required_argument, NULL, 8},
206 : : {"sequence-data", no_argument, &sequence_data, 1},
207 : : {"restrict-key", required_argument, NULL, 9},
208 : :
209 : : {NULL, 0, NULL, 0}
210 : : };
211 : :
4853 bruce@momjian.us 212 : 82 : char *pghost = NULL;
213 : 82 : char *pgport = NULL;
214 : 82 : char *pguser = NULL;
215 : 82 : char *pgdb = NULL;
216 : 82 : char *use_role = NULL;
3117 rhaas@postgresql.org 217 : 82 : const char *dumpencoding = NULL;
20 andrew@dunslane.net 218 :GNC 82 : const char *format_name = "p";
4170 alvherre@alvh.no-ip. 219 :CBC 82 : trivalue prompt_password = TRI_DEFAULT;
4853 bruce@momjian.us 220 : 82 : bool data_only = false;
221 : 82 : bool globals_only = false;
222 : 82 : bool roles_only = false;
9 nathan@postgresql.or 223 :GNC 82 : bool schema_only = false;
4853 bruce@momjian.us 224 :CBC 82 : bool tablespaces_only = false;
225 : : PGconn *conn;
226 : : int encoding;
227 : : int c,
228 : : ret;
229 : : int optindex;
230 : : DumpOptions dopt;
231 : :
2540 peter@eisentraut.org 232 : 82 : pg_logging_init(argv[0]);
233 : 82 : pg_logging_set_level(PG_LOG_WARNING);
6303 peter_e@gmx.net 234 : 82 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
8381 bruce@momjian.us 235 : 82 : progname = get_progname(argv[0]);
236 : :
8601 peter_e@gmx.net 237 [ + - ]: 82 : if (argc > 1)
238 : : {
239 [ + + - + ]: 82 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
240 : : {
241 : 1 : help();
5141 rhaas@postgresql.org 242 : 1 : exit_nicely(0);
243 : : }
8601 peter_e@gmx.net 244 [ + + + + ]: 81 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
245 : : {
246 : 19 : puts("pg_dumpall (PostgreSQL) " PG_VERSION);
5141 rhaas@postgresql.org 247 : 19 : exit_nicely(0);
248 : : }
249 : : }
250 : :
7237 peter_e@gmx.net 251 [ - + ]: 62 : if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR,
252 : : pg_dump_bin)) < 0)
253 : : {
254 : : char full_path[MAXPGPATH];
255 : :
7821 bruce@momjian.us 256 [ # # ]:UBC 0 : if (find_my_exec(argv[0], full_path) < 0)
6973 peter_e@gmx.net 257 : 0 : strlcpy(full_path, progname, sizeof(full_path));
258 : :
7978 bruce@momjian.us 259 [ # # ]: 0 : if (ret == -1)
1437 tgl@sss.pgh.pa.us 260 : 0 : pg_fatal("program \"%s\" is needed by %s but was not found in the same directory as \"%s\"",
261 : : "pg_dump", progname, full_path);
262 : : else
263 : 0 : pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s",
264 : : "pg_dump", full_path, progname);
265 : : }
266 : :
8601 peter_e@gmx.net 267 :CBC 62 : pgdumpopts = createPQExpBuffer();
20 andrew@dunslane.net 268 :GNC 62 : InitDumpOptions(&dopt);
269 : :
270 [ + + ]: 292 : while ((c = getopt_long(argc, argv, "acd:E:f:F:gh:l:Op:rsS:tU:vwWx", long_options, &optindex)) != -1)
271 : : {
8601 peter_e@gmx.net 272 [ + + + - :CBC 234 : switch (c)
+ + + + -
- + + + -
+ + + - -
- + - - +
- + - + +
+ ]
273 : : {
8325 tgl@sss.pgh.pa.us 274 :GBC 1 : case 'a':
275 : 1 : data_only = true;
4500 heikki.linnakangas@i 276 : 1 : appendPQExpBufferStr(pgdumpopts, " -a");
8325 tgl@sss.pgh.pa.us 277 : 1 : break;
278 : :
8601 peter_e@gmx.net 279 :CBC 2 : case 'c':
280 : 2 : output_clean = true;
281 : 2 : break;
282 : :
4766 heikki.linnakangas@i 283 : 9 : case 'd':
284 : 9 : connstr = pg_strdup(optarg);
285 : 9 : break;
286 : :
3117 rhaas@postgresql.org 287 :UBC 0 : case 'E':
288 : 0 : dumpencoding = pg_strdup(optarg);
289 : 0 : appendPQExpBufferStr(pgdumpopts, " -E ");
290 : 0 : appendShellString(pgdumpopts, optarg);
291 : 0 : break;
292 : :
6989 bruce@momjian.us 293 :CBC 45 : case 'f':
4902 294 : 45 : filename = pg_strdup(optarg);
4500 heikki.linnakangas@i 295 : 45 : appendPQExpBufferStr(pgdumpopts, " -f ");
3506 noah@leadboat.com 296 : 45 : appendShellString(pgdumpopts, filename);
6989 bruce@momjian.us 297 : 45 : break;
20 andrew@dunslane.net 298 :GNC 14 : case 'F':
299 : 14 : format_name = pg_strdup(optarg);
300 : 14 : break;
8601 peter_e@gmx.net 301 :CBC 20 : case 'g':
302 : 20 : globals_only = true;
303 : 20 : break;
304 : :
305 : 11 : case 'h':
4902 bruce@momjian.us 306 : 11 : pghost = pg_strdup(optarg);
8601 peter_e@gmx.net 307 : 11 : break;
308 : :
6989 bruce@momjian.us 309 :UBC 0 : case 'l':
4902 310 : 0 : pgdb = pg_strdup(optarg);
6989 311 : 0 : break;
312 : :
7916 313 : 0 : case 'O':
4500 heikki.linnakangas@i 314 : 0 : appendPQExpBufferStr(pgdumpopts, " -O");
7916 bruce@momjian.us 315 : 0 : break;
316 : :
8601 peter_e@gmx.net 317 :CBC 19 : case 'p':
4902 bruce@momjian.us 318 : 19 : pgport = pg_strdup(optarg);
8601 peter_e@gmx.net 319 : 19 : break;
320 : :
6989 bruce@momjian.us 321 : 7 : case 'r':
322 : 7 : roles_only = true;
323 : 7 : break;
324 : :
8325 tgl@sss.pgh.pa.us 325 :GBC 1 : case 's':
9 nathan@postgresql.or 326 :GNC 1 : schema_only = true;
4500 heikki.linnakangas@i 327 :GBC 1 : appendPQExpBufferStr(pgdumpopts, " -s");
8325 tgl@sss.pgh.pa.us 328 : 1 : break;
329 : :
7916 bruce@momjian.us 330 :UBC 0 : case 'S':
4500 heikki.linnakangas@i 331 : 0 : appendPQExpBufferStr(pgdumpopts, " -S ");
3506 noah@leadboat.com 332 : 0 : appendShellString(pgdumpopts, optarg);
7916 bruce@momjian.us 333 : 0 : break;
334 : :
6989 bruce@momjian.us 335 :CBC 3 : case 't':
336 : 3 : tablespaces_only = true;
337 : 3 : break;
338 : :
8601 peter_e@gmx.net 339 : 17 : case 'U':
4902 bruce@momjian.us 340 : 17 : pguser = pg_strdup(optarg);
20 andrew@dunslane.net 341 :GNC 17 : dopt.cparams.username = pg_strdup(optarg);
8601 peter_e@gmx.net 342 :CBC 17 : break;
343 : :
344 : 2 : case 'v':
345 : 2 : verbose = true;
2005 tgl@sss.pgh.pa.us 346 : 2 : pg_logging_increase_verbosity();
4500 heikki.linnakangas@i 347 : 2 : appendPQExpBufferStr(pgdumpopts, " -v");
8601 peter_e@gmx.net 348 : 2 : break;
349 : :
6226 peter_e@gmx.net 350 :UBC 0 : case 'w':
351 : 0 : prompt_password = TRI_NO;
4500 heikki.linnakangas@i 352 : 0 : appendPQExpBufferStr(pgdumpopts, " -w");
6226 peter_e@gmx.net 353 : 0 : break;
354 : :
8601 355 : 0 : case 'W':
6226 356 : 0 : prompt_password = TRI_YES;
4500 heikki.linnakangas@i 357 : 0 : appendPQExpBufferStr(pgdumpopts, " -W");
8601 peter_e@gmx.net 358 : 0 : break;
359 : :
8325 tgl@sss.pgh.pa.us 360 : 0 : case 'x':
361 : 0 : skip_acls = true;
4500 heikki.linnakangas@i 362 : 0 : appendPQExpBufferStr(pgdumpopts, " -x");
8325 tgl@sss.pgh.pa.us 363 : 0 : break;
364 : :
7916 bruce@momjian.us 365 :CBC 37 : case 0:
366 : 37 : break;
367 : :
6407 alvherre@alvh.no-ip. 368 :UBC 0 : case 2:
4500 heikki.linnakangas@i 369 : 0 : appendPQExpBufferStr(pgdumpopts, " --lock-wait-timeout ");
3506 noah@leadboat.com 370 : 0 : appendShellString(pgdumpopts, optarg);
6278 tgl@sss.pgh.pa.us 371 : 0 : break;
372 : :
373 : 0 : case 3:
4902 bruce@momjian.us 374 : 0 : use_role = pg_strdup(optarg);
4500 heikki.linnakangas@i 375 : 0 : appendPQExpBufferStr(pgdumpopts, " --role ");
3506 noah@leadboat.com 376 : 0 : appendShellString(pgdumpopts, use_role);
6407 alvherre@alvh.no-ip. 377 : 0 : break;
378 : :
3280 andrew@dunslane.net 379 :CBC 27 : case 4:
380 : 27 : dosync = false;
381 : 27 : appendPQExpBufferStr(pgdumpopts, " --no-sync");
382 : 27 : break;
383 : :
2582 andrew@dunslane.net 384 :UBC 0 : case 5:
385 : 0 : appendPQExpBufferStr(pgdumpopts, " --extra-float-digits ");
386 : 0 : appendShellString(pgdumpopts, optarg);
387 : 0 : break;
388 : :
2571 andrew@dunslane.net 389 :CBC 6 : case 6:
390 : 6 : simple_string_list_append(&database_exclude_patterns, optarg);
391 : 6 : break;
392 : :
2466 alvherre@alvh.no-ip. 393 :UBC 0 : case 7:
394 : 0 : appendPQExpBufferStr(pgdumpopts, " --rows-per-insert ");
395 : 0 : appendShellString(pgdumpopts, optarg);
396 : 0 : break;
397 : :
837 dgustafsson@postgres 398 :CBC 5 : case 8:
399 : 5 : read_dumpall_filters(optarg, &database_exclude_patterns);
400 : 2 : break;
401 : :
216 nathan@postgresql.or 402 : 7 : case 9:
403 : 7 : restrict_key = pg_strdup(optarg);
404 : 7 : appendPQExpBufferStr(pgdumpopts, " --restrict-key ");
405 : 7 : appendShellString(pgdumpopts, optarg);
406 : 7 : break;
407 : :
8593 bruce@momjian.us 408 : 1 : default:
409 : : /* getopt_long already emitted a complaint */
1437 tgl@sss.pgh.pa.us 410 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
5141 rhaas@postgresql.org 411 : 1 : exit_nicely(1);
412 : : }
413 : : }
414 : :
415 : : /* Complain if any arguments remain */
8593 bruce@momjian.us 416 [ + + ]: 58 : if (optind < argc)
417 : : {
2540 peter@eisentraut.org 418 : 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
419 : : argv[optind]);
1437 tgl@sss.pgh.pa.us 420 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
5141 rhaas@postgresql.org 421 : 1 : exit_nicely(1);
422 : : }
423 : :
424 : : /* --exclude-database is incompatible with global *-only options */
9 nathan@postgresql.or 425 :GNC 57 : check_mut_excl_opts(database_exclude_patterns.head, "--exclude-database",
426 : : globals_only, "-g/--globals-only",
427 : : roles_only, "-r/--roles-only",
428 : : tablespaces_only, "-t/--tablespaces-only");
429 : :
430 : : /* *-only options are incompatible with each other */
431 : 52 : check_mut_excl_opts(data_only, "-a/--data-only",
432 : : globals_only, "-g/--globals-only",
433 : : roles_only, "-r/--roles-only",
434 : : schema_only, "-s/--schema-only",
435 : : statistics_only, "--statistics-only",
436 : : tablespaces_only, "-t/--tablespaces-only");
437 : :
438 : : /* --no-* and *-only for same thing are incompatible */
439 : 52 : check_mut_excl_opts(data_only, "-a/--data-only",
440 : : no_data, "--no-data");
441 : 51 : check_mut_excl_opts(schema_only, "-s/--schema-only",
442 : : no_schema, "--no-schema");
443 : 50 : check_mut_excl_opts(statistics_only, "--statistics-only",
444 : : no_statistics, "--no-statistics");
445 : :
446 : : /* --statistics and --no-statistics are incompatible */
447 : 49 : check_mut_excl_opts(with_statistics, "--statistics",
448 : : no_statistics, "--no-statistics");
449 : :
450 : : /* --statistics is incompatible with *-only (except --statistics-only) */
451 : 48 : check_mut_excl_opts(with_statistics, "--statistics",
452 : : data_only, "-a/--data-only",
453 : : globals_only, "-g/--globals-only",
454 : : roles_only, "-r/--roles-only",
455 : : schema_only, "-s/--schema-only",
456 : : tablespaces_only, "-t/--tablespaces-only");
457 : :
4395 alvherre@alvh.no-ip. 458 [ + + + - ]:CBC 47 : if (if_exists && !output_clean)
97 alvherre@kurilemu.de 459 : 1 : pg_fatal("option %s requires option %s",
460 : : "--if-exists", "-c/--clean");
461 : :
462 : : /* Get format for dump. */
20 andrew@dunslane.net 463 :GNC 46 : archDumpFormat = parseDumpFormat(format_name);
464 : :
465 : : /*
466 : : * If a non-plain format is specified, a file name is also required as the
467 : : * path to the main directory.
468 : : */
469 [ + + ]: 45 : if (archDumpFormat != archNull &&
470 [ + + - + ]: 13 : (!filename || strcmp(filename, "") == 0))
471 : : {
472 : 1 : pg_log_error("option %s=d|c|t requires option %s",
473 : : "-F/--format", "-f/--file");
20 andrew@dunslane.net 474 :CBC 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
475 : 1 : exit_nicely(1);
476 : : }
477 : :
478 : : /* restrict-key is only supported with --format=plain */
20 andrew@dunslane.net 479 [ + + + + ]:GNC 44 : if (archDumpFormat != archNull && restrict_key)
480 : 1 : pg_fatal("option %s can only be used with %s=plain",
481 : : "--restrict-key", "--format");
482 : :
483 : : /* --clean and -g/--globals-only cannot be used together in non-text dump */
484 [ + + + + : 43 : if (archDumpFormat != archNull && output_clean && globals_only)
+ - ]
485 : 1 : pg_fatal("options %s and %s cannot be used together in non-text dump",
486 : : "--clean", "-g/--globals-only");
487 : :
488 : : /*
489 : : * If password values are not required in the dump, switch to using
490 : : * pg_roles which is equally useful, just more likely to have unrestricted
491 : : * access than pg_authid.
492 : : */
3295 simon@2ndQuadrant.co 493 [ - + ]:CBC 42 : if (no_role_passwords)
3295 simon@2ndQuadrant.co 494 :UBC 0 : sprintf(role_catalog, "%s", PG_ROLES);
495 : : else
3295 simon@2ndQuadrant.co 496 :CBC 42 : sprintf(role_catalog, "%s", PG_AUTHID);
497 : :
498 : : /* Add long options to the pg_dump argument list */
5693 tgl@sss.pgh.pa.us 499 [ + + ]: 42 : if (binary_upgrade)
4500 heikki.linnakangas@i 500 : 11 : appendPQExpBufferStr(pgdumpopts, " --binary-upgrade");
5693 tgl@sss.pgh.pa.us 501 [ - + ]: 42 : if (column_inserts)
4500 heikki.linnakangas@i 502 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --column-inserts");
5693 tgl@sss.pgh.pa.us 503 [ - + ]:CBC 42 : if (disable_dollar_quoting)
4500 heikki.linnakangas@i 504 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --disable-dollar-quoting");
5693 tgl@sss.pgh.pa.us 505 [ - + ]:CBC 42 : if (disable_triggers)
4500 heikki.linnakangas@i 506 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --disable-triggers");
5693 tgl@sss.pgh.pa.us 507 [ - + ]:CBC 42 : if (inserts)
4500 heikki.linnakangas@i 508 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --inserts");
1518 michael@paquier.xyz 509 [ - + ]:CBC 42 : if (no_table_access_method)
1518 michael@paquier.xyz 510 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --no-table-access-method");
5693 tgl@sss.pgh.pa.us 511 [ - + ]:CBC 42 : if (no_tablespaces)
4500 heikki.linnakangas@i 512 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --no-tablespaces");
5693 tgl@sss.pgh.pa.us 513 [ + + ]:CBC 42 : if (quote_all_identifiers)
4500 heikki.linnakangas@i 514 : 11 : appendPQExpBufferStr(pgdumpopts, " --quote-all-identifiers");
3135 rhaas@postgresql.org 515 [ - + ]: 42 : if (load_via_partition_root)
3135 rhaas@postgresql.org 516 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --load-via-partition-root");
5693 tgl@sss.pgh.pa.us 517 [ - + ]:CBC 42 : if (use_setsessauth)
4500 heikki.linnakangas@i 518 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --use-set-session-authorization");
2971 tgl@sss.pgh.pa.us 519 [ - + ]:CBC 42 : if (no_comments)
2971 tgl@sss.pgh.pa.us 520 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --no-comments");
388 jdavis@postgresql.or 521 [ - + ]:CBC 42 : if (no_data)
388 jdavis@postgresql.or 522 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --no-data");
364 tgl@sss.pgh.pa.us 523 [ - + ]:CBC 42 : if (no_policies)
364 tgl@sss.pgh.pa.us 524 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --no-policies");
3229 peter_e@gmx.net 525 [ - + ]:CBC 42 : if (no_publications)
3229 peter_e@gmx.net 526 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --no-publications");
5414 peter_e@gmx.net 527 [ - + ]:CBC 42 : if (no_security_labels)
4500 heikki.linnakangas@i 528 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --no-security-labels");
388 jdavis@postgresql.or 529 [ - + ]:CBC 42 : if (no_schema)
388 jdavis@postgresql.or 530 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --no-schema");
388 jdavis@postgresql.or 531 [ + + ]:CBC 42 : if (no_statistics)
532 : 2 : appendPQExpBufferStr(pgdumpopts, " --no-statistics");
3232 peter_e@gmx.net 533 [ - + ]: 42 : if (no_subscriptions)
3232 peter_e@gmx.net 534 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --no-subscriptions");
1761 michael@paquier.xyz 535 [ - + ]:CBC 42 : if (no_toast_compression)
1761 michael@paquier.xyz 536 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --no-toast-compression");
5555 rhaas@postgresql.org 537 [ + + ]:CBC 42 : if (no_unlogged_table_data)
4500 heikki.linnakangas@i 538 : 3 : appendPQExpBufferStr(pgdumpopts, " --no-unlogged-table-data");
355 jdavis@postgresql.or 539 [ + + ]: 42 : if (with_statistics)
225 540 : 2 : appendPQExpBufferStr(pgdumpopts, " --statistics");
2802 tmunro@postgresql.or 541 [ - + ]: 42 : if (on_conflict_do_nothing)
2802 tmunro@postgresql.or 542 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --on-conflict-do-nothing");
388 jdavis@postgresql.or 543 [ - + ]:CBC 42 : if (statistics_only)
388 jdavis@postgresql.or 544 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --statistics-only");
312 nathan@postgresql.or 545 [ - + ]:CBC 42 : if (sequence_data)
312 nathan@postgresql.or 546 :UBC 0 : appendPQExpBufferStr(pgdumpopts, " --sequence-data");
547 : :
548 : : /*
549 : : * Open the output file if required, otherwise use stdout. If required,
550 : : * then create new directory.
551 : : */
20 andrew@dunslane.net 552 [ + + ]:GNC 42 : if (archDumpFormat != archNull)
553 : : {
554 [ - + ]: 10 : Assert(filename);
555 : :
556 : : /* Create new directory or accept the empty existing directory. */
557 : 10 : create_or_open_dir(filename);
558 : : }
559 [ + + ]: 32 : else if (filename)
560 : : {
561 : 29 : OPF = fopen(filename, PG_BINARY_W);
562 [ - + ]: 29 : if (!OPF)
20 andrew@dunslane.net 563 :UNC 0 : pg_fatal("could not open output file \"%s\": %m",
564 : : filename);
565 : : }
566 : : else
20 andrew@dunslane.net 567 :GNC 3 : OPF = stdout;
568 : :
569 : : /*
570 : : * If you don't provide a restrict key, one will be appointed for you.
571 : : */
216 nathan@postgresql.or 572 [ + + ]:CBC 42 : if (!restrict_key)
573 : 36 : restrict_key = generate_restrict_key();
574 [ - + ]: 42 : if (!restrict_key)
216 nathan@postgresql.or 575 :UBC 0 : pg_fatal("could not generate restrict key");
216 nathan@postgresql.or 576 [ - + ]:CBC 42 : if (!valid_restrict_key(restrict_key))
216 nathan@postgresql.or 577 :UBC 0 : pg_fatal("invalid restrict key");
578 : :
579 : : /*
580 : : * If there was a database specified on the command line, use that,
581 : : * otherwise try to connect to database "postgres", and failing that
582 : : * "template1".
583 : : */
6989 bruce@momjian.us 584 [ - + ]:CBC 42 : if (pgdb)
585 : : {
345 andrew@dunslane.net 586 :UBC 0 : conn = ConnectDatabase(pgdb, connstr, pghost, pgport, pguser,
587 : : prompt_password, false,
588 : : progname, &connstr, &server_version, NULL, NULL);
589 : :
6989 bruce@momjian.us 590 [ # # ]: 0 : if (!conn)
1437 tgl@sss.pgh.pa.us 591 : 0 : pg_fatal("could not connect to database \"%s\"", pgdb);
592 : : }
593 : : else
594 : : {
345 andrew@dunslane.net 595 :CBC 42 : conn = ConnectDatabase("postgres", connstr, pghost, pgport, pguser,
596 : : prompt_password, false,
597 : : progname, &connstr, &server_version, NULL, NULL);
6989 bruce@momjian.us 598 [ - + ]: 42 : if (!conn)
345 andrew@dunslane.net 599 :UBC 0 : conn = ConnectDatabase("template1", connstr, pghost, pgport, pguser,
600 : : prompt_password, true,
601 : : progname, &connstr, &server_version, NULL, NULL);
602 : :
6989 bruce@momjian.us 603 [ - + ]:CBC 42 : if (!conn)
604 : : {
2540 peter@eisentraut.org 605 :UBC 0 : pg_log_error("could not connect to databases \"postgres\" or \"template1\"\n"
606 : : "Please specify an alternative database.");
1437 tgl@sss.pgh.pa.us 607 : 0 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
5141 rhaas@postgresql.org 608 : 0 : exit_nicely(1);
609 : : }
610 : : }
611 : :
612 : : /*
613 : : * Get a list of database names that match the exclude patterns
614 : : */
2571 andrew@dunslane.net 615 :CBC 42 : expand_dbname_patterns(conn, &database_exclude_patterns,
616 : : &database_exclude_names);
617 : :
618 : : /*
619 : : * Set the client encoding if requested.
620 : : */
3117 rhaas@postgresql.org 621 [ - + ]: 40 : if (dumpencoding)
622 : : {
3117 rhaas@postgresql.org 623 [ # # ]:UBC 0 : if (PQsetClientEncoding(conn, dumpencoding) < 0)
1437 tgl@sss.pgh.pa.us 624 : 0 : pg_fatal("invalid client encoding \"%s\" specified",
625 : : dumpencoding);
626 : : }
627 : :
628 : : /*
629 : : * Force standard_conforming_strings on, just in case we are dumping from
630 : : * an old server that has it disabled. Without this, literals in views,
631 : : * expressions, etc, would be incorrect for modern servers.
632 : : */
53 tgl@sss.pgh.pa.us 633 :GNC 40 : executeCommand(conn, "SET standard_conforming_strings = on");
634 : :
635 : : /*
636 : : * Get the active encoding, so we know how to escape strings.
637 : : */
7231 tgl@sss.pgh.pa.us 638 :CBC 40 : encoding = PQclientEncoding(conn);
398 andres@anarazel.de 639 : 40 : setFmtEncoding(encoding);
640 : :
641 : : /* Set the role if requested */
1552 tgl@sss.pgh.pa.us 642 [ - + ]: 40 : if (use_role)
643 : : {
6278 tgl@sss.pgh.pa.us 644 :UBC 0 : PQExpBuffer query = createPQExpBuffer();
645 : :
646 : 0 : appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
647 : 0 : executeCommand(conn, query->data);
648 : 0 : destroyPQExpBuffer(query);
649 : : }
650 : :
651 : : /* Force quoting of all identifiers if requested. */
1552 tgl@sss.pgh.pa.us 652 [ + + ]:CBC 40 : if (quote_all_identifiers)
5715 rhaas@postgresql.org 653 : 11 : executeCommand(conn, "SET quote_all_identifiers = true");
654 : :
655 : : /* create a archive file for global commands. */
20 andrew@dunslane.net 656 [ + + ]:GNC 40 : if (archDumpFormat != archNull)
657 : : {
658 : 10 : PQExpBuffer qry = createPQExpBuffer();
659 : : char global_path[MAXPGPATH];
660 : : const char *encname;
661 : 10 : pg_compress_specification compression_spec = {0};
662 : :
663 : : /*
664 : : * Check that no global object names contain newlines or carriage
665 : : * returns, which would break the map.dat file format. This is only
666 : : * needed for servers older than v19, which started prohibiting such
667 : : * names.
668 : : */
669 [ - + ]: 10 : if (server_version < 190000)
20 andrew@dunslane.net 670 :UNC 0 : check_for_invalid_global_names(conn, &database_exclude_names);
671 : :
672 : : /* Set file path for global sql commands. */
20 andrew@dunslane.net 673 :GNC 10 : snprintf(global_path, MAXPGPATH, "%s/toc.glo", filename);
674 : :
675 : : /* Open the output file */
676 : 10 : fout = CreateArchive(global_path, archCustom, compression_spec,
677 : : dosync, archModeWrite, NULL, DATA_DIR_SYNC_METHOD_FSYNC);
678 : :
679 : : /* Make dump options accessible right away */
680 : 10 : SetArchiveOptions(fout, &dopt, NULL);
681 : :
682 : 10 : ((ArchiveHandle *) fout)->connection = conn;
683 : 10 : ((ArchiveHandle *) fout)->public.numWorkers = 1;
684 : :
685 : : /* Register the cleanup hook */
686 : 10 : on_exit_close_archive(fout);
687 : :
688 : : /* Let the archiver know how noisy to be */
689 : 10 : fout->verbose = verbose;
690 : :
691 : : /*
692 : : * We allow the server to be back to 9.2, and up to any minor release
693 : : * of our own major version. (See also version check in
694 : : * pg_dumpall.c.)
695 : : */
696 : 10 : fout->minRemoteVersion = 90200;
697 : 10 : fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
698 : 10 : fout->numWorkers = 1;
699 : :
700 : : /* Dump default_transaction_read_only. */
701 : 10 : appendPQExpBufferStr(qry, "SET default_transaction_read_only = off;\n\n");
702 : 10 : ArchiveEntry(fout,
703 : : nilCatalogId, /* catalog ID */
704 : : createDumpId(), /* dump ID */
705 : 10 : ARCHIVE_OPTS(.tag = "default_transaction_read_only",
706 : : .description = "default_transaction_read_only",
707 : : .section = SECTION_PRE_DATA,
708 : : .createStmt = qry->data));
709 : 10 : resetPQExpBuffer(qry);
710 : :
711 : : /* Put the correct encoding into the archive */
712 : 10 : encname = pg_encoding_to_char(encoding);
713 : :
714 : 10 : appendPQExpBufferStr(qry, "SET client_encoding = ");
715 : 10 : appendStringLiteralAH(qry, encname, fout);
716 : 10 : appendPQExpBufferStr(qry, ";\n");
717 : 10 : ArchiveEntry(fout,
718 : : nilCatalogId, /* catalog ID */
719 : : createDumpId(), /* dump ID */
720 : 10 : ARCHIVE_OPTS(.tag = "client_encoding",
721 : : .description = "client_encoding",
722 : : .section = SECTION_PRE_DATA,
723 : : .createStmt = qry->data));
724 : 10 : resetPQExpBuffer(qry);
725 : :
726 : : /* Put the correct escape string behavior into the archive. */
727 : 10 : appendPQExpBuffer(qry, "SET standard_conforming_strings = 'on';\n");
728 : 10 : ArchiveEntry(fout,
729 : : nilCatalogId, /* catalog ID */
730 : : createDumpId(), /* dump ID */
731 : 10 : ARCHIVE_OPTS(.tag = "standard_conforming_strings",
732 : : .description = "standard_conforming_strings",
733 : : .section = SECTION_PRE_DATA,
734 : : .createStmt = qry->data));
735 : 10 : destroyPQExpBuffer(qry);
736 : : }
737 : : else
738 : : {
739 : 30 : fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n");
740 : :
741 [ + + ]: 30 : if (verbose)
742 : 2 : dumpTimestamp("Started on");
743 : :
744 : : /*
745 : : * Enter restricted mode to block any unexpected psql meta-commands. A
746 : : * malicious source might try to inject a variety of things via bogus
747 : : * responses to queries. While we cannot prevent such sources from
748 : : * affecting the destination at restore time, we can block psql
749 : : * meta-commands so that the client machine that runs psql with the
750 : : * dump output remains unaffected.
751 : : */
752 : 30 : fprintf(OPF, "\\restrict %s\n\n", restrict_key);
753 : :
754 : : /*
755 : : * We used to emit \connect postgres here, but that served no purpose
756 : : * other than to break things for installations without a postgres
757 : : * database. Everything we're restoring here is a global, so
758 : : * whichever database we're connected to at the moment is fine.
759 : : */
760 : :
761 : : /* Restore will need to write to the target cluster */
762 : 30 : fprintf(OPF, "SET default_transaction_read_only = off;\n\n");
763 : :
764 : : /* Replicate encoding and standard_conforming_strings in output */
765 : 30 : fprintf(OPF, "SET client_encoding = '%s';\n",
766 : : pg_encoding_to_char(encoding));
767 : 30 : fprintf(OPF, "SET standard_conforming_strings = on;\n");
768 : 30 : fprintf(OPF, "\n");
769 : : }
770 : :
242 jdavis@postgresql.or 771 [ + - + - :CBC 40 : if (!data_only && !statistics_only && !no_schema)
+ - ]
772 : : {
773 : : /*
774 : : * If asked to --clean, do that first. We can avoid detailed
775 : : * dependency analysis because databases never depend on each other,
776 : : * and tablespaces never depend on each other. Roles could have
777 : : * grants to each other, but DROP ROLE will clean those up silently.
778 : : *
779 : : * For non-text formats, pg_dumpall unconditionally process --clean
780 : : * option. In contrast, pg_restore only applies it if the user
781 : : * explicitly provides the flag. This discrepancy resolves corner
782 : : * cases where pg_restore requires cleanup instructions that may be
783 : : * missing from a standard pg_dumpall output.
784 : : */
20 andrew@dunslane.net 785 [ + + + + ]:GNC 40 : if (output_clean || archDumpFormat != archNull)
786 : : {
6182 tgl@sss.pgh.pa.us 787 [ + + + - :CBC 11 : if (!globals_only && !roles_only && !tablespaces_only)
+ - ]
6182 tgl@sss.pgh.pa.us 788 :GBC 9 : dropDBs(conn);
789 : :
6182 tgl@sss.pgh.pa.us 790 [ + - + - ]:CBC 11 : if (!roles_only && !no_tablespaces)
3441 791 : 11 : dropTablespaces(conn);
792 : :
6182 793 [ + - ]: 11 : if (!tablespaces_only)
794 : 11 : dropRoles(conn);
795 : : }
796 : :
797 : : /*
798 : : * Now create objects as requested. Be careful that option logic here
799 : : * is the same as for drops above.
800 : : */
6989 bruce@momjian.us 801 [ + - ]: 40 : if (!tablespaces_only)
802 : : {
803 : : /* Dump roles (users) */
804 : 40 : dumpRoles(conn);
805 : :
806 : : /* Dump role memberships */
1552 tgl@sss.pgh.pa.us 807 : 40 : dumpRoleMembership(conn);
808 : :
809 : : /* Dump role GUC privileges */
1439 810 [ + - + - ]: 40 : if (server_version >= 150000 && !skip_acls)
811 : 40 : dumpRoleGUCPrivs(conn);
812 : : }
813 : :
814 : : /* Dump tablespaces */
6569 815 [ + + + - ]: 40 : if (!roles_only && !no_tablespaces)
3441 816 : 35 : dumpTablespaces(conn);
817 : : }
818 : :
20 andrew@dunslane.net 819 [ + + ]:GNC 40 : if (archDumpFormat == archNull)
820 : : {
821 : : /*
822 : : * Exit restricted mode just before dumping the databases. pg_dump
823 : : * will handle entering restricted mode again as appropriate.
824 : : */
825 : 30 : fprintf(OPF, "\\unrestrict %s\n\n", restrict_key);
826 : : }
827 : :
6989 bruce@momjian.us 828 [ + + + + :CBC 40 : if (!globals_only && !roles_only && !tablespaces_only)
+ - ]
228 andrew@dunslane.net 829 : 20 : dumpDatabases(conn);
830 : :
20 andrew@dunslane.net 831 [ + + ]:GNC 40 : if (archDumpFormat == archNull)
832 : : {
833 : 30 : PQfinish(conn);
834 : :
835 [ + + ]: 30 : if (verbose)
836 : 2 : dumpTimestamp("Completed on");
837 : 30 : fprintf(OPF, "--\n-- PostgreSQL database cluster dump complete\n--\n\n");
838 : :
839 [ + + ]: 30 : if (filename)
840 : : {
841 : 29 : fclose(OPF);
842 : :
843 : : /* sync the resulting file, errors are not fatal */
844 [ + + ]: 29 : if (dosync)
845 : 3 : (void) fsync_fname(filename, false);
846 : : }
847 : : }
848 : : else
849 : : {
850 : : RestoreOptions *ropt;
851 : :
852 : 10 : ropt = NewRestoreOptions();
853 : 10 : SetArchiveOptions(fout, &dopt, ropt);
854 : :
855 : : /* Mark which entries should be output */
856 : 10 : ProcessArchiveRestoreOptions(fout);
857 : 10 : CloseArchive(fout);
858 : : }
859 : :
5141 rhaas@postgresql.org 860 :CBC 40 : exit_nicely(0);
861 : : }
862 : :
863 : :
864 : : static void
8601 peter_e@gmx.net 865 : 1 : help(void)
866 : : {
20 andrew@dunslane.net 867 :GNC 1 : printf(_("%s exports a PostgreSQL database cluster as an SQL script or to other formats.\n\n"), progname);
8601 peter_e@gmx.net 868 :CBC 1 : printf(_("Usage:\n"));
8549 869 : 1 : printf(_(" %s [OPTION]...\n"), progname);
870 : :
7909 bruce@momjian.us 871 : 1 : printf(_("\nGeneral options:\n"));
5049 peter_e@gmx.net 872 : 1 : printf(_(" -f, --file=FILENAME output file name\n"));
20 andrew@dunslane.net 873 :GNC 1 : printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
874 : : " plain text (default))\n"));
3368 sfrost@snowman.net 875 :CBC 1 : printf(_(" -v, --verbose verbose mode\n"));
5018 peter_e@gmx.net 876 : 1 : printf(_(" -V, --version output version information, then exit\n"));
5049 877 : 1 : printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
5018 878 : 1 : printf(_(" -?, --help show this help, then exit\n"));
7909 bruce@momjian.us 879 : 1 : printf(_("\nOptions controlling the output content:\n"));
388 jdavis@postgresql.or 880 : 1 : printf(_(" -a, --data-only dump only the data, not the schema or statistics\n"));
5049 peter_e@gmx.net 881 : 1 : printf(_(" -c, --clean clean (drop) databases before recreating\n"));
3117 rhaas@postgresql.org 882 : 1 : printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
5049 peter_e@gmx.net 883 : 1 : printf(_(" -g, --globals-only dump only global objects, no databases\n"));
884 : 1 : printf(_(" -O, --no-owner skip restoration of object ownership\n"));
885 : 1 : printf(_(" -r, --roles-only dump only roles, no databases or tablespaces\n"));
388 jdavis@postgresql.or 886 : 1 : printf(_(" -s, --schema-only dump only the schema, no data or statistics\n"));
5049 peter_e@gmx.net 887 : 1 : printf(_(" -S, --superuser=NAME superuser user name to use in the dump\n"));
888 : 1 : printf(_(" -t, --tablespaces-only dump only tablespaces, no databases or roles\n"));
889 : 1 : printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
890 : 1 : printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
891 : 1 : printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
892 : 1 : printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
893 : 1 : printf(_(" --disable-triggers disable triggers during data-only restore\n"));
2571 andrew@dunslane.net 894 : 1 : printf(_(" --exclude-database=PATTERN exclude databases whose name matches PATTERN\n"));
2582 895 : 1 : printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
565 peter@eisentraut.org 896 : 1 : printf(_(" --filter=FILENAME exclude databases based on expressions in FILENAME\n"));
4395 alvherre@alvh.no-ip. 897 : 1 : printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
5049 peter_e@gmx.net 898 : 1 : printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
2841 899 : 1 : printf(_(" --load-via-partition-root load partitions via the root table\n"));
480 bruce@momjian.us 900 : 1 : printf(_(" --no-comments do not dump comment commands\n"));
388 jdavis@postgresql.or 901 : 1 : printf(_(" --no-data do not dump data\n"));
364 tgl@sss.pgh.pa.us 902 : 1 : printf(_(" --no-policies do not dump row security policies\n"));
3229 peter_e@gmx.net 903 : 1 : printf(_(" --no-publications do not dump publications\n"));
3202 904 : 1 : printf(_(" --no-role-passwords do not dump passwords for roles\n"));
388 jdavis@postgresql.or 905 : 1 : printf(_(" --no-schema do not dump schema\n"));
5049 peter_e@gmx.net 906 : 1 : printf(_(" --no-security-labels do not dump security label assignments\n"));
388 jdavis@postgresql.or 907 : 1 : printf(_(" --no-statistics do not dump statistics\n"));
3232 peter_e@gmx.net 908 : 1 : printf(_(" --no-subscriptions do not dump subscriptions\n"));
3280 andrew@dunslane.net 909 : 1 : printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
1518 michael@paquier.xyz 910 : 1 : printf(_(" --no-table-access-method do not dump table access methods\n"));
5049 peter_e@gmx.net 911 : 1 : printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
1761 michael@paquier.xyz 912 : 1 : printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
5049 peter_e@gmx.net 913 : 1 : printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
2802 tmunro@postgresql.or 914 : 1 : printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
5049 peter_e@gmx.net 915 : 1 : printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
216 nathan@postgresql.or 916 : 1 : printf(_(" --restrict-key=RESTRICT_KEY use provided string as psql \\restrict key\n"));
2466 alvherre@alvh.no-ip. 917 : 1 : printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
312 nathan@postgresql.or 918 : 1 : printf(_(" --sequence-data include sequence data in dump\n"));
225 jdavis@postgresql.or 919 : 1 : printf(_(" --statistics dump the statistics\n"));
388 920 : 1 : printf(_(" --statistics-only dump only the statistics, not schema or data\n"));
7099 peter_e@gmx.net 921 : 1 : printf(_(" --use-set-session-authorization\n"
922 : : " use SET SESSION AUTHORIZATION commands instead of\n"
923 : : " ALTER OWNER commands to set ownership\n"));
924 : :
8549 925 : 1 : printf(_("\nConnection options:\n"));
4766 heikki.linnakangas@i 926 : 1 : printf(_(" -d, --dbname=CONNSTR connect using connection string\n"));
8313 bruce@momjian.us 927 : 1 : printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
6227 peter_e@gmx.net 928 : 1 : printf(_(" -l, --database=DBNAME alternative default database\n"));
8549 929 : 1 : printf(_(" -p, --port=PORT database server port number\n"));
930 : 1 : printf(_(" -U, --username=NAME connect as specified database user\n"));
6226 931 : 1 : printf(_(" -w, --no-password never prompt for password\n"));
8549 932 : 1 : printf(_(" -W, --password force password prompt (should happen automatically)\n"));
5408 933 : 1 : printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
934 : :
6227 935 : 1 : printf(_("\nIf -f/--file is not used, then the SQL script will be written to the standard\n"
936 : : "output.\n\n"));
2207 peter@eisentraut.org 937 : 1 : printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
938 : 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
8601 peter_e@gmx.net 939 : 1 : }
940 : :
941 : :
942 : : /*
943 : : * Drop roles
944 : : */
945 : : static void
6182 tgl@sss.pgh.pa.us 946 : 11 : dropRoles(PGconn *conn)
947 : : {
3295 simon@2ndQuadrant.co 948 : 11 : PQExpBuffer buf = createPQExpBuffer();
949 : : PGresult *res;
950 : : int i_rolname;
951 : : int i;
952 : :
3582 sfrost@snowman.net 953 [ + - ]: 11 : if (server_version >= 90600)
3295 simon@2ndQuadrant.co 954 : 11 : printfPQExpBuffer(buf,
955 : : "SELECT rolname "
956 : : "FROM %s "
957 : : "WHERE rolname !~ '^pg_' "
958 : : "ORDER BY 1", role_catalog);
959 : : else
3295 simon@2ndQuadrant.co 960 :UBC 0 : printfPQExpBuffer(buf,
961 : : "SELECT rolname "
962 : : "FROM %s "
963 : : "ORDER BY 1", role_catalog);
964 : :
3295 simon@2ndQuadrant.co 965 :CBC 11 : res = executeQuery(conn, buf->data);
966 : :
6182 tgl@sss.pgh.pa.us 967 : 11 : i_rolname = PQfnumber(res, "rolname");
968 : :
20 andrew@dunslane.net 969 [ + - + + ]:GNC 11 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
6182 tgl@sss.pgh.pa.us 970 :CBC 1 : fprintf(OPF, "--\n-- Drop roles\n--\n\n");
971 : :
972 [ + + ]: 144 : for (i = 0; i < PQntuples(res); i++)
973 : : {
974 : : const char *rolename;
20 andrew@dunslane.net 975 :GNC 133 : PQExpBuffer delQry = createPQExpBuffer();
976 : :
6182 tgl@sss.pgh.pa.us 977 :CBC 133 : rolename = PQgetvalue(res, i, i_rolname);
978 : :
20 andrew@dunslane.net 979 [ + + ]:GNC 133 : if (archDumpFormat == archNull)
980 : : {
981 : 6 : appendPQExpBuffer(delQry, "DROP ROLE %s%s;\n",
982 [ - + ]: 3 : if_exists ? "IF EXISTS " : "",
983 : : fmtId(rolename));
984 : 3 : fprintf(OPF, "%s", delQry->data);
985 : : }
986 : : else
987 : : {
988 : 130 : appendPQExpBuffer(delQry, "DROP ROLE IF EXISTS %s;\n",
989 : : fmtId(rolename));
990 : :
991 : 130 : ArchiveEntry(fout,
992 : : nilCatalogId, /* catalog ID */
993 : : createDumpId(), /* dump ID */
994 : 130 : ARCHIVE_OPTS(.tag = psprintf("ROLE %s", fmtId(rolename)),
995 : : .description = "DROP_GLOBAL",
996 : : .section = SECTION_PRE_DATA,
997 : : .createStmt = delQry->data));
998 : : }
999 : :
1000 : 133 : destroyPQExpBuffer(delQry);
1001 : : }
1002 : :
6182 tgl@sss.pgh.pa.us 1003 :CBC 11 : PQclear(res);
3295 simon@2ndQuadrant.co 1004 : 11 : destroyPQExpBuffer(buf);
1005 : :
20 andrew@dunslane.net 1006 [ + + ]:GNC 11 : if (archDumpFormat == archNull)
1007 : 1 : fprintf(OPF, "\n\n");
6182 tgl@sss.pgh.pa.us 1008 :CBC 11 : }
1009 : :
1010 : : /*
1011 : : * Dump roles
1012 : : */
1013 : : static void
7461 1014 : 40 : dumpRoles(PGconn *conn)
1015 : : {
7555 1016 : 40 : PQExpBuffer buf = createPQExpBuffer();
20 andrew@dunslane.net 1017 :GNC 40 : PQExpBuffer comment_buf = createPQExpBuffer();
1018 : 40 : PQExpBuffer seclabel_buf = createPQExpBuffer();
1019 : : PGresult *res;
1020 : : int i_oid,
1021 : : i_rolname,
1022 : : i_rolsuper,
1023 : : i_rolinherit,
1024 : : i_rolcreaterole,
1025 : : i_rolcreatedb,
1026 : : i_rolcanlogin,
1027 : : i_rolconnlimit,
1028 : : i_rolpassword,
1029 : : i_rolvaliduntil,
1030 : : i_rolreplication,
1031 : : i_rolbypassrls,
1032 : : i_rolcomment,
1033 : : i_is_current_user;
1034 : : int i;
1035 : :
1036 : : /*
1037 : : * Notes: rolconfig is dumped later, and pg_authid must be used for
1038 : : * extracting rolcomment regardless of role_catalog.
1039 : : */
3628 sfrost@snowman.net 1040 [ + - ]:CBC 40 : if (server_version >= 90600)
4195 1041 : 40 : printfPQExpBuffer(buf,
1042 : : "SELECT oid, rolname, rolsuper, rolinherit, "
1043 : : "rolcreaterole, rolcreatedb, "
1044 : : "rolcanlogin, rolconnlimit, rolpassword, "
1045 : : "rolvaliduntil, rolreplication, rolbypassrls, "
1046 : : "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
1047 : : "rolname = current_user AS is_current_user "
1048 : : "FROM %s "
1049 : : "WHERE rolname !~ '^pg_' "
1050 : : "ORDER BY 2", role_catalog);
3600 sfrost@snowman.net 1051 [ # # ]:UBC 0 : else if (server_version >= 90500)
1052 : 0 : printfPQExpBuffer(buf,
1053 : : "SELECT oid, rolname, rolsuper, rolinherit, "
1054 : : "rolcreaterole, rolcreatedb, "
1055 : : "rolcanlogin, rolconnlimit, rolpassword, "
1056 : : "rolvaliduntil, rolreplication, rolbypassrls, "
1057 : : "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
1058 : : "rolname = current_user AS is_current_user "
1059 : : "FROM %s "
1060 : : "ORDER BY 2", role_catalog);
1061 : : else
7532 tgl@sss.pgh.pa.us 1062 : 0 : printfPQExpBuffer(buf,
1063 : : "SELECT oid, rolname, rolsuper, rolinherit, "
1064 : : "rolcreaterole, rolcreatedb, "
1065 : : "rolcanlogin, rolconnlimit, rolpassword, "
1066 : : "rolvaliduntil, rolreplication, "
1067 : : "false as rolbypassrls, "
1068 : : "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
1069 : : "rolname = current_user AS is_current_user "
1070 : : "FROM %s "
1071 : : "ORDER BY 2", role_catalog);
1072 : :
7532 tgl@sss.pgh.pa.us 1073 :CBC 40 : res = executeQuery(conn, buf->data);
1074 : :
5546 bruce@momjian.us 1075 : 40 : i_oid = PQfnumber(res, "oid");
7532 tgl@sss.pgh.pa.us 1076 : 40 : i_rolname = PQfnumber(res, "rolname");
1077 : 40 : i_rolsuper = PQfnumber(res, "rolsuper");
1078 : 40 : i_rolinherit = PQfnumber(res, "rolinherit");
1079 : 40 : i_rolcreaterole = PQfnumber(res, "rolcreaterole");
1080 : 40 : i_rolcreatedb = PQfnumber(res, "rolcreatedb");
1081 : 40 : i_rolcanlogin = PQfnumber(res, "rolcanlogin");
1082 : 40 : i_rolconnlimit = PQfnumber(res, "rolconnlimit");
1083 : 40 : i_rolpassword = PQfnumber(res, "rolpassword");
1084 : 40 : i_rolvaliduntil = PQfnumber(res, "rolvaliduntil");
5555 magnus@hagander.net 1085 : 40 : i_rolreplication = PQfnumber(res, "rolreplication");
4195 sfrost@snowman.net 1086 : 40 : i_rolbypassrls = PQfnumber(res, "rolbypassrls");
7336 bruce@momjian.us 1087 : 40 : i_rolcomment = PQfnumber(res, "rolcomment");
4850 1088 : 40 : i_is_current_user = PQfnumber(res, "is_current_user");
1089 : :
20 andrew@dunslane.net 1090 [ + - + + ]:GNC 40 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
6989 bruce@momjian.us 1091 :CBC 30 : fprintf(OPF, "--\n-- Roles\n--\n\n");
1092 : :
8601 peter_e@gmx.net 1093 [ + + ]: 246 : for (i = 0; i < PQntuples(res); i++)
1094 : : {
1095 : : const char *rolename;
1096 : : Oid auth_oid;
1097 : :
5352 rhaas@postgresql.org 1098 : 206 : auth_oid = atooid(PQgetvalue(res, i, i_oid));
7532 tgl@sss.pgh.pa.us 1099 : 206 : rolename = PQgetvalue(res, i, i_rolname);
1100 : :
3566 rhaas@postgresql.org 1101 [ - + ]: 206 : if (strncmp(rolename, "pg_", 3) == 0)
1102 : : {
2540 peter@eisentraut.org 1103 :UBC 0 : pg_log_warning("role name starting with \"pg_\" skipped (%s)",
1104 : : rolename);
3628 sfrost@snowman.net 1105 : 0 : continue;
1106 : : }
1107 : :
7461 tgl@sss.pgh.pa.us 1108 :CBC 206 : resetPQExpBuffer(buf);
20 andrew@dunslane.net 1109 :GNC 206 : resetPQExpBuffer(comment_buf);
1110 : 206 : resetPQExpBuffer(seclabel_buf);
1111 : :
5546 bruce@momjian.us 1112 [ + + ]:CBC 206 : if (binary_upgrade)
1113 : : {
4500 heikki.linnakangas@i 1114 : 21 : appendPQExpBufferStr(buf, "\n-- For binary upgrade, must preserve pg_authid.oid\n");
5546 bruce@momjian.us 1115 : 21 : appendPQExpBuffer(buf,
1116 : : "SELECT pg_catalog.binary_upgrade_set_next_pg_authid_oid('%u'::pg_catalog.oid);\n\n",
1117 : : auth_oid);
1118 : : }
1119 : :
1120 : : /*
1121 : : * We dump CREATE ROLE followed by ALTER ROLE to ensure that the role
1122 : : * will acquire the right properties even if it already exists (ie, it
1123 : : * won't hurt for the CREATE to fail). This is particularly important
1124 : : * for the role we are connected as, since even with --clean we will
1125 : : * have failed to drop it. binary_upgrade cannot generate any errors,
1126 : : * so we assume the current role is already created.
1127 : : */
4850 1128 [ + + ]: 206 : if (!binary_upgrade ||
1129 [ + + ]: 21 : strcmp(PQgetvalue(res, i, i_is_current_user), "f") == 0)
4853 1130 : 195 : appendPQExpBuffer(buf, "CREATE ROLE %s;\n", fmtId(rolename));
7461 tgl@sss.pgh.pa.us 1131 : 206 : appendPQExpBuffer(buf, "ALTER ROLE %s WITH", fmtId(rolename));
1132 : :
7532 1133 [ + + ]: 206 : if (strcmp(PQgetvalue(res, i, i_rolsuper), "t") == 0)
4500 heikki.linnakangas@i 1134 : 74 : appendPQExpBufferStr(buf, " SUPERUSER");
1135 : : else
1136 : 132 : appendPQExpBufferStr(buf, " NOSUPERUSER");
1137 : :
7532 tgl@sss.pgh.pa.us 1138 [ + - ]: 206 : if (strcmp(PQgetvalue(res, i, i_rolinherit), "t") == 0)
4500 heikki.linnakangas@i 1139 : 206 : appendPQExpBufferStr(buf, " INHERIT");
1140 : : else
4500 heikki.linnakangas@i 1141 :UBC 0 : appendPQExpBufferStr(buf, " NOINHERIT");
1142 : :
7532 tgl@sss.pgh.pa.us 1143 [ + + ]:CBC 206 : if (strcmp(PQgetvalue(res, i, i_rolcreaterole), "t") == 0)
4500 heikki.linnakangas@i 1144 : 64 : appendPQExpBufferStr(buf, " CREATEROLE");
1145 : : else
1146 : 142 : appendPQExpBufferStr(buf, " NOCREATEROLE");
1147 : :
7532 tgl@sss.pgh.pa.us 1148 [ + + ]: 206 : if (strcmp(PQgetvalue(res, i, i_rolcreatedb), "t") == 0)
4500 heikki.linnakangas@i 1149 : 64 : appendPQExpBufferStr(buf, " CREATEDB");
1150 : : else
1151 : 142 : appendPQExpBufferStr(buf, " NOCREATEDB");
1152 : :
7532 tgl@sss.pgh.pa.us 1153 [ + + ]: 206 : if (strcmp(PQgetvalue(res, i, i_rolcanlogin), "t") == 0)
4500 heikki.linnakangas@i 1154 : 65 : appendPQExpBufferStr(buf, " LOGIN");
1155 : : else
1156 : 141 : appendPQExpBufferStr(buf, " NOLOGIN");
1157 : :
5555 magnus@hagander.net 1158 [ + + ]: 206 : if (strcmp(PQgetvalue(res, i, i_rolreplication), "t") == 0)
4500 heikki.linnakangas@i 1159 : 50 : appendPQExpBufferStr(buf, " REPLICATION");
1160 : : else
1161 : 156 : appendPQExpBufferStr(buf, " NOREPLICATION");
1162 : :
4195 sfrost@snowman.net 1163 [ + + ]: 206 : if (strcmp(PQgetvalue(res, i, i_rolbypassrls), "t") == 0)
1164 : 40 : appendPQExpBufferStr(buf, " BYPASSRLS");
1165 : : else
1166 : 166 : appendPQExpBufferStr(buf, " NOBYPASSRLS");
1167 : :
7532 tgl@sss.pgh.pa.us 1168 [ + + ]: 206 : if (strcmp(PQgetvalue(res, i, i_rolconnlimit), "-1") != 0)
7532 tgl@sss.pgh.pa.us 1169 :GBC 10 : appendPQExpBuffer(buf, " CONNECTION LIMIT %s",
1170 : : PQgetvalue(res, i, i_rolconnlimit));
1171 : :
1172 : :
3295 simon@2ndQuadrant.co 1173 [ + + + - ]:CBC 206 : if (!PQgetisnull(res, i, i_rolpassword) && !no_role_passwords)
1174 : : {
4500 heikki.linnakangas@i 1175 :GBC 10 : appendPQExpBufferStr(buf, " PASSWORD ");
7231 tgl@sss.pgh.pa.us 1176 : 10 : appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolpassword), conn);
1177 : : }
1178 : :
7532 tgl@sss.pgh.pa.us 1179 [ - + ]:CBC 206 : if (!PQgetisnull(res, i, i_rolvaliduntil))
8325 tgl@sss.pgh.pa.us 1180 :UBC 0 : appendPQExpBuffer(buf, " VALID UNTIL '%s'",
1181 : : PQgetvalue(res, i, i_rolvaliduntil));
1182 : :
4500 heikki.linnakangas@i 1183 :CBC 206 : appendPQExpBufferStr(buf, ";\n");
1184 : :
2971 tgl@sss.pgh.pa.us 1185 [ + - - + ]: 206 : if (!no_comments && !PQgetisnull(res, i, i_rolcomment))
1186 : : {
20 andrew@dunslane.net 1187 :UNC 0 : appendPQExpBuffer(comment_buf, "COMMENT ON ROLE %s IS ", fmtId(rolename));
1188 : 0 : appendStringLiteralConn(comment_buf, PQgetvalue(res, i, i_rolcomment), conn);
1189 : 0 : appendPQExpBufferStr(comment_buf, ";\n");
1190 : : }
1191 : :
1552 tgl@sss.pgh.pa.us 1192 [ + - ]:CBC 206 : if (!no_security_labels)
5352 rhaas@postgresql.org 1193 : 206 : buildShSecLabels(conn, "pg_authid", auth_oid,
1194 : : "ROLE", rolename,
1195 : : seclabel_buf);
1196 : :
20 andrew@dunslane.net 1197 [ + + ]:GNC 206 : if (archDumpFormat == archNull)
1198 : : {
1199 : 76 : fprintf(OPF, "%s", buf->data);
1200 : 76 : fprintf(OPF, "%s", comment_buf->data);
1201 : :
1202 [ - + ]: 76 : if (seclabel_buf->data[0] != '\0')
20 andrew@dunslane.net 1203 :UNC 0 : fprintf(OPF, "%s", seclabel_buf->data);
1204 : : }
1205 : : else
1206 : : {
20 andrew@dunslane.net 1207 :GNC 130 : char *tag = psprintf("ROLE %s", fmtId(rolename));
1208 : :
1209 : 130 : ArchiveEntry(fout,
1210 : : nilCatalogId, /* catalog ID */
1211 : : createDumpId(), /* dump ID */
1212 : 130 : ARCHIVE_OPTS(.tag = tag,
1213 : : .description = "ROLE",
1214 : : .section = SECTION_PRE_DATA,
1215 : : .createStmt = buf->data));
1216 [ - + ]: 130 : if (comment_buf->data[0] != '\0')
20 andrew@dunslane.net 1217 :UNC 0 : ArchiveEntry(fout,
1218 : : nilCatalogId, /* catalog ID */
1219 : : createDumpId(), /* dump ID */
1220 : 0 : ARCHIVE_OPTS(.tag = tag,
1221 : : .description = "COMMENT",
1222 : : .section = SECTION_PRE_DATA,
1223 : : .createStmt = comment_buf->data));
1224 : :
20 andrew@dunslane.net 1225 [ - + ]:GNC 130 : if (seclabel_buf->data[0] != '\0')
20 andrew@dunslane.net 1226 :UNC 0 : ArchiveEntry(fout,
1227 : : nilCatalogId, /* catalog ID */
1228 : : createDumpId(), /* dump ID */
1229 : 0 : ARCHIVE_OPTS(.tag = tag,
1230 : : .description = "SECURITY LABEL",
1231 : : .section = SECTION_PRE_DATA,
1232 : : .createStmt = seclabel_buf->data));
1233 : : }
1234 : : }
1235 : :
1236 : : /*
1237 : : * Dump configuration settings for roles after all roles have been dumped.
1238 : : * We do it this way because config settings for roles could mention the
1239 : : * names of other roles.
1240 : : */
20 andrew@dunslane.net 1241 [ + - + + ]:GNC 40 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
228 andrew@dunslane.net 1242 :CBC 30 : fprintf(OPF, "\n--\n-- User Configurations\n--\n");
1243 : :
3441 tgl@sss.pgh.pa.us 1244 [ + + ]: 246 : for (i = 0; i < PQntuples(res); i++)
1245 : 206 : dumpUserConfig(conn, PQgetvalue(res, i, i_rolname));
1246 : :
8601 peter_e@gmx.net 1247 : 40 : PQclear(res);
1248 : :
20 andrew@dunslane.net 1249 [ + + ]:GNC 40 : if (archDumpFormat == archNull)
1250 : 30 : fprintf(OPF, "\n\n");
1251 : :
7555 tgl@sss.pgh.pa.us 1252 :CBC 40 : destroyPQExpBuffer(buf);
20 andrew@dunslane.net 1253 :GNC 40 : destroyPQExpBuffer(comment_buf);
1254 : 40 : destroyPQExpBuffer(seclabel_buf);
8601 peter_e@gmx.net 1255 :CBC 40 : }
1256 : :
1257 : :
1258 : : /*
1259 : : * Dump role memberships.
1260 : : *
1261 : : * Note: we expect dumpRoles already created all the roles, but there is
1262 : : * no membership yet.
1263 : : */
1264 : : static void
7532 tgl@sss.pgh.pa.us 1265 : 40 : dumpRoleMembership(PGconn *conn)
1266 : : {
3295 simon@2ndQuadrant.co 1267 : 40 : PQExpBuffer buf = createPQExpBuffer();
20 andrew@dunslane.net 1268 :GNC 40 : PQExpBuffer querybuf = createPQExpBuffer();
1031 tgl@sss.pgh.pa.us 1269 :CBC 40 : PQExpBuffer optbuf = createPQExpBuffer();
1270 : : PGresult *res;
1301 rhaas@postgresql.org 1271 : 40 : int start = 0,
1272 : : end,
1273 : : total;
1274 : : bool dump_grantors;
1275 : : bool dump_grant_options;
1276 : : int i_role;
1277 : : int i_member;
1278 : : int i_grantor;
1279 : : int i_roleid;
1280 : : int i_memberid;
1281 : : int i_grantorid;
1282 : : int i_admin_option;
1283 : : int i_inherit_option;
1284 : : int i_set_option;
1285 : :
1286 : : /*
1287 : : * Previous versions of PostgreSQL didn't used to track the grantor very
1288 : : * carefully in the backend, and the grantor could be any user even if
1289 : : * they didn't have ADMIN OPTION on the role, or a user that no longer
1290 : : * existed. To avoid dump and restore failures, don't dump the grantor
1291 : : * when talking to an old server version.
1292 : : *
1293 : : * Also, in older versions the roleid and/or member could be role OIDs
1294 : : * that no longer exist. If we find such cases, print a warning and skip
1295 : : * the entry.
1296 : : */
13 tgl@sss.pgh.pa.us 1297 : 40 : dump_grantors = (server_version >= 160000);
1298 : :
1299 : : /*
1300 : : * Previous versions of PostgreSQL also did not have grant-level options.
1301 : : */
1213 rhaas@postgresql.org 1302 : 40 : dump_grant_options = (server_version >= 160000);
1303 : :
1304 : : /* Generate and execute query. */
1301 1305 : 40 : printfPQExpBuffer(buf, "SELECT ur.rolname AS role, "
1306 : : "um.rolname AS member, "
1307 : : "ug.rolname AS grantor, "
1308 : : "a.roleid AS roleid, "
1309 : : "a.member AS memberid, "
1310 : : "a.grantor AS grantorid, "
1311 : : "a.admin_option");
1213 1312 [ + - ]: 40 : if (dump_grant_options)
1313 : 40 : appendPQExpBufferStr(buf, ", a.inherit_option, a.set_option");
1298 1314 : 40 : appendPQExpBuffer(buf, " FROM pg_auth_members a "
1315 : : "LEFT JOIN %s ur on ur.oid = a.roleid "
1316 : : "LEFT JOIN %s um on um.oid = a.member "
1317 : : "LEFT JOIN %s ug on ug.oid = a.grantor "
1318 : : "WHERE NOT (ur.rolname ~ '^pg_' AND um.rolname ~ '^pg_')"
1319 : : "ORDER BY 1,2,3", role_catalog, role_catalog, role_catalog);
3295 simon@2ndQuadrant.co 1320 : 40 : res = executeQuery(conn, buf->data);
387 tgl@sss.pgh.pa.us 1321 : 40 : i_role = PQfnumber(res, "role");
1322 : 40 : i_member = PQfnumber(res, "member");
1323 : 40 : i_grantor = PQfnumber(res, "grantor");
1324 : 40 : i_roleid = PQfnumber(res, "roleid");
1325 : 40 : i_memberid = PQfnumber(res, "memberid");
1326 : 40 : i_grantorid = PQfnumber(res, "grantorid");
1327 : 40 : i_admin_option = PQfnumber(res, "admin_option");
1298 rhaas@postgresql.org 1328 : 40 : i_inherit_option = PQfnumber(res, "inherit_option");
1213 1329 : 40 : i_set_option = PQfnumber(res, "set_option");
1330 : :
20 andrew@dunslane.net 1331 [ + + - + ]:GNC 40 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
6989 bruce@momjian.us 1332 :UBC 0 : fprintf(OPF, "--\n-- Role memberships\n--\n\n");
1333 : :
1334 : : /*
1335 : : * We can't dump these GRANT commands in arbitrary order, because a role
1336 : : * that is named as a grantor must already have ADMIN OPTION on the role
1337 : : * for which it is granting permissions, except for the bootstrap
1338 : : * superuser, who can always be named as the grantor.
1339 : : *
1340 : : * We handle this by considering these grants role by role. For each role,
1341 : : * we initially consider the only allowable grantor to be the bootstrap
1342 : : * superuser. Every time we grant ADMIN OPTION on the role to some user,
1343 : : * that user also becomes an allowable grantor. We make repeated passes
1344 : : * over the grants for the role, each time dumping those whose grantors
1345 : : * are allowable and which we haven't done yet. Eventually this should let
1346 : : * us dump all the grants.
1347 : : */
1301 rhaas@postgresql.org 1348 :CBC 40 : total = PQntuples(res);
1349 [ + + ]: 50 : while (start < total)
1350 : : {
387 tgl@sss.pgh.pa.us 1351 :GBC 10 : char *role = PQgetvalue(res, start, i_role);
1352 : : int i;
1353 : : bool *done;
1354 : : int remaining;
1301 rhaas@postgresql.org 1355 : 10 : int prev_remaining = 0;
1356 : : rolename_hash *ht;
1357 : :
1358 : : /* If we hit a null roleid, we're done (nulls sort to the end). */
387 tgl@sss.pgh.pa.us 1359 [ - + ]: 10 : if (PQgetisnull(res, start, i_role))
1360 : : {
1361 : : /* translator: %s represents a numeric role OID */
13 tgl@sss.pgh.pa.us 1362 :UBC 0 : pg_log_warning("ignoring role grant for missing role with OID %s",
1363 : : PQgetvalue(res, start, i_roleid));
387 1364 : 0 : break;
1365 : : }
1366 : :
1367 : : /* All memberships for a single role should be adjacent. */
1301 rhaas@postgresql.org 1368 [ + + ]:GBC 20 : for (end = start; end < total; ++end)
1369 : : {
1370 : : char *otherrole;
1371 : :
387 tgl@sss.pgh.pa.us 1372 : 10 : otherrole = PQgetvalue(res, end, i_role);
1301 rhaas@postgresql.org 1373 [ - + ]: 10 : if (strcmp(role, otherrole) != 0)
1301 rhaas@postgresql.org 1374 :UBC 0 : break;
1375 : : }
1376 : :
1301 rhaas@postgresql.org 1377 :GBC 10 : remaining = end - start;
30 michael@paquier.xyz 1378 :GNC 10 : done = pg_malloc0_array(bool, remaining);
1379 : :
1380 : : /*
1381 : : * We use a hashtable to track the member names that have been granted
1382 : : * admin option. Usually a hashtable is overkill, but sometimes not.
1383 : : */
1301 rhaas@postgresql.org 1384 :GBC 10 : ht = rolename_create(remaining, NULL);
1385 : :
1386 : : /*
1387 : : * Make repeated passes over the grants for this role until all have
1388 : : * been dumped.
1389 : : */
1390 [ + + ]: 20 : while (remaining > 0)
1391 : : {
1392 : : /*
1393 : : * We should make progress on every iteration, because a notional
1394 : : * graph whose vertices are grants and whose edges point from
1395 : : * grantors to members should be connected and acyclic. If we fail
1396 : : * to make progress, either we or the server have messed up.
1397 : : */
1398 [ - + ]: 10 : if (remaining == prev_remaining)
1399 : : {
1301 rhaas@postgresql.org 1400 :UBC 0 : pg_log_error("could not find a legal dump ordering for memberships in role \"%s\"",
1401 : : role);
1402 : 0 : PQfinish(conn);
1403 : 0 : exit_nicely(1);
1404 : : }
1054 dgustafsson@postgres 1405 :GBC 10 : prev_remaining = remaining;
1406 : :
1407 : : /* Make one pass over the grants for this role. */
1301 rhaas@postgresql.org 1408 [ + + ]: 20 : for (i = start; i < end; ++i)
1409 : : {
1410 : : char *member;
1411 : : char *grantorid;
13 tgl@sss.pgh.pa.us 1412 : 10 : char *grantor = NULL;
1413 : 10 : bool dump_this_grantor = dump_grantors;
1213 rhaas@postgresql.org 1414 : 10 : char *set_option = "true";
1415 : : char *admin_option;
1416 : : bool found;
1417 : :
1418 : : /* If we already did this grant, don't do it again. */
1301 1419 [ - + ]: 10 : if (done[i - start])
1301 rhaas@postgresql.org 1420 :UBC 0 : continue;
1421 : :
1422 : : /* Complain about, then ignore, entries for unknown members. */
387 tgl@sss.pgh.pa.us 1423 [ - + ]:GBC 10 : if (PQgetisnull(res, i, i_member))
1424 : : {
1425 : : /* translator: %s represents a numeric role OID */
13 tgl@sss.pgh.pa.us 1426 :UBC 0 : pg_log_warning("ignoring role grant to missing role with OID %s",
1427 : : PQgetvalue(res, i, i_memberid));
387 1428 : 0 : done[i - start] = true;
1429 : 0 : --remaining;
1430 : 0 : continue;
1431 : : }
13 tgl@sss.pgh.pa.us 1432 :GBC 10 : member = PQgetvalue(res, i, i_member);
1433 : :
1434 : : /* If the grantor is unknown, complain and dump without it. */
1435 : 10 : grantorid = PQgetvalue(res, i, i_grantorid);
1436 [ + - ]: 10 : if (dump_this_grantor)
1437 : : {
1438 [ - + ]: 10 : if (PQgetisnull(res, i, i_grantor))
1439 : : {
1440 : : /* translator: %s represents a numeric role OID */
13 tgl@sss.pgh.pa.us 1441 :UBC 0 : pg_log_warning("grant of role \"%s\" to \"%s\" has invalid grantor OID %s",
1442 : : role, member, grantorid);
1443 : 0 : pg_log_warning_detail("This grant will be dumped without GRANTED BY.");
1444 : 0 : dump_this_grantor = false;
1445 : : }
1446 : : else
13 tgl@sss.pgh.pa.us 1447 :GBC 10 : grantor = PQgetvalue(res, i, i_grantor);
1448 : : }
1449 : :
387 1450 : 10 : admin_option = PQgetvalue(res, i, i_admin_option);
1213 rhaas@postgresql.org 1451 [ + - ]: 10 : if (dump_grant_options)
1452 : 10 : set_option = PQgetvalue(res, i, i_set_option);
1453 : :
1454 : : /*
1455 : : * If we're not dumping the grantor or if the grantor is the
1456 : : * bootstrap superuser, it's fine to dump this now. Otherwise,
1457 : : * it's got to be someone who has already been granted ADMIN
1458 : : * OPTION.
1459 : : */
13 tgl@sss.pgh.pa.us 1460 [ + - ]: 10 : if (dump_this_grantor &&
1301 rhaas@postgresql.org 1461 [ - + - - ]: 10 : atooid(grantorid) != BOOTSTRAP_SUPERUSERID &&
1301 rhaas@postgresql.org 1462 :UBC 0 : rolename_lookup(ht, grantor) == NULL)
1463 : 0 : continue;
1464 : :
1465 : : /* Remember that we did this so that we don't do it again. */
1301 rhaas@postgresql.org 1466 :GBC 10 : done[i - start] = true;
1467 : 10 : --remaining;
1468 : :
1469 : : /*
1470 : : * If ADMIN OPTION is being granted, remember that grants
1471 : : * listing this member as the grantor can now be dumped.
1472 : : */
1473 [ - + ]: 10 : if (*admin_option == 't')
1301 rhaas@postgresql.org 1474 :UBC 0 : rolename_insert(ht, member, &found);
1475 : :
1476 : : /* Generate the actual GRANT statement. */
1298 rhaas@postgresql.org 1477 :GBC 10 : resetPQExpBuffer(optbuf);
20 andrew@dunslane.net 1478 :GNC 10 : resetPQExpBuffer(querybuf);
1479 : 10 : appendPQExpBuffer(querybuf, "GRANT %s", fmtId(role));
1480 : 10 : appendPQExpBuffer(querybuf, " TO %s", fmtId(member));
1301 rhaas@postgresql.org 1481 [ - + ]:GBC 10 : if (*admin_option == 't')
1298 rhaas@postgresql.org 1482 :UBC 0 : appendPQExpBufferStr(optbuf, "ADMIN OPTION");
1213 rhaas@postgresql.org 1483 [ + - ]:GBC 10 : if (dump_grant_options)
1484 : : {
1485 : : char *inherit_option;
1486 : :
1298 1487 [ - + ]: 10 : if (optbuf->data[0] != '\0')
1298 rhaas@postgresql.org 1488 :UBC 0 : appendPQExpBufferStr(optbuf, ", ");
1298 rhaas@postgresql.org 1489 :GBC 10 : inherit_option = PQgetvalue(res, i, i_inherit_option);
1490 : 10 : appendPQExpBuffer(optbuf, "INHERIT %s",
1491 [ + - ]: 10 : *inherit_option == 't' ?
1492 : : "TRUE" : "FALSE");
1493 : : }
1213 1494 [ - + ]: 10 : if (*set_option != 't')
1495 : : {
1213 rhaas@postgresql.org 1496 [ # # ]:UBC 0 : if (optbuf->data[0] != '\0')
1497 : 0 : appendPQExpBufferStr(optbuf, ", ");
331 drowley@postgresql.o 1498 : 0 : appendPQExpBufferStr(optbuf, "SET FALSE");
1499 : : }
1298 rhaas@postgresql.org 1500 [ + - ]:GBC 10 : if (optbuf->data[0] != '\0')
20 andrew@dunslane.net 1501 :GNC 10 : appendPQExpBuffer(querybuf, " WITH %s", optbuf->data);
13 tgl@sss.pgh.pa.us 1502 [ + - ]:GBC 10 : if (dump_this_grantor)
20 andrew@dunslane.net 1503 :GNC 10 : appendPQExpBuffer(querybuf, " GRANTED BY %s", fmtId(grantor));
1504 : 10 : appendPQExpBuffer(querybuf, ";\n");
1505 : :
1506 [ - + ]: 10 : if (archDumpFormat == archNull)
20 andrew@dunslane.net 1507 :UNC 0 : fprintf(OPF, "%s", querybuf->data);
1508 : : else
20 andrew@dunslane.net 1509 :GNC 10 : ArchiveEntry(fout,
1510 : : nilCatalogId, /* catalog ID */
1511 : : createDumpId(), /* dump ID */
1512 : 10 : ARCHIVE_OPTS(.tag = psprintf("ROLE %s", fmtId(role)),
1513 : : .description = "ROLE PROPERTIES",
1514 : : .section = SECTION_PRE_DATA,
1515 : : .createStmt = querybuf->data));
1516 : : }
1517 : : }
1518 : :
1301 rhaas@postgresql.org 1519 :GBC 10 : rolename_destroy(ht);
1520 : 10 : pg_free(done);
1521 : 10 : start = end;
1522 : : }
1523 : :
7532 tgl@sss.pgh.pa.us 1524 :CBC 40 : PQclear(res);
3295 simon@2ndQuadrant.co 1525 : 40 : destroyPQExpBuffer(buf);
20 andrew@dunslane.net 1526 :GNC 40 : destroyPQExpBuffer(querybuf);
1527 : 40 : destroyPQExpBuffer(optbuf);
1528 : :
1529 [ + + ]: 40 : if (archDumpFormat == archNull)
1530 : 30 : fprintf(OPF, "\n\n");
7532 tgl@sss.pgh.pa.us 1531 :CBC 40 : }
1532 : :
1533 : :
1534 : : /*
1535 : : * Dump role configuration parameter privileges. This code is used for 15.0
1536 : : * and later servers.
1537 : : *
1538 : : * Note: we expect dumpRoles already created all the roles, but there are
1539 : : * no per-role configuration parameter privileges yet.
1540 : : */
1541 : : static void
1439 1542 : 40 : dumpRoleGUCPrivs(PGconn *conn)
1543 : : {
1544 : : PGresult *res;
1545 : : int i;
1546 : :
1547 : : /*
1548 : : * Get all parameters that have non-default acls defined.
1549 : : */
1550 : 40 : res = executeQuery(conn, "SELECT parname, "
1551 : : "pg_catalog.pg_get_userbyid(" CppAsString2(BOOTSTRAP_SUPERUSERID) ") AS parowner, "
1552 : : "paracl, "
1553 : : "pg_catalog.acldefault('p', " CppAsString2(BOOTSTRAP_SUPERUSERID) ") AS acldefault "
1554 : : "FROM pg_catalog.pg_parameter_acl "
1555 : : "ORDER BY 1");
1556 : :
20 andrew@dunslane.net 1557 [ + + + - ]:GNC 40 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
1439 tgl@sss.pgh.pa.us 1558 :CBC 1 : fprintf(OPF, "--\n-- Role privileges on configuration parameters\n--\n\n");
1559 : :
1560 [ + + ]: 43 : for (i = 0; i < PQntuples(res); i++)
1561 : : {
1562 : 3 : PQExpBuffer buf = createPQExpBuffer();
1563 : 3 : char *parname = PQgetvalue(res, i, 0);
1564 : 3 : char *parowner = PQgetvalue(res, i, 1);
1565 : 3 : char *paracl = PQgetvalue(res, i, 2);
1566 : 3 : char *acldefault = PQgetvalue(res, i, 3);
1567 : : char *fparname;
1568 : :
1569 : : /* needed for buildACLCommands() */
1570 : 3 : fparname = pg_strdup(fmtId(parname));
1571 : :
1572 [ - + ]: 3 : if (!buildACLCommands(fparname, NULL, NULL, "PARAMETER",
1573 : : paracl, acldefault,
1574 : : parowner, "", server_version, buf))
1575 : : {
1439 tgl@sss.pgh.pa.us 1576 :UBC 0 : pg_log_error("could not parse ACL list (%s) for parameter \"%s\"",
1577 : : paracl, parname);
1578 : 0 : PQfinish(conn);
1579 : 0 : exit_nicely(1);
1580 : : }
1581 : :
20 andrew@dunslane.net 1582 [ + - ]:GNC 3 : if (archDumpFormat == archNull)
1583 : 3 : fprintf(OPF, "%s", buf->data);
1584 : : else
20 andrew@dunslane.net 1585 :UNC 0 : ArchiveEntry(fout,
1586 : : nilCatalogId, /* catalog ID */
1587 : : createDumpId(), /* dump ID */
1588 : 0 : ARCHIVE_OPTS(.tag = psprintf("ROLE %s", fmtId(parowner)),
1589 : : .description = "ROLE PROPERTIES",
1590 : : .section = SECTION_PRE_DATA,
1591 : : .createStmt = buf->data));
1592 : :
1439 tgl@sss.pgh.pa.us 1593 :CBC 3 : free(fparname);
1594 : 3 : destroyPQExpBuffer(buf);
1595 : : }
1596 : :
1597 : 40 : PQclear(res);
1598 : :
20 andrew@dunslane.net 1599 [ + + ]:GNC 40 : if (archDumpFormat == archNull)
1600 : 30 : fprintf(OPF, "\n\n");
1439 tgl@sss.pgh.pa.us 1601 :CBC 40 : }
1602 : :
1603 : :
1604 : : /*
1605 : : * Drop tablespaces.
1606 : : */
1607 : : static void
6182 1608 : 11 : dropTablespaces(PGconn *conn)
1609 : : {
1610 : : PGresult *res;
1611 : : int i;
1612 : :
1613 : : /*
1614 : : * Get all tablespaces except built-in ones (which we assume are named
1615 : : * pg_xxx)
1616 : : */
1617 : 11 : res = executeQuery(conn, "SELECT spcname "
1618 : : "FROM pg_catalog.pg_tablespace "
1619 : : "WHERE spcname !~ '^pg_' "
1620 : : "ORDER BY 1");
1621 : :
20 andrew@dunslane.net 1622 [ + - + + ]:GNC 11 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
6182 tgl@sss.pgh.pa.us 1623 :CBC 1 : fprintf(OPF, "--\n-- Drop tablespaces\n--\n\n");
1624 : :
1625 [ + + ]: 32 : for (i = 0; i < PQntuples(res); i++)
1626 : : {
1627 : 21 : char *spcname = PQgetvalue(res, i, 0);
20 andrew@dunslane.net 1628 :GNC 21 : PQExpBuffer delQry = createPQExpBuffer();
1629 : :
1630 [ + + ]: 21 : if (archDumpFormat == archNull)
1631 : : {
1632 : 2 : appendPQExpBuffer(delQry, "DROP TABLESPACE %s%s;\n",
1633 [ - + ]: 1 : if_exists ? "IF EXISTS " : "",
1634 : : fmtId(spcname));
1635 : 1 : fprintf(OPF, "%s", delQry->data);
1636 : : }
1637 : : else
1638 : : {
1639 : 20 : appendPQExpBuffer(delQry, "DROP TABLESPACE IF EXISTS %s;\n",
1640 : : fmtId(spcname));
1641 : 20 : ArchiveEntry(fout,
1642 : : nilCatalogId, /* catalog ID */
1643 : : createDumpId(), /* dump ID */
1644 : 20 : ARCHIVE_OPTS(.tag = psprintf("TABLESPACE %s", fmtId(spcname)),
1645 : : .description = "DROP_GLOBAL",
1646 : : .section = SECTION_PRE_DATA,
1647 : : .createStmt = delQry->data));
1648 : : }
1649 : :
1650 : 21 : destroyPQExpBuffer(delQry);
1651 : : }
1652 : :
6182 tgl@sss.pgh.pa.us 1653 :CBC 11 : PQclear(res);
1654 : :
20 andrew@dunslane.net 1655 [ + + ]:GNC 11 : if (archDumpFormat == archNull)
1656 : 1 : fprintf(OPF, "\n\n");
6182 tgl@sss.pgh.pa.us 1657 :CBC 11 : }
1658 : :
1659 : : /*
1660 : : * Dump tablespaces.
1661 : : */
1662 : : static void
7940 1663 : 35 : dumpTablespaces(PGconn *conn)
1664 : : {
1665 : : PGresult *res;
20 andrew@dunslane.net 1666 :GNC 35 : PQExpBuffer comment_buf = createPQExpBuffer();
1667 : 35 : PQExpBuffer seclabel_buf = createPQExpBuffer();
1668 : : int i;
1669 : :
1670 : : /*
1671 : : * Get all tablespaces except built-in ones (which we assume are named
1672 : : * pg_xxx)
1673 : : */
1552 tgl@sss.pgh.pa.us 1674 :CBC 35 : res = executeQuery(conn, "SELECT oid, spcname, "
1675 : : "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
1676 : : "pg_catalog.pg_tablespace_location(oid), "
1677 : : "spcacl, acldefault('t', spcowner) AS acldefault, "
1678 : : "array_to_string(spcoptions, ', '),"
1679 : : "pg_catalog.shobj_description(oid, 'pg_tablespace') "
1680 : : "FROM pg_catalog.pg_tablespace "
1681 : : "WHERE spcname !~ '^pg_' "
1682 : : "ORDER BY 1");
1683 : :
20 andrew@dunslane.net 1684 [ + + + + ]:GNC 35 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
6989 bruce@momjian.us 1685 :CBC 12 : fprintf(OPF, "--\n-- Tablespaces\n--\n\n");
1686 : :
7940 tgl@sss.pgh.pa.us 1687 [ + + ]: 67 : for (i = 0; i < PQntuples(res); i++)
1688 : : {
1689 : 32 : PQExpBuffer buf = createPQExpBuffer();
2939 1690 : 32 : Oid spcoid = atooid(PQgetvalue(res, i, 0));
5352 rhaas@postgresql.org 1691 : 32 : char *spcname = PQgetvalue(res, i, 1);
1692 : 32 : char *spcowner = PQgetvalue(res, i, 2);
1693 : 32 : char *spclocation = PQgetvalue(res, i, 3);
1694 : 32 : char *spcacl = PQgetvalue(res, i, 4);
1560 tgl@sss.pgh.pa.us 1695 : 32 : char *acldefault = PQgetvalue(res, i, 5);
3528 sfrost@snowman.net 1696 : 32 : char *spcoptions = PQgetvalue(res, i, 6);
1697 : 32 : char *spccomment = PQgetvalue(res, i, 7);
1698 : : char *fspcname;
1699 : :
1700 : : /* needed for buildACLCommands() */
5224 bruce@momjian.us 1701 : 32 : fspcname = pg_strdup(fmtId(spcname));
1702 : :
20 andrew@dunslane.net 1703 :GNC 32 : resetPQExpBuffer(comment_buf);
1704 : 32 : resetPQExpBuffer(seclabel_buf);
1705 : :
1487 rhaas@postgresql.org 1706 [ + + ]:CBC 32 : if (binary_upgrade)
1707 : : {
1487 rhaas@postgresql.org 1708 :GBC 5 : appendPQExpBufferStr(buf, "\n-- For binary upgrade, must preserve pg_tablespace oid\n");
1709 : 5 : appendPQExpBuffer(buf, "SELECT pg_catalog.binary_upgrade_set_next_pg_tablespace_oid('%u'::pg_catalog.oid);\n", spcoid);
1710 : : }
1711 : :
7940 tgl@sss.pgh.pa.us 1712 :CBC 32 : appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
1713 : 32 : appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
1714 : :
4500 heikki.linnakangas@i 1715 : 32 : appendPQExpBufferStr(buf, " LOCATION ");
1716 : :
1717 : : /*
1718 : : * In-place tablespaces use a relative path, and need to be dumped
1719 : : * with an empty string as location.
1720 : : */
949 michael@paquier.xyz 1721 [ + + ]: 32 : if (is_absolute_path(spclocation))
1722 : 22 : appendStringLiteralConn(buf, spclocation, conn);
1723 : : else
1724 : 10 : appendStringLiteralConn(buf, "", conn);
1725 : :
4500 heikki.linnakangas@i 1726 : 32 : appendPQExpBufferStr(buf, ";\n");
1727 : :
5913 rhaas@postgresql.org 1728 [ + - + + ]: 32 : if (spcoptions && spcoptions[0] != '\0')
5913 rhaas@postgresql.org 1729 :GBC 10 : appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n",
1730 : : fspcname, spcoptions);
1731 : :
1732 : : /* tablespaces can't have initprivs */
1733 : :
7940 tgl@sss.pgh.pa.us 1734 [ + - ]:CBC 32 : if (!skip_acls &&
2939 1735 [ - + ]: 32 : !buildACLCommands(fspcname, NULL, NULL, "TABLESPACE",
1736 : : spcacl, acldefault,
1737 : : spcowner, "", server_version, buf))
1738 : : {
2540 peter@eisentraut.org 1739 :UBC 0 : pg_log_error("could not parse ACL list (%s) for tablespace \"%s\"",
1740 : : spcacl, spcname);
7940 tgl@sss.pgh.pa.us 1741 : 0 : PQfinish(conn);
5141 rhaas@postgresql.org 1742 : 0 : exit_nicely(1);
1743 : : }
1744 : :
2971 tgl@sss.pgh.pa.us 1745 [ + - + - :CBC 32 : if (!no_comments && spccomment && spccomment[0] != '\0')
- + ]
1746 : : {
20 andrew@dunslane.net 1747 :UNC 0 : appendPQExpBuffer(comment_buf, "COMMENT ON TABLESPACE %s IS ", fspcname);
1748 : 0 : appendStringLiteralConn(comment_buf, spccomment, conn);
1749 : 0 : appendPQExpBufferStr(comment_buf, ";\n");
1750 : : }
1751 : :
1552 tgl@sss.pgh.pa.us 1752 [ + - ]:CBC 32 : if (!no_security_labels)
5352 rhaas@postgresql.org 1753 : 32 : buildShSecLabels(conn, "pg_tablespace", spcoid,
1754 : : "TABLESPACE", spcname,
1755 : : seclabel_buf);
1756 : :
20 andrew@dunslane.net 1757 [ + + ]:GNC 32 : if (archDumpFormat == archNull)
1758 : : {
1759 : 12 : fprintf(OPF, "%s", buf->data);
1760 : :
1761 [ - + ]: 12 : if (comment_buf->data[0] != '\0')
20 andrew@dunslane.net 1762 :UNC 0 : fprintf(OPF, "%s", comment_buf->data);
1763 : :
20 andrew@dunslane.net 1764 [ - + ]:GNC 12 : if (seclabel_buf->data[0] != '\0')
20 andrew@dunslane.net 1765 :UNC 0 : fprintf(OPF, "%s", seclabel_buf->data);
1766 : : }
1767 : : else
1768 : : {
20 andrew@dunslane.net 1769 :GNC 20 : char *tag = psprintf("TABLESPACE %s", fmtId(fspcname));
1770 : :
1771 : 20 : ArchiveEntry(fout,
1772 : : nilCatalogId, /* catalog ID */
1773 : : createDumpId(), /* dump ID */
1774 : 20 : ARCHIVE_OPTS(.tag = tag,
1775 : : .description = "TABLESPACE",
1776 : : .section = SECTION_PRE_DATA,
1777 : : .createStmt = buf->data));
1778 : :
1779 [ - + ]: 20 : if (comment_buf->data[0] != '\0')
20 andrew@dunslane.net 1780 :UNC 0 : ArchiveEntry(fout,
1781 : : nilCatalogId, /* catalog ID */
1782 : : createDumpId(), /* dump ID */
1783 : 0 : ARCHIVE_OPTS(.tag = tag,
1784 : : .description = "COMMENT",
1785 : : .section = SECTION_PRE_DATA,
1786 : : .createStmt = comment_buf->data));
1787 : :
20 andrew@dunslane.net 1788 [ - + ]:GNC 20 : if (seclabel_buf->data[0] != '\0')
20 andrew@dunslane.net 1789 :UNC 0 : ArchiveEntry(fout,
1790 : : nilCatalogId, /* catalog ID */
1791 : : createDumpId(), /* dump ID */
1792 : 0 : ARCHIVE_OPTS(.tag = tag,
1793 : : .description = "SECURITY LABEL",
1794 : : .section = SECTION_PRE_DATA,
1795 : : .createStmt = seclabel_buf->data));
1796 : : }
1797 : :
7940 tgl@sss.pgh.pa.us 1798 :CBC 32 : free(fspcname);
1799 : 32 : destroyPQExpBuffer(buf);
1800 : : }
1801 : :
1802 : 35 : PQclear(res);
20 andrew@dunslane.net 1803 :GNC 35 : destroyPQExpBuffer(comment_buf);
1804 : 35 : destroyPQExpBuffer(seclabel_buf);
1805 : :
1806 [ + + ]: 35 : if (archDumpFormat == archNull)
1807 : 25 : fprintf(OPF, "\n\n");
7940 tgl@sss.pgh.pa.us 1808 :CBC 35 : }
1809 : :
1810 : :
1811 : : /*
1812 : : * Dump commands to drop each database.
1813 : : */
1814 : : static void
6182 tgl@sss.pgh.pa.us 1815 :GBC 9 : dropDBs(PGconn *conn)
1816 : : {
1817 : : PGresult *res;
1818 : : int i;
1819 : :
1820 : : /*
1821 : : * Skip databases marked not datallowconn, since we'd be unable to connect
1822 : : * to them anyway. This must agree with dumpDatabases().
1823 : : */
3441 1824 : 9 : res = executeQuery(conn,
1825 : : "SELECT datname "
1826 : : "FROM pg_database d "
1827 : : "WHERE datallowconn AND datconnlimit != -2 "
1828 : : "ORDER BY datname");
1829 : :
20 andrew@dunslane.net 1830 [ + - - + ]:GNC 9 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
2974 tgl@sss.pgh.pa.us 1831 :UBC 0 : fprintf(OPF, "--\n-- Drop databases (except postgres and template1)\n--\n\n");
1832 : :
6182 tgl@sss.pgh.pa.us 1833 [ + + ]:GBC 82 : for (i = 0; i < PQntuples(res); i++)
1834 : : {
1835 : 73 : char *dbname = PQgetvalue(res, i, 0);
1836 : :
1837 : : /*
1838 : : * Skip "postgres" and "template1"; dumpDatabases() will deal with
1839 : : * them specially. Also, be sure to skip "template0", even if for
1840 : : * some reason it's not marked !datallowconn.
1841 : : */
1842 [ + + ]: 73 : if (strcmp(dbname, "template1") != 0 &&
2974 1843 [ + - ]: 64 : strcmp(dbname, "template0") != 0 &&
6182 1844 [ + + ]: 64 : strcmp(dbname, "postgres") != 0)
1845 : : {
20 andrew@dunslane.net 1846 [ - + ]:GNC 55 : if (archDumpFormat == archNull)
1847 : : {
5 alvherre@kurilemu.de 1848 :UNC 0 : fprintf(OPF, "DROP DATABASE %s%s;\n",
1849 [ # # ]: 0 : if_exists ? "IF EXISTS " : "",
1850 : : fmtId(dbname));
1851 : : }
1852 : : else
1853 : : {
5 alvherre@kurilemu.de 1854 :GNC 55 : char *stmt = psprintf("DROP DATABASE IF EXISTS %s;\n",
1855 : : fmtId(dbname));
1856 : :
20 andrew@dunslane.net 1857 : 55 : ArchiveEntry(fout,
1858 : : nilCatalogId, /* catalog ID */
1859 : : createDumpId(), /* dump ID */
1860 : 55 : ARCHIVE_OPTS(.tag = psprintf("DATABASE %s", fmtId(dbname)),
1861 : : .description = "DROP_GLOBAL",
1862 : : .section = SECTION_PRE_DATA,
1863 : : .createStmt = stmt));
5 alvherre@kurilemu.de 1864 : 55 : pg_free(stmt);
1865 : : }
1866 : : }
1867 : : }
1868 : :
6182 tgl@sss.pgh.pa.us 1869 :GBC 9 : PQclear(res);
1870 : :
20 andrew@dunslane.net 1871 [ - + ]:GNC 9 : if (archDumpFormat == archNull)
20 andrew@dunslane.net 1872 :UNC 0 : fprintf(OPF, "\n\n");
6182 tgl@sss.pgh.pa.us 1873 :GBC 9 : }
1874 : :
1875 : :
1876 : : /*
1877 : : * Dump user-specific configuration
1878 : : */
1879 : : static void
8600 peter_e@gmx.net 1880 :CBC 206 : dumpUserConfig(PGconn *conn, const char *username)
1881 : : {
1882 : 206 : PQExpBuffer buf = createPQExpBuffer();
1883 : : PGresult *res;
1884 : :
1033 akorotkov@postgresql 1885 : 206 : printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
1886 : : "WHERE setdatabase = 0 AND setrole = "
1887 : : "(SELECT oid FROM %s WHERE rolname = ",
1888 : : role_catalog);
1552 tgl@sss.pgh.pa.us 1889 : 206 : appendStringLiteralConn(buf, username, conn);
1890 : 206 : appendPQExpBufferChar(buf, ')');
1891 : :
1892 : 206 : res = executeQuery(conn, buf->data);
1893 : :
20 andrew@dunslane.net 1894 [ - + - - ]:GNC 206 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
1895 : : {
1896 : : char *sanitized;
1897 : :
216 noah@leadboat.com 1898 :LBC (5) : sanitized = sanitize_line(username, true);
1899 : (5) : fprintf(OPF, "\n--\n-- User Config \"%s\"\n--\n\n", sanitized);
1900 : (5) : free(sanitized);
1901 : : }
1902 : :
1552 tgl@sss.pgh.pa.us 1903 [ - + ]:CBC 206 : for (int i = 0; i < PQntuples(res); i++)
1904 : : {
1552 tgl@sss.pgh.pa.us 1905 :LBC (5) : resetPQExpBuffer(buf);
1033 akorotkov@postgresql 1906 : (5) : makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
1907 : : "ROLE", username, NULL, NULL,
1908 : : buf);
1909 : :
20 andrew@dunslane.net 1910 [ # # ]:UNC 0 : if (archDumpFormat == archNull)
1911 : 0 : fprintf(OPF, "%s", buf->data);
1912 : : else
1913 : 0 : ArchiveEntry(fout,
1914 : : nilCatalogId, /* catalog ID */
1915 : : createDumpId(), /* dump ID */
1916 : 0 : ARCHIVE_OPTS(.tag = psprintf("ROLE %s", fmtId(username)),
1917 : : .description = "ROLE PROPERTIES",
1918 : : .section = SECTION_PRE_DATA,
1919 : : .createStmt = buf->data));
1920 : : }
1921 : :
1552 tgl@sss.pgh.pa.us 1922 :CBC 206 : PQclear(res);
1923 : :
8600 peter_e@gmx.net 1924 : 206 : destroyPQExpBuffer(buf);
1925 : 206 : }
1926 : :
1927 : : /*
1928 : : * Find a list of database names that match the given patterns.
1929 : : * See also expand_table_name_patterns() in pg_dump.c
1930 : : */
1931 : : static void
2571 andrew@dunslane.net 1932 : 42 : expand_dbname_patterns(PGconn *conn,
1933 : : SimpleStringList *patterns,
1934 : : SimpleStringList *names)
1935 : : {
1936 : : PQExpBuffer query;
1937 : : PGresult *res;
1938 : :
1939 [ + + ]: 42 : if (patterns->head == NULL)
1940 : 36 : return; /* nothing to do */
1941 : :
1942 : 6 : query = createPQExpBuffer();
1943 : :
1944 : : /*
1945 : : * The loop below runs multiple SELECTs, which might sometimes result in
1946 : : * duplicate entries in the name list, but we don't care, since all we're
1947 : : * going to do is test membership of the list.
1948 : : */
1949 : :
1950 [ + + ]: 10 : for (SimpleStringListCell *cell = patterns->head; cell; cell = cell->next)
1951 : : {
1952 : : int dotcnt;
1953 : :
2446 drowley@postgresql.o 1954 : 6 : appendPQExpBufferStr(query,
1955 : : "SELECT datname FROM pg_catalog.pg_database n\n");
2571 andrew@dunslane.net 1956 : 6 : processSQLNamePattern(conn, query, cell->val, false,
1957 : : false, NULL, "datname", NULL, NULL, NULL,
1958 : : &dotcnt);
1959 : :
1425 rhaas@postgresql.org 1960 [ + + ]: 6 : if (dotcnt > 0)
1961 : : {
1962 : 2 : pg_log_error("improper qualified name (too many dotted names): %s",
1963 : : cell->val);
1964 : 2 : PQfinish(conn);
1965 : 2 : exit_nicely(1);
1966 : : }
1967 : :
2571 andrew@dunslane.net 1968 : 4 : res = executeQuery(conn, query->data);
1969 [ + + ]: 10 : for (int i = 0; i < PQntuples(res); i++)
1970 : : {
1971 : 6 : simple_string_list_append(names, PQgetvalue(res, i, 0));
1972 : : }
1973 : :
1974 : 4 : PQclear(res);
1975 : 4 : resetPQExpBuffer(query);
1976 : : }
1977 : :
1978 : 4 : destroyPQExpBuffer(query);
1979 : : }
1980 : :
1981 : : /*
1982 : : * Dump contents of databases.
1983 : : */
1984 : : static void
228 1985 : 20 : dumpDatabases(PGconn *conn)
1986 : : {
1987 : : PGresult *res;
1988 : : int i;
1989 : : char db_subdir[MAXPGPATH];
1990 : : char dbfilepath[MAXPGPATH];
20 andrew@dunslane.net 1991 :GNC 20 : FILE *map_file = NULL;
1992 : :
1993 : : /*
1994 : : * Skip databases marked not datallowconn, since we'd be unable to connect
1995 : : * to them anyway. This must agree with dropDBs().
1996 : : *
1997 : : * We arrange for template1 to be processed first, then we process other
1998 : : * DBs in alphabetical order. If we just did them all alphabetically, we
1999 : : * might find ourselves trying to drop the "postgres" database while still
2000 : : * connected to it. This makes trying to run the restore script while
2001 : : * connected to "template1" a bad idea, but there's no fixed order that
2002 : : * doesn't have some failure mode with --clean.
2003 : : */
2974 tgl@sss.pgh.pa.us 2004 :CBC 20 : res = executeQuery(conn,
2005 : : "SELECT datname, oid "
2006 : : "FROM pg_database d "
2007 : : "WHERE datallowconn AND datconnlimit != -2 "
2008 : : "ORDER BY (datname <> 'template1'), datname");
2009 : :
20 andrew@dunslane.net 2010 [ + - + + ]:GNC 20 : if (PQntuples(res) > 0 && archDumpFormat == archNull)
2571 andrew@dunslane.net 2011 :CBC 11 : fprintf(OPF, "--\n-- Databases\n--\n\n");
2012 : :
2013 : : /*
2014 : : * If directory/tar/custom format is specified, create a subdirectory
2015 : : * under the main directory and each database dump file or subdirectory
2016 : : * will be created in that subdirectory by pg_dump.
2017 : : */
20 andrew@dunslane.net 2018 [ + + ]:GNC 20 : if (archDumpFormat != archNull)
2019 : : {
2020 : : char map_file_path[MAXPGPATH];
2021 : :
2022 : 9 : snprintf(db_subdir, MAXPGPATH, "%s/databases", filename);
2023 : :
2024 : : /* Create a subdirectory with 'databases' name under main directory. */
2025 [ - + ]: 9 : if (mkdir(db_subdir, pg_dir_create_mode) != 0)
20 andrew@dunslane.net 2026 :UNC 0 : pg_fatal("could not create directory \"%s\": %m", db_subdir);
2027 : :
20 andrew@dunslane.net 2028 :GNC 9 : snprintf(map_file_path, MAXPGPATH, "%s/map.dat", filename);
2029 : :
2030 : : /* Create a map file (to store dboid and dbname) */
2031 : 9 : map_file = fopen(map_file_path, PG_BINARY_W);
2032 [ - + ]: 9 : if (!map_file)
20 andrew@dunslane.net 2033 :UNC 0 : pg_fatal("could not open file \"%s\": %m", map_file_path);
2034 : :
11 andrew@dunslane.net 2035 :GNC 9 : fprintf(map_file,
2036 : : "#################################################################\n"
2037 : : "# map.dat\n"
2038 : : "#\n"
2039 : : "# This file maps oids to database names\n"
2040 : : "#\n"
2041 : : "# pg_restore will restore all the databases listed here, unless\n"
2042 : : "# otherwise excluded. You can also inhibit restoration of a\n"
2043 : : "# database by removing the line or commenting out the line with\n"
2044 : : "# a # mark.\n"
2045 : : "#################################################################\n");
2046 : : }
2047 : :
8601 peter_e@gmx.net 2048 [ + + ]:CBC 145 : for (i = 0; i < PQntuples(res); i++)
2049 : : {
2974 tgl@sss.pgh.pa.us 2050 : 125 : char *dbname = PQgetvalue(res, i, 0);
2051 : : char *sanitized;
20 andrew@dunslane.net 2052 :GNC 125 : char *oid = PQgetvalue(res, i, 1);
2053 : 125 : const char *create_opts = "";
2054 : : int ret;
2055 : :
2056 : : /* Skip template0, even if it's not marked !datallowconn. */
2974 tgl@sss.pgh.pa.us 2057 [ - + ]:CBC 125 : if (strcmp(dbname, "template0") == 0)
2974 tgl@sss.pgh.pa.us 2058 :UBC 0 : continue;
2059 : :
2060 : : /* Skip any explicitly excluded database */
2571 andrew@dunslane.net 2061 [ + + ]:CBC 125 : if (simple_string_list_member(&database_exclude_names, dbname))
2062 : : {
2441 peter@eisentraut.org 2063 : 6 : pg_log_info("excluding database \"%s\"", dbname);
2571 andrew@dunslane.net 2064 : 6 : continue;
2065 : : }
2066 : :
2441 peter@eisentraut.org 2067 : 119 : pg_log_info("dumping database \"%s\"", dbname);
2068 : :
216 noah@leadboat.com 2069 : 119 : sanitized = sanitize_line(dbname, true);
2070 : :
20 andrew@dunslane.net 2071 [ + + ]:GNC 119 : if (archDumpFormat == archNull)
2072 : 48 : fprintf(OPF, "--\n-- Database \"%s\" dump\n--\n\n", sanitized);
2073 : :
216 noah@leadboat.com 2074 :CBC 119 : free(sanitized);
2075 : :
2076 : : /*
2077 : : * We assume that "template1" and "postgres" already exist in the
2078 : : * target installation. dropDBs() won't have removed them, for fear
2079 : : * of removing the DB the restore script is initially connected to. If
2080 : : * --clean was specified, tell pg_dump to drop and recreate them;
2081 : : * otherwise we'll merely restore their contents. Other databases
2082 : : * should simply be created.
2083 : : */
2974 tgl@sss.pgh.pa.us 2084 [ + + + + ]: 119 : if (strcmp(dbname, "template1") == 0 || strcmp(dbname, "postgres") == 0)
2085 : : {
2086 [ - + ]: 39 : if (output_clean)
2974 tgl@sss.pgh.pa.us 2087 :UBC 0 : create_opts = "--clean --create";
2088 : : /* Since pg_dump won't emit a \connect command, we must */
20 andrew@dunslane.net 2089 [ + + ]:GNC 39 : else if (archDumpFormat == archNull)
2090 : 21 : fprintf(OPF, "\\connect %s\n\n", dbname);
2091 : : else
228 andrew@dunslane.net 2092 :CBC 18 : create_opts = "";
2093 : : }
2094 : : else
2974 tgl@sss.pgh.pa.us 2095 : 80 : create_opts = "--create";
2096 : :
20 andrew@dunslane.net 2097 [ + - + + ]:GNC 119 : if (filename && archDumpFormat == archNull)
6989 bruce@momjian.us 2098 :CBC 48 : fclose(OPF);
2099 : :
2100 : : /*
2101 : : * If this is not a plain format dump, then append dboid and dbname to
2102 : : * the map.dat file.
2103 : : */
20 andrew@dunslane.net 2104 [ + + ]:GNC 119 : if (archDumpFormat != archNull)
2105 : : {
2106 [ + + ]: 71 : if (archDumpFormat == archCustom)
2107 : 8 : snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\".dmp", db_subdir, oid);
2108 [ + + ]: 63 : else if (archDumpFormat == archTar)
2109 : 8 : snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\".tar", db_subdir, oid);
2110 : : else
2111 : 55 : snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\"", db_subdir, oid);
2112 : :
2113 : : /* Put one line entry for dboid and dbname in map file. */
2114 : 71 : fprintf(map_file, "%s %s\n", oid, dbname);
2115 : : }
2116 : :
2117 : 119 : ret = runPgDump(dbname, create_opts, dbfilepath);
8601 peter_e@gmx.net 2118 [ - + ]:CBC 119 : if (ret != 0)
1437 tgl@sss.pgh.pa.us 2119 :UBC 0 : pg_fatal("pg_dump failed on database \"%s\", exiting", dbname);
2120 : :
20 andrew@dunslane.net 2121 [ + - + + ]:GNC 119 : if (filename && archDumpFormat == archNull)
2122 : : {
228 andrew@dunslane.net 2123 :CBC 48 : OPF = fopen(filename, PG_BINARY_A);
6989 bruce@momjian.us 2124 [ - + ]: 48 : if (!OPF)
1437 tgl@sss.pgh.pa.us 2125 :UBC 0 : pg_fatal("could not re-open the output file \"%s\": %m",
2126 : : filename);
2127 : : }
2128 : : }
2129 : :
2130 : : /* Close map file */
20 andrew@dunslane.net 2131 [ + + ]:GNC 20 : if (archDumpFormat != archNull)
2132 : 9 : fclose(map_file);
2133 : :
8601 peter_e@gmx.net 2134 :CBC 20 : PQclear(res);
2135 : 20 : }
2136 : :
2137 : :
2138 : :
2139 : : /*
2140 : : * Run pg_dump on dbname, with specified options.
2141 : : */
2142 : : static int
20 andrew@dunslane.net 2143 :GNC 119 : runPgDump(const char *dbname, const char *create_opts, char *dbfile)
2144 : : {
2145 : : PQExpBufferData connstrbuf;
2146 : : PQExpBufferData cmd;
2147 : : int ret;
2148 : :
984 peter@eisentraut.org 2149 :CBC 119 : initPQExpBuffer(&connstrbuf);
2150 : 119 : initPQExpBuffer(&cmd);
2151 : :
2152 : : /*
2153 : : * If this is not a plain format dump, then append file name and dump
2154 : : * format to the pg_dump command to get archive dump.
2155 : : */
20 andrew@dunslane.net 2156 [ + + ]:GNC 119 : if (archDumpFormat != archNull)
2157 : : {
2158 : 71 : printfPQExpBuffer(&cmd, "\"%s\" %s -f %s %s", pg_dump_bin,
2159 : 71 : pgdumpopts->data, dbfile, create_opts);
2160 : :
2161 [ + + ]: 71 : if (archDumpFormat == archDirectory)
2162 : 55 : appendPQExpBufferStr(&cmd, " --format=directory ");
2163 [ + + ]: 16 : else if (archDumpFormat == archCustom)
2164 : 8 : appendPQExpBufferStr(&cmd, " --format=custom ");
2165 [ + - ]: 8 : else if (archDumpFormat == archTar)
2166 : 8 : appendPQExpBufferStr(&cmd, " --format=tar ");
2167 : : }
2168 : : else
2169 : : {
2170 : 48 : printfPQExpBuffer(&cmd, "\"%s\" %s %s", pg_dump_bin,
2171 : 48 : pgdumpopts->data, create_opts);
2172 : :
2173 : : /*
2174 : : * If we have a filename, use the undocumented plain-append pg_dump
2175 : : * format.
2176 : : */
2177 [ + - ]: 48 : if (filename)
2178 : 48 : appendPQExpBufferStr(&cmd, " -Fa ");
2179 : : else
20 andrew@dunslane.net 2180 :UNC 0 : appendPQExpBufferStr(&cmd, " -Fp ");
2181 : : }
2182 : :
2183 : : /*
2184 : : * Append the database name to the already-constructed stem of connection
2185 : : * string.
2186 : : */
984 peter@eisentraut.org 2187 :CBC 119 : appendPQExpBuffer(&connstrbuf, "%s dbname=", connstr);
2188 : 119 : appendConnStrVal(&connstrbuf, dbname);
2189 : :
2190 : 119 : appendShellString(&cmd, connstrbuf.data);
2191 : :
2192 : 119 : pg_log_info("running \"%s\"", cmd.data);
2193 : :
1294 tgl@sss.pgh.pa.us 2194 : 119 : fflush(NULL);
2195 : :
984 peter@eisentraut.org 2196 : 119 : ret = system(cmd.data);
2197 : :
2198 : 119 : termPQExpBuffer(&cmd);
2199 : 119 : termPQExpBuffer(&connstrbuf);
2200 : :
8601 peter_e@gmx.net 2201 : 119 : return ret;
2202 : : }
2203 : :
2204 : : /*
2205 : : * buildShSecLabels
2206 : : *
2207 : : * Build SECURITY LABEL command(s) for a shared object
2208 : : *
2209 : : * The caller has to provide object type and identity in two separate formats:
2210 : : * catalog_name (e.g., "pg_database") and object OID, as well as
2211 : : * type name (e.g., "DATABASE") and object name (not pre-quoted).
2212 : : *
2213 : : * The command(s) are appended to "buffer".
2214 : : */
2215 : : static void
2939 tgl@sss.pgh.pa.us 2216 : 238 : buildShSecLabels(PGconn *conn, const char *catalog_name, Oid objectId,
2217 : : const char *objtype, const char *objname,
2218 : : PQExpBuffer buffer)
2219 : : {
5026 bruce@momjian.us 2220 : 238 : PQExpBuffer sql = createPQExpBuffer();
2221 : : PGresult *res;
2222 : :
2028 peter@eisentraut.org 2223 : 238 : buildShSecLabelQuery(catalog_name, objectId, sql);
5352 rhaas@postgresql.org 2224 : 238 : res = executeQuery(conn, sql->data);
2939 tgl@sss.pgh.pa.us 2225 : 238 : emitShSecLabels(conn, res, buffer, objtype, objname);
2226 : :
5352 rhaas@postgresql.org 2227 : 238 : PQclear(res);
2228 : 238 : destroyPQExpBuffer(sql);
2229 : 238 : }
2230 : :
2231 : : /*
2232 : : * As above for a SQL command (which returns nothing).
2233 : : */
2234 : : static void
7532 tgl@sss.pgh.pa.us 2235 : 51 : executeCommand(PGconn *conn, const char *query)
2236 : : {
2237 : : PGresult *res;
2238 : :
2540 peter@eisentraut.org 2239 : 51 : pg_log_info("executing %s", query);
2240 : :
7532 tgl@sss.pgh.pa.us 2241 : 51 : res = PQexec(conn, query);
2242 [ + - - + ]: 102 : if (!res ||
2243 : 51 : PQresultStatus(res) != PGRES_COMMAND_OK)
2244 : : {
2540 peter@eisentraut.org 2245 :UBC 0 : pg_log_error("query failed: %s", PQerrorMessage(conn));
1437 tgl@sss.pgh.pa.us 2246 : 0 : pg_log_error_detail("Query was: %s", query);
7532 2247 : 0 : PQfinish(conn);
5141 rhaas@postgresql.org 2248 : 0 : exit_nicely(1);
2249 : : }
2250 : :
7532 tgl@sss.pgh.pa.us 2251 :CBC 51 : PQclear(res);
2252 : 51 : }
2253 : :
2254 : :
2255 : : /*
2256 : : * check_for_invalid_global_names
2257 : : *
2258 : : * Check that no database, role, or tablespace name contains a newline or
2259 : : * carriage return character. Such characters in database names would break
2260 : : * the map.dat file format used for non-plain-text dumps. Role and tablespace
2261 : : * names are also checked because such characters were forbidden starting in
2262 : : * v19.
2263 : : *
2264 : : * Excluded databases are skipped since they won't appear in map.dat.
2265 : : */
2266 : : static void
20 andrew@dunslane.net 2267 :UNC 0 : check_for_invalid_global_names(PGconn *conn,
2268 : : SimpleStringList *database_exclude_names)
2269 : : {
2270 : : PGresult *res;
2271 : : int i;
2272 : : PQExpBuffer names;
2273 : 0 : int count = 0;
2274 : :
2275 : 0 : res = executeQuery(conn,
2276 : : "SELECT datname AS objname, 'database' AS objtype "
2277 : : "FROM pg_catalog.pg_database "
2278 : : "WHERE datallowconn AND datconnlimit != -2 "
2279 : : "UNION ALL "
2280 : : "SELECT rolname AS objname, 'role' AS objtype "
2281 : : "FROM pg_catalog.pg_roles "
2282 : : "UNION ALL "
2283 : : "SELECT spcname AS objname, 'tablespace' AS objtype "
2284 : : "FROM pg_catalog.pg_tablespace");
2285 : :
2286 : 0 : names = createPQExpBuffer();
2287 : :
2288 [ # # ]: 0 : for (i = 0; i < PQntuples(res); i++)
2289 : : {
2290 : 0 : char *objname = PQgetvalue(res, i, 0);
2291 : 0 : char *objtype = PQgetvalue(res, i, 1);
2292 : :
2293 : : /* Skip excluded databases since they won't be in map.dat */
2294 [ # # # # ]: 0 : if (strcmp(objtype, "database") == 0 &&
2295 : 0 : simple_string_list_member(database_exclude_names, objname))
2296 : 0 : continue;
2297 : :
2298 [ # # ]: 0 : if (strpbrk(objname, "\n\r"))
2299 : : {
2300 : 0 : appendPQExpBuffer(names, " %s: \"", objtype);
2301 [ # # ]: 0 : for (char *p = objname; *p; p++)
2302 : : {
2303 [ # # ]: 0 : if (*p == '\n')
2304 : 0 : appendPQExpBufferStr(names, "\\n");
2305 [ # # ]: 0 : else if (*p == '\r')
2306 : 0 : appendPQExpBufferStr(names, "\\r");
2307 : : else
2308 : 0 : appendPQExpBufferChar(names, *p);
2309 : : }
2310 : 0 : appendPQExpBufferStr(names, "\"\n");
2311 : 0 : count++;
2312 : : }
2313 : : }
2314 : :
2315 : 0 : PQclear(res);
2316 : :
2317 [ # # ]: 0 : if (count > 0)
2318 : 0 : pg_fatal("database, role, or tablespace names contain a newline or carriage return character, which is not supported in non-plain-text dumps:\n%s",
2319 : : names->data);
2320 : :
2321 : 0 : destroyPQExpBuffer(names);
2322 : 0 : }
2323 : :
2324 : :
2325 : : /*
2326 : : * dumpTimestamp
2327 : : */
2328 : : static void
4158 tgl@sss.pgh.pa.us 2329 :CBC 4 : dumpTimestamp(const char *msg)
2330 : : {
2331 : : char buf[64];
7868 bruce@momjian.us 2332 : 4 : time_t now = time(NULL);
2333 : :
4158 tgl@sss.pgh.pa.us 2334 [ + - ]: 4 : if (strftime(buf, sizeof(buf), PGDUMP_STRFTIME_FMT, localtime(&now)) != 0)
6989 bruce@momjian.us 2335 : 4 : fprintf(OPF, "-- %s %s\n\n", msg, buf);
7951 2336 : 4 : }
2337 : :
2338 : : /*
2339 : : * read_dumpall_filters - retrieve database identifier patterns from file
2340 : : *
2341 : : * Parse the specified filter file for include and exclude patterns, and add
2342 : : * them to the relevant lists. If the filename is "-" then filters will be
2343 : : * read from STDIN rather than a file.
2344 : : *
2345 : : * At the moment, the only allowed filter is for database exclusion.
2346 : : */
2347 : : static void
837 dgustafsson@postgres 2348 : 5 : read_dumpall_filters(const char *filename, SimpleStringList *pattern)
2349 : : {
2350 : : FilterStateData fstate;
2351 : : char *objname;
2352 : : FilterCommandType comtype;
2353 : : FilterObjectType objtype;
2354 : :
2355 : 5 : filter_init(&fstate, filename, exit);
2356 : :
2357 [ + + ]: 12 : while (filter_read_item(&fstate, &objname, &comtype, &objtype))
2358 : : {
2359 [ - + ]: 3 : if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
2360 : : {
836 dgustafsson@postgres 2361 :UBC 0 : pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
2362 : : "include",
2363 : : filter_object_type_name(objtype));
837 2364 : 0 : exit_nicely(1);
2365 : : }
2366 : :
837 dgustafsson@postgres 2367 [ - + + - ]:CBC 3 : switch (objtype)
2368 : : {
837 dgustafsson@postgres 2369 :UBC 0 : case FILTER_OBJECT_TYPE_NONE:
2370 : 0 : break;
837 dgustafsson@postgres 2371 :CBC 1 : case FILTER_OBJECT_TYPE_FUNCTION:
2372 : : case FILTER_OBJECT_TYPE_INDEX:
2373 : : case FILTER_OBJECT_TYPE_TABLE_DATA:
2374 : : case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
2375 : : case FILTER_OBJECT_TYPE_TRIGGER:
2376 : : case FILTER_OBJECT_TYPE_EXTENSION:
2377 : : case FILTER_OBJECT_TYPE_FOREIGN_DATA:
2378 : : case FILTER_OBJECT_TYPE_SCHEMA:
2379 : : case FILTER_OBJECT_TYPE_TABLE:
2380 : : case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
836 2381 : 1 : pg_log_filter_error(&fstate, _("unsupported filter object"));
837 2382 : 1 : exit_nicely(1);
2383 : : break;
2384 : :
2385 : 2 : case FILTER_OBJECT_TYPE_DATABASE:
2386 : 2 : simple_string_list_append(pattern, objname);
2387 : 2 : break;
2388 : : }
2389 : :
2390 [ - + ]: 2 : if (objname)
2391 : 2 : free(objname);
2392 : : }
2393 : :
2394 : 2 : filter_free(&fstate);
2395 : 2 : }
2396 : :
2397 : : /*
2398 : : * parseDumpFormat
2399 : : *
2400 : : * This will validate dump formats.
2401 : : */
2402 : : static ArchiveFormat
20 andrew@dunslane.net 2403 :GNC 46 : parseDumpFormat(const char *format)
2404 : : {
2405 : : ArchiveFormat archDumpFormat;
2406 : :
2407 [ - + ]: 46 : if (pg_strcasecmp(format, "c") == 0)
20 andrew@dunslane.net 2408 :UNC 0 : archDumpFormat = archCustom;
20 andrew@dunslane.net 2409 [ + + ]:GNC 46 : else if (pg_strcasecmp(format, "custom") == 0)
2410 : 1 : archDumpFormat = archCustom;
2411 [ + + ]: 45 : else if (pg_strcasecmp(format, "d") == 0)
2412 : 3 : archDumpFormat = archDirectory;
2413 [ + + ]: 42 : else if (pg_strcasecmp(format, "directory") == 0)
2414 : 8 : archDumpFormat = archDirectory;
2415 [ + + ]: 34 : else if (pg_strcasecmp(format, "p") == 0)
2416 : 32 : archDumpFormat = archNull;
2417 [ - + ]: 2 : else if (pg_strcasecmp(format, "plain") == 0)
20 andrew@dunslane.net 2418 :UNC 0 : archDumpFormat = archNull;
20 andrew@dunslane.net 2419 [ - + ]:GNC 2 : else if (pg_strcasecmp(format, "t") == 0)
20 andrew@dunslane.net 2420 :UNC 0 : archDumpFormat = archTar;
20 andrew@dunslane.net 2421 [ + + ]:GNC 2 : else if (pg_strcasecmp(format, "tar") == 0)
2422 : 1 : archDumpFormat = archTar;
2423 : : else
2424 : 1 : pg_fatal("unrecognized output format \"%s\"; please specify \"c\", \"d\", \"p\", or \"t\"",
2425 : : format);
2426 : :
2427 : 45 : return archDumpFormat;
2428 : : }
2429 : :
2430 : : /*
2431 : : * createDumpId
2432 : : *
2433 : : * Return the next dumpId.
2434 : : */
2435 : : static int
2436 : 395 : createDumpId(void)
2437 : : {
2438 : 395 : return ++dumpIdVal;
2439 : : }
|