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