LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dumpall.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19beta1 Lines: 71.5 % 764 546
Test Date: 2026-06-19 14:16:39 Functions: 94.1 % 17 16
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * pg_dumpall.c
       4              :  *
       5              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       6              :  * Portions Copyright (c) 1994, Regents of the University of California
       7              :  *
       8              :  * pg_dumpall forces all pg_dump output to be text, since it also outputs
       9              :  * text into the same output stream.
      10              :  *
      11              :  * src/bin/pg_dump/pg_dumpall.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : 
      16              : #include "postgres_fe.h"
      17              : 
      18              : #include <time.h>
      19              : #include <unistd.h>
      20              : 
      21              : #include "catalog/pg_authid_d.h"
      22              : #include "common/connect.h"
      23              : #include "common/file_perm.h"
      24              : #include "common/file_utils.h"
      25              : #include "common/hashfn_unstable.h"
      26              : #include "common/logging.h"
      27              : #include "common/string.h"
      28              : #include "connectdb.h"
      29              : #include "dumputils.h"
      30              : #include "fe_utils/string_utils.h"
      31              : #include "filter.h"
      32              : #include "getopt_long.h"
      33              : 
      34              : /* version string we expect back from pg_dump */
      35              : #define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
      36              : 
      37              : typedef struct
      38              : {
      39              :     uint32      status;
      40              :     uint32      hashval;
      41              :     char       *rolename;
      42              : } RoleNameEntry;
      43              : 
      44              : #define SH_PREFIX   rolename
      45              : #define SH_ELEMENT_TYPE RoleNameEntry
      46              : #define SH_KEY_TYPE char *
      47              : #define SH_KEY      rolename
      48              : #define SH_HASH_KEY(tb, key)    hash_string(key)
      49              : #define SH_EQUAL(tb, a, b)      (strcmp(a, b) == 0)
      50              : #define SH_STORE_HASH
      51              : #define SH_GET_HASH(tb, a)      (a)->hashval
      52              : #define SH_SCOPE    static inline
      53              : #define SH_RAW_ALLOCATOR    pg_malloc0
      54              : #define SH_DECLARE
      55              : #define SH_DEFINE
      56              : #include "lib/simplehash.h"
      57              : 
      58              : static void help(void);
      59              : 
      60              : static void dropRoles(PGconn *conn);
      61              : static void dumpRoles(PGconn *conn);
      62              : static void dumpRoleMembership(PGconn *conn);
      63              : static void dumpRoleGUCPrivs(PGconn *conn);
      64              : static void dropTablespaces(PGconn *conn);
      65              : static void dumpTablespaces(PGconn *conn);
      66              : static void dropDBs(PGconn *conn);
      67              : static void dumpUserConfig(PGconn *conn, const char *username);
      68              : static void dumpDatabases(PGconn *conn);
      69              : static void dumpTimestamp(const char *msg);
      70              : static int  runPgDump(const char *dbname, const char *create_opts);
      71              : static void buildShSecLabels(PGconn *conn,
      72              :                              const char *catalog_name, Oid objectId,
      73              :                              const char *objtype, const char *objname,
      74              :                              PQExpBuffer buffer);
      75              : static void executeCommand(PGconn *conn, const char *query);
      76              : static void expand_dbname_patterns(PGconn *conn, SimpleStringList *patterns,
      77              :                                    SimpleStringList *names);
      78              : static void read_dumpall_filters(const char *filename, SimpleStringList *pattern);
      79              : 
      80              : static char pg_dump_bin[MAXPGPATH];
      81              : static PQExpBuffer pgdumpopts;
      82              : static const char *connstr = "";
      83              : static bool output_clean = false;
      84              : static bool skip_acls = false;
      85              : static bool verbose = false;
      86              : static bool dosync = true;
      87              : 
      88              : static int  binary_upgrade = 0;
      89              : static int  column_inserts = 0;
      90              : static int  disable_dollar_quoting = 0;
      91              : static int  disable_triggers = 0;
      92              : static int  if_exists = 0;
      93              : static int  inserts = 0;
      94              : static int  no_table_access_method = 0;
      95              : static int  no_tablespaces = 0;
      96              : static int  use_setsessauth = 0;
      97              : static int  no_comments = 0;
      98              : static int  no_policies = 0;
      99              : static int  no_publications = 0;
     100              : static int  no_security_labels = 0;
     101              : static int  no_data = 0;
     102              : static int  no_schema = 0;
     103              : static int  no_statistics = 0;
     104              : static int  no_subscriptions = 0;
     105              : static int  no_toast_compression = 0;
     106              : static int  no_unlogged_table_data = 0;
     107              : static int  no_role_passwords = 0;
     108              : static int  with_statistics = 0;
     109              : static int  server_version;
     110              : static int  load_via_partition_root = 0;
     111              : static int  on_conflict_do_nothing = 0;
     112              : static int  statistics_only = 0;
     113              : static int  sequence_data = 0;
     114              : 
     115              : static char role_catalog[10];
     116              : #define PG_AUTHID "pg_authid"
     117              : #define PG_ROLES  "pg_roles "
     118              : 
     119              : static FILE *OPF;
     120              : static char *filename = NULL;
     121              : 
     122              : static SimpleStringList database_exclude_patterns = {NULL, NULL};
     123              : static SimpleStringList database_exclude_names = {NULL, NULL};
     124              : 
     125              : static char *restrict_key;
     126              : 
     127              : int
     128           66 : main(int argc, char *argv[])
     129              : {
     130              :     static struct option long_options[] = {
     131              :         {"data-only", no_argument, NULL, 'a'},
     132              :         {"clean", no_argument, NULL, 'c'},
     133              :         {"encoding", required_argument, NULL, 'E'},
     134              :         {"file", required_argument, NULL, 'f'},
     135              :         {"globals-only", no_argument, NULL, 'g'},
     136              :         {"host", required_argument, NULL, 'h'},
     137              :         {"dbname", required_argument, NULL, 'd'},
     138              :         {"database", required_argument, NULL, 'l'},
     139              :         {"no-owner", no_argument, NULL, 'O'},
     140              :         {"port", required_argument, NULL, 'p'},
     141              :         {"roles-only", no_argument, NULL, 'r'},
     142              :         {"schema-only", no_argument, NULL, 's'},
     143              :         {"superuser", required_argument, NULL, 'S'},
     144              :         {"tablespaces-only", no_argument, NULL, 't'},
     145              :         {"username", required_argument, NULL, 'U'},
     146              :         {"verbose", no_argument, NULL, 'v'},
     147              :         {"no-password", no_argument, NULL, 'w'},
     148              :         {"password", no_argument, NULL, 'W'},
     149              :         {"no-privileges", no_argument, NULL, 'x'},
     150              :         {"no-acl", no_argument, NULL, 'x'},
     151              : 
     152              :         /*
     153              :          * the following options don't have an equivalent short option letter
     154              :          */
     155              :         {"attribute-inserts", no_argument, &column_inserts, 1},
     156              :         {"binary-upgrade", no_argument, &binary_upgrade, 1},
     157              :         {"column-inserts", no_argument, &column_inserts, 1},
     158              :         {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
     159              :         {"disable-triggers", no_argument, &disable_triggers, 1},
     160              :         {"exclude-database", required_argument, NULL, 6},
     161              :         {"extra-float-digits", required_argument, NULL, 5},
     162              :         {"if-exists", no_argument, &if_exists, 1},
     163              :         {"inserts", no_argument, &inserts, 1},
     164              :         {"lock-wait-timeout", required_argument, NULL, 2},
     165              :         {"no-table-access-method", no_argument, &no_table_access_method, 1},
     166              :         {"no-tablespaces", no_argument, &no_tablespaces, 1},
     167              :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     168              :         {"load-via-partition-root", no_argument, &load_via_partition_root, 1},
     169              :         {"role", required_argument, NULL, 3},
     170              :         {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
     171              :         {"no-comments", no_argument, &no_comments, 1},
     172              :         {"no-data", no_argument, &no_data, 1},
     173              :         {"no-policies", no_argument, &no_policies, 1},
     174              :         {"no-publications", no_argument, &no_publications, 1},
     175              :         {"no-role-passwords", no_argument, &no_role_passwords, 1},
     176              :         {"no-schema", no_argument, &no_schema, 1},
     177              :         {"no-security-labels", no_argument, &no_security_labels, 1},
     178              :         {"no-subscriptions", no_argument, &no_subscriptions, 1},
     179              :         {"no-statistics", no_argument, &no_statistics, 1},
     180              :         {"no-sync", no_argument, NULL, 4},
     181              :         {"no-toast-compression", no_argument, &no_toast_compression, 1},
     182              :         {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
     183              :         {"on-conflict-do-nothing", no_argument, &on_conflict_do_nothing, 1},
     184              :         {"rows-per-insert", required_argument, NULL, 7},
     185              :         {"statistics", no_argument, &with_statistics, 1},
     186              :         {"statistics-only", no_argument, &statistics_only, 1},
     187              :         {"filter", required_argument, NULL, 8},
     188              :         {"sequence-data", no_argument, &sequence_data, 1},
     189              :         {"restrict-key", required_argument, NULL, 9},
     190              : 
     191              :         {NULL, 0, NULL, 0}
     192              :     };
     193              : 
     194           66 :     char       *pghost = NULL;
     195           66 :     char       *pgport = NULL;
     196           66 :     char       *pguser = NULL;
     197           66 :     char       *pgdb = NULL;
     198           66 :     char       *use_role = NULL;
     199           66 :     const char *dumpencoding = NULL;
     200           66 :     trivalue    prompt_password = TRI_DEFAULT;
     201           66 :     bool        data_only = false;
     202           66 :     bool        globals_only = false;
     203           66 :     bool        roles_only = false;
     204           66 :     bool        tablespaces_only = false;
     205              :     PGconn     *conn;
     206              :     int         encoding;
     207              :     int         c,
     208              :                 ret;
     209              :     int         optindex;
     210              : 
     211           66 :     pg_logging_init(argv[0]);
     212           66 :     pg_logging_set_level(PG_LOG_WARNING);
     213           66 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     214           66 :     progname = get_progname(argv[0]);
     215              : 
     216           66 :     if (argc > 1)
     217              :     {
     218           66 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     219              :         {
     220            1 :             help();
     221            1 :             exit_nicely(0);
     222              :         }
     223           65 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     224              :         {
     225           20 :             puts("pg_dumpall (PostgreSQL) " PG_VERSION);
     226           20 :             exit_nicely(0);
     227              :         }
     228              :     }
     229              : 
     230           45 :     if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR,
     231              :                                pg_dump_bin)) < 0)
     232              :     {
     233              :         char        full_path[MAXPGPATH];
     234              : 
     235            0 :         if (find_my_exec(argv[0], full_path) < 0)
     236            0 :             strlcpy(full_path, progname, sizeof(full_path));
     237              : 
     238            0 :         if (ret == -1)
     239            0 :             pg_fatal("program \"%s\" is needed by %s but was not found in the same directory as \"%s\"",
     240              :                      "pg_dump", progname, full_path);
     241              :         else
     242            0 :             pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s",
     243              :                      "pg_dump", full_path, progname);
     244              :     }
     245              : 
     246           45 :     pgdumpopts = createPQExpBuffer();
     247              : 
     248          244 :     while ((c = getopt_long(argc, argv, "acd:E:f:gh:l:Op:rsS:tU:vwWx", long_options, &optindex)) != -1)
     249              :     {
     250          203 :         switch (c)
     251              :         {
     252            1 :             case 'a':
     253            1 :                 data_only = true;
     254            1 :                 appendPQExpBufferStr(pgdumpopts, " -a");
     255            1 :                 break;
     256              : 
     257            2 :             case 'c':
     258            2 :                 output_clean = true;
     259            2 :                 break;
     260              : 
     261            9 :             case 'd':
     262            9 :                 connstr = pg_strdup(optarg);
     263            9 :                 break;
     264              : 
     265            0 :             case 'E':
     266            0 :                 dumpencoding = pg_strdup(optarg);
     267            0 :                 appendPQExpBufferStr(pgdumpopts, " -E ");
     268            0 :                 appendShellString(pgdumpopts, optarg);
     269            0 :                 break;
     270              : 
     271           34 :             case 'f':
     272           34 :                 filename = pg_strdup(optarg);
     273           34 :                 appendPQExpBufferStr(pgdumpopts, " -f ");
     274           34 :                 appendShellString(pgdumpopts, filename);
     275           34 :                 break;
     276              : 
     277           19 :             case 'g':
     278           19 :                 globals_only = true;
     279           19 :                 break;
     280              : 
     281           12 :             case 'h':
     282           12 :                 pghost = pg_strdup(optarg);
     283           12 :                 break;
     284              : 
     285            0 :             case 'l':
     286            0 :                 pgdb = pg_strdup(optarg);
     287            0 :                 break;
     288              : 
     289            0 :             case 'O':
     290            0 :                 appendPQExpBufferStr(pgdumpopts, " -O");
     291            0 :                 break;
     292              : 
     293           20 :             case 'p':
     294           20 :                 pgport = pg_strdup(optarg);
     295           20 :                 break;
     296              : 
     297            7 :             case 'r':
     298            7 :                 roles_only = true;
     299            7 :                 break;
     300              : 
     301            0 :             case 's':
     302            0 :                 appendPQExpBufferStr(pgdumpopts, " -s");
     303            0 :                 break;
     304              : 
     305            0 :             case 'S':
     306            0 :                 appendPQExpBufferStr(pgdumpopts, " -S ");
     307            0 :                 appendShellString(pgdumpopts, optarg);
     308            0 :                 break;
     309              : 
     310            2 :             case 't':
     311            2 :                 tablespaces_only = true;
     312            2 :                 break;
     313              : 
     314           18 :             case 'U':
     315           18 :                 pguser = pg_strdup(optarg);
     316           18 :                 break;
     317              : 
     318            2 :             case 'v':
     319            2 :                 verbose = true;
     320            2 :                 pg_logging_increase_verbosity();
     321            2 :                 appendPQExpBufferStr(pgdumpopts, " -v");
     322            2 :                 break;
     323              : 
     324            0 :             case 'w':
     325            0 :                 prompt_password = TRI_NO;
     326            0 :                 appendPQExpBufferStr(pgdumpopts, " -w");
     327            0 :                 break;
     328              : 
     329            0 :             case 'W':
     330            0 :                 prompt_password = TRI_YES;
     331            0 :                 appendPQExpBufferStr(pgdumpopts, " -W");
     332            0 :                 break;
     333              : 
     334            0 :             case 'x':
     335            0 :                 skip_acls = true;
     336            0 :                 appendPQExpBufferStr(pgdumpopts, " -x");
     337            0 :                 break;
     338              : 
     339           32 :             case 0:
     340           32 :                 break;
     341              : 
     342            0 :             case 2:
     343            0 :                 appendPQExpBufferStr(pgdumpopts, " --lock-wait-timeout ");
     344            0 :                 appendShellString(pgdumpopts, optarg);
     345            0 :                 break;
     346              : 
     347            0 :             case 3:
     348            0 :                 use_role = pg_strdup(optarg);
     349            0 :                 appendPQExpBufferStr(pgdumpopts, " --role ");
     350            0 :                 appendShellString(pgdumpopts, use_role);
     351            0 :                 break;
     352              : 
     353           28 :             case 4:
     354           28 :                 dosync = false;
     355           28 :                 appendPQExpBufferStr(pgdumpopts, " --no-sync");
     356           28 :                 break;
     357              : 
     358            0 :             case 5:
     359            0 :                 appendPQExpBufferStr(pgdumpopts, " --extra-float-digits ");
     360            0 :                 appendShellString(pgdumpopts, optarg);
     361            0 :                 break;
     362              : 
     363            5 :             case 6:
     364            5 :                 simple_string_list_append(&database_exclude_patterns, optarg);
     365            5 :                 break;
     366              : 
     367            0 :             case 7:
     368            0 :                 appendPQExpBufferStr(pgdumpopts, " --rows-per-insert ");
     369            0 :                 appendShellString(pgdumpopts, optarg);
     370            0 :                 break;
     371              : 
     372            5 :             case 8:
     373            5 :                 read_dumpall_filters(optarg, &database_exclude_patterns);
     374            2 :                 break;
     375              : 
     376            6 :             case 9:
     377            6 :                 restrict_key = pg_strdup(optarg);
     378            6 :                 appendPQExpBufferStr(pgdumpopts, " --restrict-key ");
     379            6 :                 appendShellString(pgdumpopts, optarg);
     380            6 :                 break;
     381              : 
     382            1 :             default:
     383              :                 /* getopt_long already emitted a complaint */
     384            1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     385            1 :                 exit_nicely(1);
     386              :         }
     387              :     }
     388              : 
     389              :     /* Complain if any arguments remain */
     390           41 :     if (optind < argc)
     391              :     {
     392            1 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     393              :                      argv[optind]);
     394            1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     395            1 :         exit_nicely(1);
     396              :     }
     397              : 
     398           40 :     if (database_exclude_patterns.head != NULL &&
     399            5 :         (globals_only || roles_only || tablespaces_only))
     400              :     {
     401            2 :         pg_log_error("option %s cannot be used together with %s, %s, or %s",
     402              :                      "--exclude-database",
     403              :                      "-g/--globals-only", "-r/--roles-only", "-t/--tablespaces-only");
     404            2 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     405            2 :         exit_nicely(1);
     406              :     }
     407              : 
     408              :     /* Make sure the user hasn't specified a mix of globals-only options */
     409           38 :     if (globals_only && roles_only)
     410              :     {
     411            1 :         pg_log_error("options %s and %s cannot be used together",
     412              :                      "-g/--globals-only", "-r/--roles-only");
     413            1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     414            1 :         exit_nicely(1);
     415              :     }
     416              : 
     417           37 :     if (globals_only && tablespaces_only)
     418              :     {
     419            1 :         pg_log_error("options %s and %s cannot be used together",
     420              :                      "-g/--globals-only", "-t/--tablespaces-only");
     421            1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     422            1 :         exit_nicely(1);
     423              :     }
     424              : 
     425           36 :     if (if_exists && !output_clean)
     426            1 :         pg_fatal("option %s requires option %s",
     427              :                  "--if-exists", "-c/--clean");
     428              : 
     429              :     /* --clean and --data-only are incompatible */
     430           35 :     if (output_clean && data_only)
     431            1 :         pg_fatal("options %s and %s cannot be used together",
     432              :                  "-c/--clean", "-a/--data-only");
     433              : 
     434           34 :     if (roles_only && tablespaces_only)
     435              :     {
     436            1 :         pg_log_error("options %s and %s cannot be used together",
     437              :                      "-r/--roles-only", "-t/--tablespaces-only");
     438            1 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     439            1 :         exit_nicely(1);
     440              :     }
     441              : 
     442              :     /*
     443              :      * If password values are not required in the dump, switch to using
     444              :      * pg_roles which is equally useful, just more likely to have unrestricted
     445              :      * access than pg_authid.
     446              :      */
     447           33 :     if (no_role_passwords)
     448            0 :         sprintf(role_catalog, "%s", PG_ROLES);
     449              :     else
     450           33 :         sprintf(role_catalog, "%s", PG_AUTHID);
     451              : 
     452              :     /* Add long options to the pg_dump argument list */
     453           33 :     if (binary_upgrade)
     454           12 :         appendPQExpBufferStr(pgdumpopts, " --binary-upgrade");
     455           33 :     if (column_inserts)
     456            0 :         appendPQExpBufferStr(pgdumpopts, " --column-inserts");
     457           33 :     if (disable_dollar_quoting)
     458            0 :         appendPQExpBufferStr(pgdumpopts, " --disable-dollar-quoting");
     459           33 :     if (disable_triggers)
     460            0 :         appendPQExpBufferStr(pgdumpopts, " --disable-triggers");
     461           33 :     if (inserts)
     462            0 :         appendPQExpBufferStr(pgdumpopts, " --inserts");
     463           33 :     if (no_table_access_method)
     464            0 :         appendPQExpBufferStr(pgdumpopts, " --no-table-access-method");
     465           33 :     if (no_tablespaces)
     466            0 :         appendPQExpBufferStr(pgdumpopts, " --no-tablespaces");
     467           33 :     if (quote_all_identifiers)
     468           12 :         appendPQExpBufferStr(pgdumpopts, " --quote-all-identifiers");
     469           33 :     if (load_via_partition_root)
     470            0 :         appendPQExpBufferStr(pgdumpopts, " --load-via-partition-root");
     471           33 :     if (use_setsessauth)
     472            0 :         appendPQExpBufferStr(pgdumpopts, " --use-set-session-authorization");
     473           33 :     if (no_comments)
     474            0 :         appendPQExpBufferStr(pgdumpopts, " --no-comments");
     475           33 :     if (no_data)
     476            0 :         appendPQExpBufferStr(pgdumpopts, " --no-data");
     477           33 :     if (no_policies)
     478            0 :         appendPQExpBufferStr(pgdumpopts, " --no-policies");
     479           33 :     if (no_publications)
     480            0 :         appendPQExpBufferStr(pgdumpopts, " --no-publications");
     481           33 :     if (no_security_labels)
     482            0 :         appendPQExpBufferStr(pgdumpopts, " --no-security-labels");
     483           33 :     if (no_schema)
     484            0 :         appendPQExpBufferStr(pgdumpopts, " --no-schema");
     485           33 :     if (no_statistics)
     486            2 :         appendPQExpBufferStr(pgdumpopts, " --no-statistics");
     487           33 :     if (no_subscriptions)
     488            0 :         appendPQExpBufferStr(pgdumpopts, " --no-subscriptions");
     489           33 :     if (no_toast_compression)
     490            0 :         appendPQExpBufferStr(pgdumpopts, " --no-toast-compression");
     491           33 :     if (no_unlogged_table_data)
     492            3 :         appendPQExpBufferStr(pgdumpopts, " --no-unlogged-table-data");
     493           33 :     if (with_statistics)
     494            2 :         appendPQExpBufferStr(pgdumpopts, " --statistics");
     495           33 :     if (on_conflict_do_nothing)
     496            0 :         appendPQExpBufferStr(pgdumpopts, " --on-conflict-do-nothing");
     497           33 :     if (statistics_only)
     498            0 :         appendPQExpBufferStr(pgdumpopts, " --statistics-only");
     499           33 :     if (sequence_data)
     500            0 :         appendPQExpBufferStr(pgdumpopts, " --sequence-data");
     501              : 
     502              :     /*
     503              :      * If you don't provide a restrict key, one will be appointed for you.
     504              :      */
     505           33 :     if (!restrict_key)
     506           27 :         restrict_key = generate_restrict_key();
     507           33 :     if (!restrict_key)
     508            0 :         pg_fatal("could not generate restrict key");
     509           33 :     if (!valid_restrict_key(restrict_key))
     510            0 :         pg_fatal("invalid restrict key");
     511              : 
     512              :     /*
     513              :      * If there was a database specified on the command line, use that,
     514              :      * otherwise try to connect to database "postgres", and failing that
     515              :      * "template1".
     516              :      */
     517           33 :     if (pgdb)
     518              :     {
     519            0 :         conn = ConnectDatabase(pgdb, connstr, pghost, pgport, pguser,
     520              :                                prompt_password, false,
     521              :                                progname, &connstr, &server_version, NULL, NULL);
     522              : 
     523            0 :         if (!conn)
     524            0 :             pg_fatal("could not connect to database \"%s\"", pgdb);
     525              :     }
     526              :     else
     527              :     {
     528           33 :         conn = ConnectDatabase("postgres", connstr, pghost, pgport, pguser,
     529              :                                prompt_password, false,
     530              :                                progname, &connstr, &server_version, NULL, NULL);
     531           33 :         if (!conn)
     532            0 :             conn = ConnectDatabase("template1", connstr, pghost, pgport, pguser,
     533              :                                    prompt_password, true,
     534              :                                    progname, &connstr, &server_version, NULL, NULL);
     535              : 
     536           33 :         if (!conn)
     537              :         {
     538            0 :             pg_log_error("could not connect to databases \"postgres\" or \"template1\"\n"
     539              :                          "Please specify an alternative database.");
     540            0 :             pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     541            0 :             exit_nicely(1);
     542              :         }
     543              :     }
     544              : 
     545              :     /*
     546              :      * Get a list of database names that match the exclude patterns
     547              :      */
     548           33 :     expand_dbname_patterns(conn, &database_exclude_patterns,
     549              :                            &database_exclude_names);
     550              : 
     551              :     /*
     552              :      * Open the output file if required, otherwise use stdout
     553              :      */
     554           31 :     if (filename)
     555              :     {
     556           30 :         OPF = fopen(filename, PG_BINARY_W);
     557           30 :         if (!OPF)
     558            0 :             pg_fatal("could not open output file \"%s\": %m",
     559              :                      filename);
     560              :     }
     561              :     else
     562            1 :         OPF = stdout;
     563              : 
     564              :     /*
     565              :      * Set the client encoding if requested.
     566              :      */
     567           31 :     if (dumpencoding)
     568              :     {
     569            0 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
     570            0 :             pg_fatal("invalid client encoding \"%s\" specified",
     571              :                      dumpencoding);
     572              :     }
     573              : 
     574              :     /*
     575              :      * Force standard_conforming_strings on, just in case we are dumping from
     576              :      * an old server that has it disabled.  Without this, literals in views,
     577              :      * expressions, etc, would be incorrect for modern servers.
     578              :      */
     579           31 :     executeCommand(conn, "SET standard_conforming_strings = on");
     580              : 
     581              :     /*
     582              :      * Get the active encoding, so we know how to escape strings.
     583              :      */
     584           31 :     encoding = PQclientEncoding(conn);
     585           31 :     setFmtEncoding(encoding);
     586              : 
     587              :     /* Set the role if requested */
     588           31 :     if (use_role)
     589              :     {
     590            0 :         PQExpBuffer query = createPQExpBuffer();
     591              : 
     592            0 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
     593            0 :         executeCommand(conn, query->data);
     594            0 :         destroyPQExpBuffer(query);
     595              :     }
     596              : 
     597              :     /* Force quoting of all identifiers if requested. */
     598           31 :     if (quote_all_identifiers)
     599           12 :         executeCommand(conn, "SET quote_all_identifiers = true");
     600              : 
     601           31 :     fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n");
     602           31 :     if (verbose)
     603            2 :         dumpTimestamp("Started on");
     604              : 
     605              :     /*
     606              :      * Enter restricted mode to block any unexpected psql meta-commands.  A
     607              :      * malicious source might try to inject a variety of things via bogus
     608              :      * responses to queries.  While we cannot prevent such sources from
     609              :      * affecting the destination at restore time, we can block psql
     610              :      * meta-commands so that the client machine that runs psql with the dump
     611              :      * output remains unaffected.
     612              :      */
     613           31 :     fprintf(OPF, "\\restrict %s\n\n", restrict_key);
     614              : 
     615              :     /*
     616              :      * We used to emit \connect postgres here, but that served no purpose
     617              :      * other than to break things for installations without a postgres
     618              :      * database.  Everything we're restoring here is a global, so whichever
     619              :      * database we're connected to at the moment is fine.
     620              :      */
     621              : 
     622              :     /* Restore will need to write to the target cluster */
     623           31 :     fprintf(OPF, "SET default_transaction_read_only = off;\n\n");
     624              : 
     625              :     /* Replicate encoding and standard_conforming_strings in output */
     626           31 :     fprintf(OPF, "SET client_encoding = '%s';\n",
     627              :             pg_encoding_to_char(encoding));
     628           31 :     fprintf(OPF, "SET standard_conforming_strings = on;\n");
     629           31 :     fprintf(OPF, "\n");
     630              : 
     631           31 :     if (!data_only && !statistics_only && !no_schema)
     632              :     {
     633              :         /*
     634              :          * If asked to --clean, do that first.  We can avoid detailed
     635              :          * dependency analysis because databases never depend on each other,
     636              :          * and tablespaces never depend on each other.  Roles could have
     637              :          * grants to each other, but DROP ROLE will clean those up silently.
     638              :          */
     639           31 :         if (output_clean)
     640              :         {
     641            1 :             if (!globals_only && !roles_only && !tablespaces_only)
     642            0 :                 dropDBs(conn);
     643              : 
     644            1 :             if (!roles_only && !no_tablespaces)
     645            1 :                 dropTablespaces(conn);
     646              : 
     647            1 :             if (!tablespaces_only)
     648            1 :                 dropRoles(conn);
     649              :         }
     650              : 
     651              :         /*
     652              :          * Now create objects as requested.  Be careful that option logic here
     653              :          * is the same as for drops above.
     654              :          */
     655           31 :         if (!tablespaces_only)
     656              :         {
     657              :             /* Dump roles (users) */
     658           31 :             dumpRoles(conn);
     659              : 
     660              :             /* Dump role memberships */
     661           31 :             dumpRoleMembership(conn);
     662              : 
     663              :             /* Dump role GUC privileges */
     664           31 :             if (server_version >= 150000 && !skip_acls)
     665           31 :                 dumpRoleGUCPrivs(conn);
     666              :         }
     667              : 
     668              :         /* Dump tablespaces */
     669           31 :         if (!roles_only && !no_tablespaces)
     670           26 :             dumpTablespaces(conn);
     671              :     }
     672              : 
     673              :     /*
     674              :      * Exit restricted mode just before dumping the databases.  pg_dump will
     675              :      * handle entering restricted mode again as appropriate.
     676              :      */
     677           31 :     fprintf(OPF, "\\unrestrict %s\n\n", restrict_key);
     678              : 
     679           31 :     if (!globals_only && !roles_only && !tablespaces_only)
     680           11 :         dumpDatabases(conn);
     681              : 
     682           31 :     PQfinish(conn);
     683              : 
     684           31 :     if (verbose)
     685            2 :         dumpTimestamp("Completed on");
     686           31 :     fprintf(OPF, "--\n-- PostgreSQL database cluster dump complete\n--\n\n");
     687              : 
     688           31 :     if (filename)
     689              :     {
     690           30 :         fclose(OPF);
     691              : 
     692              :         /* sync the resulting file, errors are not fatal */
     693           30 :         if (dosync)
     694            3 :             (void) fsync_fname(filename, false);
     695              :     }
     696              : 
     697           31 :     exit_nicely(0);
     698              : }
     699              : 
     700              : 
     701              : static void
     702            1 : help(void)
     703              : {
     704            1 :     printf(_("%s exports a PostgreSQL database cluster as an SQL script.\n\n"), progname);
     705            1 :     printf(_("Usage:\n"));
     706            1 :     printf(_("  %s [OPTION]...\n"), progname);
     707              : 
     708            1 :     printf(_("\nGeneral options:\n"));
     709            1 :     printf(_("  -f, --file=FILENAME          output file name\n"));
     710            1 :     printf(_("  -v, --verbose                verbose mode\n"));
     711            1 :     printf(_("  -V, --version                output version information, then exit\n"));
     712            1 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
     713            1 :     printf(_("  -?, --help                   show this help, then exit\n"));
     714            1 :     printf(_("\nOptions controlling the output content:\n"));
     715            1 :     printf(_("  -a, --data-only              dump only the data, not the schema or statistics\n"));
     716            1 :     printf(_("  -c, --clean                  clean (drop) databases before recreating\n"));
     717            1 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
     718            1 :     printf(_("  -g, --globals-only           dump only global objects, no databases\n"));
     719            1 :     printf(_("  -O, --no-owner               skip restoration of object ownership\n"));
     720            1 :     printf(_("  -r, --roles-only             dump only roles, no databases or tablespaces\n"));
     721            1 :     printf(_("  -s, --schema-only            dump only the schema, no data or statistics\n"));
     722            1 :     printf(_("  -S, --superuser=NAME         superuser user name to use in the dump\n"));
     723            1 :     printf(_("  -t, --tablespaces-only       dump only tablespaces, no databases or roles\n"));
     724            1 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
     725            1 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
     726            1 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
     727            1 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
     728            1 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
     729            1 :     printf(_("  --exclude-database=PATTERN   exclude databases whose name matches PATTERN\n"));
     730            1 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
     731            1 :     printf(_("  --filter=FILENAME            exclude databases based on expressions in FILENAME\n"));
     732            1 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
     733            1 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
     734            1 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
     735            1 :     printf(_("  --no-comments                do not dump comment commands\n"));
     736            1 :     printf(_("  --no-data                    do not dump data\n"));
     737            1 :     printf(_("  --no-policies                do not dump row security policies\n"));
     738            1 :     printf(_("  --no-publications            do not dump publications\n"));
     739            1 :     printf(_("  --no-role-passwords          do not dump passwords for roles\n"));
     740            1 :     printf(_("  --no-schema                  do not dump schema\n"));
     741            1 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
     742            1 :     printf(_("  --no-statistics              do not dump statistics\n"));
     743            1 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
     744            1 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
     745            1 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
     746            1 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
     747            1 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
     748            1 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
     749            1 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
     750            1 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
     751            1 :     printf(_("  --restrict-key=RESTRICT_KEY  use provided string as psql \\restrict key\n"));
     752            1 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
     753            1 :     printf(_("  --sequence-data              include sequence data in dump\n"));
     754            1 :     printf(_("  --statistics                 dump the statistics\n"));
     755            1 :     printf(_("  --statistics-only            dump only the statistics, not schema or data\n"));
     756            1 :     printf(_("  --use-set-session-authorization\n"
     757              :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
     758              :              "                               ALTER OWNER commands to set ownership\n"));
     759              : 
     760            1 :     printf(_("\nConnection options:\n"));
     761            1 :     printf(_("  -d, --dbname=CONNSTR     connect using connection string\n"));
     762            1 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
     763            1 :     printf(_("  -l, --database=DBNAME    alternative default database\n"));
     764            1 :     printf(_("  -p, --port=PORT          database server port number\n"));
     765            1 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
     766            1 :     printf(_("  -w, --no-password        never prompt for password\n"));
     767            1 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
     768            1 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
     769              : 
     770            1 :     printf(_("\nIf -f/--file is not used, then the SQL script will be written to the standard\n"
     771              :              "output.\n\n"));
     772            1 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     773            1 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
     774            1 : }
     775              : 
     776              : 
     777              : /*
     778              :  * Drop roles
     779              :  */
     780              : static void
     781            1 : dropRoles(PGconn *conn)
     782              : {
     783            1 :     PQExpBuffer buf = createPQExpBuffer();
     784              :     PGresult   *res;
     785              :     int         i_rolname;
     786              :     int         i;
     787              : 
     788            1 :     if (server_version >= 90600)
     789            1 :         printfPQExpBuffer(buf,
     790              :                           "SELECT rolname "
     791              :                           "FROM %s "
     792              :                           "WHERE rolname !~ '^pg_' "
     793              :                           "ORDER BY 1", role_catalog);
     794              :     else
     795            0 :         printfPQExpBuffer(buf,
     796              :                           "SELECT rolname "
     797              :                           "FROM %s "
     798              :                           "ORDER BY 1", role_catalog);
     799              : 
     800            1 :     res = executeQuery(conn, buf->data);
     801              : 
     802            1 :     i_rolname = PQfnumber(res, "rolname");
     803              : 
     804            1 :     if (PQntuples(res) > 0)
     805            1 :         fprintf(OPF, "--\n-- Drop roles\n--\n\n");
     806              : 
     807            4 :     for (i = 0; i < PQntuples(res); i++)
     808              :     {
     809              :         const char *rolename;
     810              : 
     811            3 :         rolename = PQgetvalue(res, i, i_rolname);
     812              : 
     813            6 :         fprintf(OPF, "DROP ROLE %s%s;\n",
     814            3 :                 if_exists ? "IF EXISTS " : "",
     815              :                 fmtId(rolename));
     816              :     }
     817              : 
     818            1 :     PQclear(res);
     819            1 :     destroyPQExpBuffer(buf);
     820              : 
     821            1 :     fprintf(OPF, "\n\n");
     822            1 : }
     823              : 
     824              : /*
     825              :  * Dump roles
     826              :  */
     827              : static void
     828           31 : dumpRoles(PGconn *conn)
     829              : {
     830           31 :     PQExpBuffer buf = createPQExpBuffer();
     831              :     PGresult   *res;
     832              :     int         i_oid,
     833              :                 i_rolname,
     834              :                 i_rolsuper,
     835              :                 i_rolinherit,
     836              :                 i_rolcreaterole,
     837              :                 i_rolcreatedb,
     838              :                 i_rolcanlogin,
     839              :                 i_rolconnlimit,
     840              :                 i_rolpassword,
     841              :                 i_rolvaliduntil,
     842              :                 i_rolreplication,
     843              :                 i_rolbypassrls,
     844              :                 i_rolcomment,
     845              :                 i_is_current_user;
     846              :     int         i;
     847              : 
     848              :     /*
     849              :      * Notes: rolconfig is dumped later, and pg_authid must be used for
     850              :      * extracting rolcomment regardless of role_catalog.
     851              :      */
     852           31 :     if (server_version >= 90600)
     853           31 :         printfPQExpBuffer(buf,
     854              :                           "SELECT oid, rolname, rolsuper, rolinherit, "
     855              :                           "rolcreaterole, rolcreatedb, "
     856              :                           "rolcanlogin, rolconnlimit, rolpassword, "
     857              :                           "rolvaliduntil, rolreplication, rolbypassrls, "
     858              :                           "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
     859              :                           "rolname = current_user AS is_current_user "
     860              :                           "FROM %s "
     861              :                           "WHERE rolname !~ '^pg_' "
     862              :                           "ORDER BY 2", role_catalog);
     863            0 :     else if (server_version >= 90500)
     864            0 :         printfPQExpBuffer(buf,
     865              :                           "SELECT oid, rolname, rolsuper, rolinherit, "
     866              :                           "rolcreaterole, rolcreatedb, "
     867              :                           "rolcanlogin, rolconnlimit, rolpassword, "
     868              :                           "rolvaliduntil, rolreplication, rolbypassrls, "
     869              :                           "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
     870              :                           "rolname = current_user AS is_current_user "
     871              :                           "FROM %s "
     872              :                           "ORDER BY 2", role_catalog);
     873              :     else
     874            0 :         printfPQExpBuffer(buf,
     875              :                           "SELECT oid, rolname, rolsuper, rolinherit, "
     876              :                           "rolcreaterole, rolcreatedb, "
     877              :                           "rolcanlogin, rolconnlimit, rolpassword, "
     878              :                           "rolvaliduntil, rolreplication, "
     879              :                           "false as rolbypassrls, "
     880              :                           "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, "
     881              :                           "rolname = current_user AS is_current_user "
     882              :                           "FROM %s "
     883              :                           "ORDER BY 2", role_catalog);
     884              : 
     885           31 :     res = executeQuery(conn, buf->data);
     886              : 
     887           31 :     i_oid = PQfnumber(res, "oid");
     888           31 :     i_rolname = PQfnumber(res, "rolname");
     889           31 :     i_rolsuper = PQfnumber(res, "rolsuper");
     890           31 :     i_rolinherit = PQfnumber(res, "rolinherit");
     891           31 :     i_rolcreaterole = PQfnumber(res, "rolcreaterole");
     892           31 :     i_rolcreatedb = PQfnumber(res, "rolcreatedb");
     893           31 :     i_rolcanlogin = PQfnumber(res, "rolcanlogin");
     894           31 :     i_rolconnlimit = PQfnumber(res, "rolconnlimit");
     895           31 :     i_rolpassword = PQfnumber(res, "rolpassword");
     896           31 :     i_rolvaliduntil = PQfnumber(res, "rolvaliduntil");
     897           31 :     i_rolreplication = PQfnumber(res, "rolreplication");
     898           31 :     i_rolbypassrls = PQfnumber(res, "rolbypassrls");
     899           31 :     i_rolcomment = PQfnumber(res, "rolcomment");
     900           31 :     i_is_current_user = PQfnumber(res, "is_current_user");
     901              : 
     902           31 :     if (PQntuples(res) > 0)
     903           31 :         fprintf(OPF, "--\n-- Roles\n--\n\n");
     904              : 
     905          108 :     for (i = 0; i < PQntuples(res); i++)
     906              :     {
     907              :         const char *rolename;
     908              :         Oid         auth_oid;
     909              : 
     910           77 :         auth_oid = atooid(PQgetvalue(res, i, i_oid));
     911           77 :         rolename = PQgetvalue(res, i, i_rolname);
     912              : 
     913           77 :         if (strncmp(rolename, "pg_", 3) == 0)
     914              :         {
     915            0 :             pg_log_warning("role name starting with \"pg_\" skipped (%s)",
     916              :                            rolename);
     917            0 :             continue;
     918              :         }
     919              : 
     920           77 :         resetPQExpBuffer(buf);
     921              : 
     922           77 :         if (binary_upgrade)
     923              :         {
     924           22 :             appendPQExpBufferStr(buf, "\n-- For binary upgrade, must preserve pg_authid.oid\n");
     925           22 :             appendPQExpBuffer(buf,
     926              :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_authid_oid('%u'::pg_catalog.oid);\n\n",
     927              :                               auth_oid);
     928              :         }
     929              : 
     930              :         /*
     931              :          * We dump CREATE ROLE followed by ALTER ROLE to ensure that the role
     932              :          * will acquire the right properties even if it already exists (ie, it
     933              :          * won't hurt for the CREATE to fail).  This is particularly important
     934              :          * for the role we are connected as, since even with --clean we will
     935              :          * have failed to drop it.  binary_upgrade cannot generate any errors,
     936              :          * so we assume the current role is already created.
     937              :          */
     938           77 :         if (!binary_upgrade ||
     939           22 :             strcmp(PQgetvalue(res, i, i_is_current_user), "f") == 0)
     940           65 :             appendPQExpBuffer(buf, "CREATE ROLE %s;\n", fmtId(rolename));
     941           77 :         appendPQExpBuffer(buf, "ALTER ROLE %s WITH", fmtId(rolename));
     942              : 
     943           77 :         if (strcmp(PQgetvalue(res, i, i_rolsuper), "t") == 0)
     944           55 :             appendPQExpBufferStr(buf, " SUPERUSER");
     945              :         else
     946           22 :             appendPQExpBufferStr(buf, " NOSUPERUSER");
     947              : 
     948           77 :         if (strcmp(PQgetvalue(res, i, i_rolinherit), "t") == 0)
     949           77 :             appendPQExpBufferStr(buf, " INHERIT");
     950              :         else
     951            0 :             appendPQExpBufferStr(buf, " NOINHERIT");
     952              : 
     953           77 :         if (strcmp(PQgetvalue(res, i, i_rolcreaterole), "t") == 0)
     954           55 :             appendPQExpBufferStr(buf, " CREATEROLE");
     955              :         else
     956           22 :             appendPQExpBufferStr(buf, " NOCREATEROLE");
     957              : 
     958           77 :         if (strcmp(PQgetvalue(res, i, i_rolcreatedb), "t") == 0)
     959           55 :             appendPQExpBufferStr(buf, " CREATEDB");
     960              :         else
     961           22 :             appendPQExpBufferStr(buf, " NOCREATEDB");
     962              : 
     963           77 :         if (strcmp(PQgetvalue(res, i, i_rolcanlogin), "t") == 0)
     964           56 :             appendPQExpBufferStr(buf, " LOGIN");
     965              :         else
     966           21 :             appendPQExpBufferStr(buf, " NOLOGIN");
     967              : 
     968           77 :         if (strcmp(PQgetvalue(res, i, i_rolreplication), "t") == 0)
     969           31 :             appendPQExpBufferStr(buf, " REPLICATION");
     970              :         else
     971           46 :             appendPQExpBufferStr(buf, " NOREPLICATION");
     972              : 
     973           77 :         if (strcmp(PQgetvalue(res, i, i_rolbypassrls), "t") == 0)
     974           31 :             appendPQExpBufferStr(buf, " BYPASSRLS");
     975              :         else
     976           46 :             appendPQExpBufferStr(buf, " NOBYPASSRLS");
     977              : 
     978           77 :         if (strcmp(PQgetvalue(res, i, i_rolconnlimit), "-1") != 0)
     979            0 :             appendPQExpBuffer(buf, " CONNECTION LIMIT %s",
     980              :                               PQgetvalue(res, i, i_rolconnlimit));
     981              : 
     982              : 
     983           77 :         if (!PQgetisnull(res, i, i_rolpassword) && !no_role_passwords)
     984              :         {
     985            0 :             appendPQExpBufferStr(buf, " PASSWORD ");
     986            0 :             appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolpassword), conn);
     987              :         }
     988              : 
     989           77 :         if (!PQgetisnull(res, i, i_rolvaliduntil))
     990            0 :             appendPQExpBuffer(buf, " VALID UNTIL '%s'",
     991              :                               PQgetvalue(res, i, i_rolvaliduntil));
     992              : 
     993           77 :         appendPQExpBufferStr(buf, ";\n");
     994              : 
     995           77 :         if (!no_comments && !PQgetisnull(res, i, i_rolcomment))
     996              :         {
     997            0 :             appendPQExpBuffer(buf, "COMMENT ON ROLE %s IS ", fmtId(rolename));
     998            0 :             appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolcomment), conn);
     999            0 :             appendPQExpBufferStr(buf, ";\n");
    1000              :         }
    1001              : 
    1002           77 :         if (!no_security_labels)
    1003           77 :             buildShSecLabels(conn, "pg_authid", auth_oid,
    1004              :                              "ROLE", rolename,
    1005              :                              buf);
    1006              : 
    1007           77 :         fprintf(OPF, "%s", buf->data);
    1008              :     }
    1009              : 
    1010              :     /*
    1011              :      * Dump configuration settings for roles after all roles have been dumped.
    1012              :      * We do it this way because config settings for roles could mention the
    1013              :      * names of other roles.
    1014              :      */
    1015           31 :     if (PQntuples(res) > 0)
    1016           31 :         fprintf(OPF, "\n--\n-- User Configurations\n--\n");
    1017              : 
    1018          108 :     for (i = 0; i < PQntuples(res); i++)
    1019           77 :         dumpUserConfig(conn, PQgetvalue(res, i, i_rolname));
    1020              : 
    1021           31 :     PQclear(res);
    1022              : 
    1023           31 :     fprintf(OPF, "\n\n");
    1024              : 
    1025           31 :     destroyPQExpBuffer(buf);
    1026           31 : }
    1027              : 
    1028              : 
    1029              : /*
    1030              :  * Dump role memberships.
    1031              :  *
    1032              :  * Note: we expect dumpRoles already created all the roles, but there is
    1033              :  * no membership yet.
    1034              :  */
    1035              : static void
    1036           31 : dumpRoleMembership(PGconn *conn)
    1037              : {
    1038           31 :     PQExpBuffer buf = createPQExpBuffer();
    1039           31 :     PQExpBuffer optbuf = createPQExpBuffer();
    1040              :     PGresult   *res;
    1041           31 :     int         start = 0,
    1042              :                 end,
    1043              :                 total;
    1044              :     bool        dump_grantors;
    1045              :     bool        dump_grant_options;
    1046              :     int         i_role;
    1047              :     int         i_member;
    1048              :     int         i_grantor;
    1049              :     int         i_roleid;
    1050              :     int         i_memberid;
    1051              :     int         i_grantorid;
    1052              :     int         i_admin_option;
    1053              :     int         i_inherit_option;
    1054              :     int         i_set_option;
    1055              : 
    1056              :     /*
    1057              :      * Previous versions of PostgreSQL didn't used to track the grantor very
    1058              :      * carefully in the backend, and the grantor could be any user even if
    1059              :      * they didn't have ADMIN OPTION on the role, or a user that no longer
    1060              :      * existed. To avoid dump and restore failures, don't dump the grantor
    1061              :      * when talking to an old server version.
    1062              :      *
    1063              :      * Also, in older versions the roleid and/or member could be role OIDs
    1064              :      * that no longer exist.  If we find such cases, print a warning and skip
    1065              :      * the entry.
    1066              :      */
    1067           31 :     dump_grantors = (server_version >= 160000);
    1068              : 
    1069              :     /*
    1070              :      * Previous versions of PostgreSQL also did not have grant-level options.
    1071              :      */
    1072           31 :     dump_grant_options = (server_version >= 160000);
    1073              : 
    1074              :     /* Generate and execute query. */
    1075           31 :     printfPQExpBuffer(buf, "SELECT ur.rolname AS role, "
    1076              :                       "um.rolname AS member, "
    1077              :                       "ug.rolname AS grantor, "
    1078              :                       "a.roleid AS roleid, "
    1079              :                       "a.member AS memberid, "
    1080              :                       "a.grantor AS grantorid, "
    1081              :                       "a.admin_option");
    1082           31 :     if (dump_grant_options)
    1083           31 :         appendPQExpBufferStr(buf, ", a.inherit_option, a.set_option");
    1084           31 :     appendPQExpBuffer(buf, " FROM pg_auth_members a "
    1085              :                       "LEFT JOIN %s ur on ur.oid = a.roleid "
    1086              :                       "LEFT JOIN %s um on um.oid = a.member "
    1087              :                       "LEFT JOIN %s ug on ug.oid = a.grantor "
    1088              :                       "WHERE NOT (ur.rolname ~ '^pg_' AND um.rolname ~ '^pg_')"
    1089              :                       "ORDER BY 1,2,3", role_catalog, role_catalog, role_catalog);
    1090           31 :     res = executeQuery(conn, buf->data);
    1091           31 :     i_role = PQfnumber(res, "role");
    1092           31 :     i_member = PQfnumber(res, "member");
    1093           31 :     i_grantor = PQfnumber(res, "grantor");
    1094           31 :     i_roleid = PQfnumber(res, "roleid");
    1095           31 :     i_memberid = PQfnumber(res, "memberid");
    1096           31 :     i_grantorid = PQfnumber(res, "grantorid");
    1097           31 :     i_admin_option = PQfnumber(res, "admin_option");
    1098           31 :     i_inherit_option = PQfnumber(res, "inherit_option");
    1099           31 :     i_set_option = PQfnumber(res, "set_option");
    1100              : 
    1101           31 :     if (PQntuples(res) > 0)
    1102            0 :         fprintf(OPF, "--\n-- Role memberships\n--\n\n");
    1103              : 
    1104              :     /*
    1105              :      * We can't dump these GRANT commands in arbitrary order, because a role
    1106              :      * that is named as a grantor must already have ADMIN OPTION on the role
    1107              :      * for which it is granting permissions, except for the bootstrap
    1108              :      * superuser, who can always be named as the grantor.
    1109              :      *
    1110              :      * We handle this by considering these grants role by role. For each role,
    1111              :      * we initially consider the only allowable grantor to be the bootstrap
    1112              :      * superuser. Every time we grant ADMIN OPTION on the role to some user,
    1113              :      * that user also becomes an allowable grantor. We make repeated passes
    1114              :      * over the grants for the role, each time dumping those whose grantors
    1115              :      * are allowable and which we haven't done yet. Eventually this should let
    1116              :      * us dump all the grants.
    1117              :      */
    1118           31 :     total = PQntuples(res);
    1119           31 :     while (start < total)
    1120              :     {
    1121            0 :         char       *role = PQgetvalue(res, start, i_role);
    1122              :         int         i;
    1123              :         bool       *done;
    1124              :         int         remaining;
    1125            0 :         int         prev_remaining = 0;
    1126              :         rolename_hash *ht;
    1127              : 
    1128              :         /* If we hit a null roleid, we're done (nulls sort to the end). */
    1129            0 :         if (PQgetisnull(res, start, i_role))
    1130              :         {
    1131              :             /* translator: %s represents a numeric role OID */
    1132            0 :             pg_log_warning("ignoring role grant for missing role with OID %s",
    1133              :                            PQgetvalue(res, start, i_roleid));
    1134            0 :             break;
    1135              :         }
    1136              : 
    1137              :         /* All memberships for a single role should be adjacent. */
    1138            0 :         for (end = start; end < total; ++end)
    1139              :         {
    1140              :             char       *otherrole;
    1141              : 
    1142            0 :             otherrole = PQgetvalue(res, end, i_role);
    1143            0 :             if (strcmp(role, otherrole) != 0)
    1144            0 :                 break;
    1145              :         }
    1146              : 
    1147            0 :         remaining = end - start;
    1148            0 :         done = pg_malloc0_array(bool, remaining);
    1149              : 
    1150              :         /*
    1151              :          * We use a hashtable to track the member names that have been granted
    1152              :          * admin option.  Usually a hashtable is overkill, but sometimes not.
    1153              :          */
    1154            0 :         ht = rolename_create(remaining, NULL);
    1155              : 
    1156              :         /*
    1157              :          * Make repeated passes over the grants for this role until all have
    1158              :          * been dumped.
    1159              :          */
    1160            0 :         while (remaining > 0)
    1161              :         {
    1162              :             /*
    1163              :              * We should make progress on every iteration, because a notional
    1164              :              * graph whose vertices are grants and whose edges point from
    1165              :              * grantors to members should be connected and acyclic. If we fail
    1166              :              * to make progress, either we or the server have messed up.
    1167              :              */
    1168            0 :             if (remaining == prev_remaining)
    1169              :             {
    1170            0 :                 pg_log_error("could not find a legal dump ordering for memberships in role \"%s\"",
    1171              :                              role);
    1172            0 :                 PQfinish(conn);
    1173            0 :                 exit_nicely(1);
    1174              :             }
    1175            0 :             prev_remaining = remaining;
    1176              : 
    1177              :             /* Make one pass over the grants for this role. */
    1178            0 :             for (i = start; i < end; ++i)
    1179              :             {
    1180              :                 char       *member;
    1181              :                 char       *grantorid;
    1182            0 :                 char       *grantor = NULL;
    1183            0 :                 bool        dump_this_grantor = dump_grantors;
    1184            0 :                 char       *set_option = "true";
    1185              :                 char       *admin_option;
    1186              :                 bool        found;
    1187              : 
    1188              :                 /* If we already did this grant, don't do it again. */
    1189            0 :                 if (done[i - start])
    1190            0 :                     continue;
    1191              : 
    1192              :                 /* Complain about, then ignore, entries for unknown members. */
    1193            0 :                 if (PQgetisnull(res, i, i_member))
    1194              :                 {
    1195              :                     /* translator: %s represents a numeric role OID */
    1196            0 :                     pg_log_warning("ignoring role grant to missing role with OID %s",
    1197              :                                    PQgetvalue(res, i, i_memberid));
    1198            0 :                     done[i - start] = true;
    1199            0 :                     --remaining;
    1200            0 :                     continue;
    1201              :                 }
    1202            0 :                 member = PQgetvalue(res, i, i_member);
    1203              : 
    1204              :                 /* If the grantor is unknown, complain and dump without it. */
    1205            0 :                 grantorid = PQgetvalue(res, i, i_grantorid);
    1206            0 :                 if (dump_this_grantor)
    1207              :                 {
    1208            0 :                     if (PQgetisnull(res, i, i_grantor))
    1209              :                     {
    1210              :                         /* translator: %s represents a numeric role OID */
    1211            0 :                         pg_log_warning("grant of role \"%s\" to \"%s\" has invalid grantor OID %s",
    1212              :                                        role, member, grantorid);
    1213            0 :                         pg_log_warning_detail("This grant will be dumped without GRANTED BY.");
    1214            0 :                         dump_this_grantor = false;
    1215              :                     }
    1216              :                     else
    1217            0 :                         grantor = PQgetvalue(res, i, i_grantor);
    1218              :                 }
    1219              : 
    1220            0 :                 admin_option = PQgetvalue(res, i, i_admin_option);
    1221            0 :                 if (dump_grant_options)
    1222            0 :                     set_option = PQgetvalue(res, i, i_set_option);
    1223              : 
    1224              :                 /*
    1225              :                  * If we're not dumping the grantor or if the grantor is the
    1226              :                  * bootstrap superuser, it's fine to dump this now. Otherwise,
    1227              :                  * it's got to be someone who has already been granted ADMIN
    1228              :                  * OPTION.
    1229              :                  */
    1230            0 :                 if (dump_this_grantor &&
    1231            0 :                     atooid(grantorid) != BOOTSTRAP_SUPERUSERID &&
    1232            0 :                     rolename_lookup(ht, grantor) == NULL)
    1233            0 :                     continue;
    1234              : 
    1235              :                 /* Remember that we did this so that we don't do it again. */
    1236            0 :                 done[i - start] = true;
    1237            0 :                 --remaining;
    1238              : 
    1239              :                 /*
    1240              :                  * If ADMIN OPTION is being granted, remember that grants
    1241              :                  * listing this member as the grantor can now be dumped.
    1242              :                  */
    1243            0 :                 if (*admin_option == 't')
    1244            0 :                     rolename_insert(ht, member, &found);
    1245              : 
    1246              :                 /* Generate the actual GRANT statement. */
    1247            0 :                 resetPQExpBuffer(optbuf);
    1248            0 :                 fprintf(OPF, "GRANT %s", fmtId(role));
    1249            0 :                 fprintf(OPF, " TO %s", fmtId(member));
    1250            0 :                 if (*admin_option == 't')
    1251            0 :                     appendPQExpBufferStr(optbuf, "ADMIN OPTION");
    1252            0 :                 if (dump_grant_options)
    1253              :                 {
    1254              :                     char       *inherit_option;
    1255              : 
    1256            0 :                     if (optbuf->data[0] != '\0')
    1257            0 :                         appendPQExpBufferStr(optbuf, ", ");
    1258            0 :                     inherit_option = PQgetvalue(res, i, i_inherit_option);
    1259            0 :                     appendPQExpBuffer(optbuf, "INHERIT %s",
    1260            0 :                                       *inherit_option == 't' ?
    1261              :                                       "TRUE" : "FALSE");
    1262              :                 }
    1263            0 :                 if (*set_option != 't')
    1264              :                 {
    1265            0 :                     if (optbuf->data[0] != '\0')
    1266            0 :                         appendPQExpBufferStr(optbuf, ", ");
    1267            0 :                     appendPQExpBufferStr(optbuf, "SET FALSE");
    1268              :                 }
    1269            0 :                 if (optbuf->data[0] != '\0')
    1270            0 :                     fprintf(OPF, " WITH %s", optbuf->data);
    1271            0 :                 if (dump_this_grantor)
    1272            0 :                     fprintf(OPF, " GRANTED BY %s", fmtId(grantor));
    1273            0 :                 fprintf(OPF, ";\n");
    1274              :             }
    1275              :         }
    1276              : 
    1277            0 :         rolename_destroy(ht);
    1278            0 :         pg_free(done);
    1279            0 :         start = end;
    1280              :     }
    1281              : 
    1282           31 :     PQclear(res);
    1283           31 :     destroyPQExpBuffer(buf);
    1284              : 
    1285           31 :     fprintf(OPF, "\n\n");
    1286           31 : }
    1287              : 
    1288              : 
    1289              : /*
    1290              :  * Dump role configuration parameter privileges.  This code is used for 15.0
    1291              :  * and later servers.
    1292              :  *
    1293              :  * Note: we expect dumpRoles already created all the roles, but there are
    1294              :  * no per-role configuration parameter privileges yet.
    1295              :  */
    1296              : static void
    1297           31 : dumpRoleGUCPrivs(PGconn *conn)
    1298              : {
    1299              :     PGresult   *res;
    1300              :     int         i;
    1301              : 
    1302              :     /*
    1303              :      * Get all parameters that have non-default acls defined.
    1304              :      */
    1305           31 :     res = executeQuery(conn, "SELECT parname, "
    1306              :                        "pg_catalog.pg_get_userbyid(" CppAsString2(BOOTSTRAP_SUPERUSERID) ") AS parowner, "
    1307              :                        "paracl, "
    1308              :                        "pg_catalog.acldefault('p', " CppAsString2(BOOTSTRAP_SUPERUSERID) ") AS acldefault "
    1309              :                        "FROM pg_catalog.pg_parameter_acl "
    1310              :                        "ORDER BY 1");
    1311              : 
    1312           31 :     if (PQntuples(res) > 0)
    1313            1 :         fprintf(OPF, "--\n-- Role privileges on configuration parameters\n--\n\n");
    1314              : 
    1315           34 :     for (i = 0; i < PQntuples(res); i++)
    1316              :     {
    1317            3 :         PQExpBuffer buf = createPQExpBuffer();
    1318            3 :         char       *parname = PQgetvalue(res, i, 0);
    1319            3 :         char       *parowner = PQgetvalue(res, i, 1);
    1320            3 :         char       *paracl = PQgetvalue(res, i, 2);
    1321            3 :         char       *acldefault = PQgetvalue(res, i, 3);
    1322              :         char       *fparname;
    1323              : 
    1324              :         /* needed for buildACLCommands() */
    1325            3 :         fparname = pg_strdup(fmtId(parname));
    1326              : 
    1327            3 :         if (!buildACLCommands(fparname, NULL, NULL, "PARAMETER",
    1328              :                               paracl, acldefault,
    1329              :                               parowner, "", server_version, buf))
    1330              :         {
    1331            0 :             pg_log_error("could not parse ACL list (%s) for parameter \"%s\"",
    1332              :                          paracl, parname);
    1333            0 :             PQfinish(conn);
    1334            0 :             exit_nicely(1);
    1335              :         }
    1336              : 
    1337            3 :         fprintf(OPF, "%s", buf->data);
    1338              : 
    1339            3 :         free(fparname);
    1340            3 :         destroyPQExpBuffer(buf);
    1341              :     }
    1342              : 
    1343           31 :     PQclear(res);
    1344           31 :     fprintf(OPF, "\n\n");
    1345           31 : }
    1346              : 
    1347              : 
    1348              : /*
    1349              :  * Drop tablespaces.
    1350              :  */
    1351              : static void
    1352            1 : dropTablespaces(PGconn *conn)
    1353              : {
    1354              :     PGresult   *res;
    1355              :     int         i;
    1356              : 
    1357              :     /*
    1358              :      * Get all tablespaces except built-in ones (which we assume are named
    1359              :      * pg_xxx)
    1360              :      */
    1361            1 :     res = executeQuery(conn, "SELECT spcname "
    1362              :                        "FROM pg_catalog.pg_tablespace "
    1363              :                        "WHERE spcname !~ '^pg_' "
    1364              :                        "ORDER BY 1");
    1365              : 
    1366            1 :     if (PQntuples(res) > 0)
    1367            1 :         fprintf(OPF, "--\n-- Drop tablespaces\n--\n\n");
    1368              : 
    1369            2 :     for (i = 0; i < PQntuples(res); i++)
    1370              :     {
    1371            1 :         char       *spcname = PQgetvalue(res, i, 0);
    1372              : 
    1373            2 :         fprintf(OPF, "DROP TABLESPACE %s%s;\n",
    1374            1 :                 if_exists ? "IF EXISTS " : "",
    1375              :                 fmtId(spcname));
    1376              :     }
    1377              : 
    1378            1 :     PQclear(res);
    1379              : 
    1380            1 :     fprintf(OPF, "\n\n");
    1381            1 : }
    1382              : 
    1383              : /*
    1384              :  * Dump tablespaces.
    1385              :  */
    1386              : static void
    1387           26 : dumpTablespaces(PGconn *conn)
    1388              : {
    1389              :     PGresult   *res;
    1390              :     int         i;
    1391              : 
    1392              :     /*
    1393              :      * Get all tablespaces except built-in ones (which we assume are named
    1394              :      * pg_xxx)
    1395              :      */
    1396           26 :     res = executeQuery(conn, "SELECT oid, spcname, "
    1397              :                        "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
    1398              :                        "pg_catalog.pg_tablespace_location(oid), "
    1399              :                        "spcacl, acldefault('t', spcowner) AS acldefault, "
    1400              :                        "array_to_string(spcoptions, ', '),"
    1401              :                        "pg_catalog.shobj_description(oid, 'pg_tablespace') "
    1402              :                        "FROM pg_catalog.pg_tablespace "
    1403              :                        "WHERE spcname !~ '^pg_' "
    1404              :                        "ORDER BY 1");
    1405              : 
    1406           26 :     if (PQntuples(res) > 0)
    1407           12 :         fprintf(OPF, "--\n-- Tablespaces\n--\n\n");
    1408              : 
    1409           38 :     for (i = 0; i < PQntuples(res); i++)
    1410              :     {
    1411           12 :         PQExpBuffer buf = createPQExpBuffer();
    1412           12 :         Oid         spcoid = atooid(PQgetvalue(res, i, 0));
    1413           12 :         char       *spcname = PQgetvalue(res, i, 1);
    1414           12 :         char       *spcowner = PQgetvalue(res, i, 2);
    1415           12 :         char       *spclocation = PQgetvalue(res, i, 3);
    1416           12 :         char       *spcacl = PQgetvalue(res, i, 4);
    1417           12 :         char       *acldefault = PQgetvalue(res, i, 5);
    1418           12 :         char       *spcoptions = PQgetvalue(res, i, 6);
    1419           12 :         char       *spccomment = PQgetvalue(res, i, 7);
    1420              :         char       *fspcname;
    1421              : 
    1422              :         /* needed for buildACLCommands() */
    1423           12 :         fspcname = pg_strdup(fmtId(spcname));
    1424              : 
    1425           12 :         if (binary_upgrade)
    1426              :         {
    1427            5 :             appendPQExpBufferStr(buf, "\n-- For binary upgrade, must preserve pg_tablespace oid\n");
    1428            5 :             appendPQExpBuffer(buf, "SELECT pg_catalog.binary_upgrade_set_next_pg_tablespace_oid('%u'::pg_catalog.oid);\n", spcoid);
    1429              :         }
    1430              : 
    1431           12 :         appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
    1432           12 :         appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
    1433              : 
    1434           12 :         appendPQExpBufferStr(buf, " LOCATION ");
    1435              : 
    1436              :         /*
    1437              :          * In-place tablespaces use a relative path, and need to be dumped
    1438              :          * with an empty string as location.
    1439              :          */
    1440           12 :         if (is_absolute_path(spclocation))
    1441            2 :             appendStringLiteralConn(buf, spclocation, conn);
    1442              :         else
    1443           10 :             appendStringLiteralConn(buf, "", conn);
    1444              : 
    1445           12 :         appendPQExpBufferStr(buf, ";\n");
    1446              : 
    1447           12 :         if (spcoptions && spcoptions[0] != '\0')
    1448            0 :             appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n",
    1449              :                               fspcname, spcoptions);
    1450              : 
    1451              :         /* tablespaces can't have initprivs */
    1452              : 
    1453           12 :         if (!skip_acls &&
    1454           12 :             !buildACLCommands(fspcname, NULL, NULL, "TABLESPACE",
    1455              :                               spcacl, acldefault,
    1456              :                               spcowner, "", server_version, buf))
    1457              :         {
    1458            0 :             pg_log_error("could not parse ACL list (%s) for tablespace \"%s\"",
    1459              :                          spcacl, spcname);
    1460            0 :             PQfinish(conn);
    1461            0 :             exit_nicely(1);
    1462              :         }
    1463              : 
    1464           12 :         if (!no_comments && spccomment && spccomment[0] != '\0')
    1465              :         {
    1466            0 :             appendPQExpBuffer(buf, "COMMENT ON TABLESPACE %s IS ", fspcname);
    1467            0 :             appendStringLiteralConn(buf, spccomment, conn);
    1468            0 :             appendPQExpBufferStr(buf, ";\n");
    1469              :         }
    1470              : 
    1471           12 :         if (!no_security_labels)
    1472           12 :             buildShSecLabels(conn, "pg_tablespace", spcoid,
    1473              :                              "TABLESPACE", spcname,
    1474              :                              buf);
    1475              : 
    1476           12 :         fprintf(OPF, "%s", buf->data);
    1477              : 
    1478           12 :         free(fspcname);
    1479           12 :         destroyPQExpBuffer(buf);
    1480              :     }
    1481              : 
    1482           26 :     PQclear(res);
    1483           26 :     fprintf(OPF, "\n\n");
    1484           26 : }
    1485              : 
    1486              : 
    1487              : /*
    1488              :  * Dump commands to drop each database.
    1489              :  */
    1490              : static void
    1491            0 : dropDBs(PGconn *conn)
    1492              : {
    1493              :     PGresult   *res;
    1494              :     int         i;
    1495              : 
    1496              :     /*
    1497              :      * Skip databases marked not datallowconn, since we'd be unable to connect
    1498              :      * to them anyway.  This must agree with dumpDatabases().
    1499              :      */
    1500            0 :     res = executeQuery(conn,
    1501              :                        "SELECT datname "
    1502              :                        "FROM pg_database d "
    1503              :                        "WHERE datallowconn AND datconnlimit != -2 "
    1504              :                        "ORDER BY datname");
    1505              : 
    1506            0 :     if (PQntuples(res) > 0)
    1507            0 :         fprintf(OPF, "--\n-- Drop databases (except postgres and template1)\n--\n\n");
    1508              : 
    1509            0 :     for (i = 0; i < PQntuples(res); i++)
    1510              :     {
    1511            0 :         char       *dbname = PQgetvalue(res, i, 0);
    1512              : 
    1513              :         /*
    1514              :          * Skip "postgres" and "template1"; dumpDatabases() will deal with
    1515              :          * them specially.  Also, be sure to skip "template0", even if for
    1516              :          * some reason it's not marked !datallowconn.
    1517              :          */
    1518            0 :         if (strcmp(dbname, "template1") != 0 &&
    1519            0 :             strcmp(dbname, "template0") != 0 &&
    1520            0 :             strcmp(dbname, "postgres") != 0)
    1521              :         {
    1522            0 :             fprintf(OPF, "DROP DATABASE %s%s;\n",
    1523            0 :                     if_exists ? "IF EXISTS " : "",
    1524              :                     fmtId(dbname));
    1525              :         }
    1526              :     }
    1527              : 
    1528            0 :     PQclear(res);
    1529              : 
    1530            0 :     fprintf(OPF, "\n\n");
    1531            0 : }
    1532              : 
    1533              : 
    1534              : /*
    1535              :  * Dump user-specific configuration
    1536              :  */
    1537              : static void
    1538           77 : dumpUserConfig(PGconn *conn, const char *username)
    1539              : {
    1540           77 :     PQExpBuffer buf = createPQExpBuffer();
    1541              :     PGresult   *res;
    1542              : 
    1543           77 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    1544              :                       "WHERE setdatabase = 0 AND setrole = "
    1545              :                       "(SELECT oid FROM %s WHERE rolname = ",
    1546              :                       role_catalog);
    1547           77 :     appendStringLiteralConn(buf, username, conn);
    1548           77 :     appendPQExpBufferChar(buf, ')');
    1549              : 
    1550           77 :     res = executeQuery(conn, buf->data);
    1551              : 
    1552           77 :     if (PQntuples(res) > 0)
    1553              :     {
    1554              :         char       *sanitized;
    1555              : 
    1556            0 :         sanitized = sanitize_line(username, true);
    1557            0 :         fprintf(OPF, "\n--\n-- User Config \"%s\"\n--\n\n", sanitized);
    1558            0 :         free(sanitized);
    1559              :     }
    1560              : 
    1561           77 :     for (int i = 0; i < PQntuples(res); i++)
    1562              :     {
    1563            0 :         resetPQExpBuffer(buf);
    1564            0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    1565              :                                "ROLE", username, NULL, NULL,
    1566              :                                buf);
    1567            0 :         fprintf(OPF, "%s", buf->data);
    1568              :     }
    1569              : 
    1570           77 :     PQclear(res);
    1571              : 
    1572           77 :     destroyPQExpBuffer(buf);
    1573           77 : }
    1574              : 
    1575              : /*
    1576              :  * Find a list of database names that match the given patterns.
    1577              :  * See also expand_table_name_patterns() in pg_dump.c
    1578              :  */
    1579              : static void
    1580           33 : expand_dbname_patterns(PGconn *conn,
    1581              :                        SimpleStringList *patterns,
    1582              :                        SimpleStringList *names)
    1583              : {
    1584              :     PQExpBuffer query;
    1585              :     PGresult   *res;
    1586              : 
    1587           33 :     if (patterns->head == NULL)
    1588           28 :         return;                 /* nothing to do */
    1589              : 
    1590            5 :     query = createPQExpBuffer();
    1591              : 
    1592              :     /*
    1593              :      * The loop below runs multiple SELECTs, which might sometimes result in
    1594              :      * duplicate entries in the name list, but we don't care, since all we're
    1595              :      * going to do is test membership of the list.
    1596              :      */
    1597              : 
    1598            8 :     for (SimpleStringListCell *cell = patterns->head; cell; cell = cell->next)
    1599              :     {
    1600              :         int         dotcnt;
    1601              : 
    1602            5 :         appendPQExpBufferStr(query,
    1603              :                              "SELECT datname FROM pg_catalog.pg_database n\n");
    1604            5 :         processSQLNamePattern(conn, query, cell->val, false,
    1605              :                               false, NULL, "datname", NULL, NULL, NULL,
    1606              :                               &dotcnt);
    1607              : 
    1608            5 :         if (dotcnt > 0)
    1609              :         {
    1610            2 :             pg_log_error("improper qualified name (too many dotted names): %s",
    1611              :                          cell->val);
    1612            2 :             PQfinish(conn);
    1613            2 :             exit_nicely(1);
    1614              :         }
    1615              : 
    1616            3 :         res = executeQuery(conn, query->data);
    1617            7 :         for (int i = 0; i < PQntuples(res); i++)
    1618              :         {
    1619            4 :             simple_string_list_append(names, PQgetvalue(res, i, 0));
    1620              :         }
    1621              : 
    1622            3 :         PQclear(res);
    1623            3 :         resetPQExpBuffer(query);
    1624              :     }
    1625              : 
    1626            3 :     destroyPQExpBuffer(query);
    1627              : }
    1628              : 
    1629              : /*
    1630              :  * Dump contents of databases.
    1631              :  */
    1632              : static void
    1633           11 : dumpDatabases(PGconn *conn)
    1634              : {
    1635              :     PGresult   *res;
    1636              :     int         i;
    1637              : 
    1638              :     /*
    1639              :      * Skip databases marked not datallowconn, since we'd be unable to connect
    1640              :      * to them anyway.  This must agree with dropDBs().
    1641              :      *
    1642              :      * We arrange for template1 to be processed first, then we process other
    1643              :      * DBs in alphabetical order.  If we just did them all alphabetically, we
    1644              :      * might find ourselves trying to drop the "postgres" database while still
    1645              :      * connected to it.  This makes trying to run the restore script while
    1646              :      * connected to "template1" a bad idea, but there's no fixed order that
    1647              :      * doesn't have some failure mode with --clean.
    1648              :      */
    1649           11 :     res = executeQuery(conn,
    1650              :                        "SELECT datname "
    1651              :                        "FROM pg_database d "
    1652              :                        "WHERE datallowconn AND datconnlimit != -2 "
    1653              :                        "ORDER BY (datname <> 'template1'), datname");
    1654              : 
    1655           11 :     if (PQntuples(res) > 0)
    1656           11 :         fprintf(OPF, "--\n-- Databases\n--\n\n");
    1657              : 
    1658           63 :     for (i = 0; i < PQntuples(res); i++)
    1659              :     {
    1660           52 :         char       *dbname = PQgetvalue(res, i, 0);
    1661              :         char       *sanitized;
    1662              :         const char *create_opts;
    1663              :         int         ret;
    1664              : 
    1665              :         /* Skip template0, even if it's not marked !datallowconn. */
    1666           52 :         if (strcmp(dbname, "template0") == 0)
    1667            0 :             continue;
    1668              : 
    1669              :         /* Skip any explicitly excluded database */
    1670           52 :         if (simple_string_list_member(&database_exclude_names, dbname))
    1671              :         {
    1672            4 :             pg_log_info("excluding database \"%s\"", dbname);
    1673            4 :             continue;
    1674              :         }
    1675              : 
    1676           48 :         pg_log_info("dumping database \"%s\"", dbname);
    1677              : 
    1678           48 :         sanitized = sanitize_line(dbname, true);
    1679           48 :         fprintf(OPF, "--\n-- Database \"%s\" dump\n--\n\n", sanitized);
    1680           48 :         free(sanitized);
    1681              : 
    1682              :         /*
    1683              :          * We assume that "template1" and "postgres" already exist in the
    1684              :          * target installation.  dropDBs() won't have removed them, for fear
    1685              :          * of removing the DB the restore script is initially connected to. If
    1686              :          * --clean was specified, tell pg_dump to drop and recreate them;
    1687              :          * otherwise we'll merely restore their contents.  Other databases
    1688              :          * should simply be created.
    1689              :          */
    1690           48 :         if (strcmp(dbname, "template1") == 0 || strcmp(dbname, "postgres") == 0)
    1691              :         {
    1692           21 :             if (output_clean)
    1693            0 :                 create_opts = "--clean --create";
    1694              :             else
    1695              :             {
    1696           21 :                 create_opts = "";
    1697              :                 /* Since pg_dump won't emit a \connect command, we must */
    1698           21 :                 fprintf(OPF, "\\connect %s\n\n", dbname);
    1699              :             }
    1700              :         }
    1701              :         else
    1702           27 :             create_opts = "--create";
    1703              : 
    1704           48 :         if (filename)
    1705           48 :             fclose(OPF);
    1706              : 
    1707           48 :         ret = runPgDump(dbname, create_opts);
    1708           48 :         if (ret != 0)
    1709            0 :             pg_fatal("pg_dump failed on database \"%s\", exiting", dbname);
    1710              : 
    1711           48 :         if (filename)
    1712              :         {
    1713           48 :             OPF = fopen(filename, PG_BINARY_A);
    1714           48 :             if (!OPF)
    1715            0 :                 pg_fatal("could not re-open the output file \"%s\": %m",
    1716              :                          filename);
    1717              :         }
    1718              :     }
    1719              : 
    1720           11 :     PQclear(res);
    1721           11 : }
    1722              : 
    1723              : 
    1724              : 
    1725              : /*
    1726              :  * Run pg_dump on dbname, with specified options.
    1727              :  */
    1728              : static int
    1729           48 : runPgDump(const char *dbname, const char *create_opts)
    1730              : {
    1731              :     PQExpBufferData connstrbuf;
    1732              :     PQExpBufferData cmd;
    1733              :     int         ret;
    1734              : 
    1735           48 :     initPQExpBuffer(&connstrbuf);
    1736           48 :     initPQExpBuffer(&cmd);
    1737              : 
    1738           48 :     printfPQExpBuffer(&cmd, "\"%s\" %s %s", pg_dump_bin,
    1739           48 :                       pgdumpopts->data, create_opts);
    1740              : 
    1741              :     /*
    1742              :      * If we have a filename, use the undocumented plain-append pg_dump
    1743              :      * format.
    1744              :      */
    1745           48 :     if (filename)
    1746           48 :         appendPQExpBufferStr(&cmd, " -Fa ");
    1747              :     else
    1748            0 :         appendPQExpBufferStr(&cmd, " -Fp ");
    1749              : 
    1750              :     /*
    1751              :      * Append the database name to the already-constructed stem of connection
    1752              :      * string.
    1753              :      */
    1754           48 :     appendPQExpBuffer(&connstrbuf, "%s dbname=", connstr);
    1755           48 :     appendConnStrVal(&connstrbuf, dbname);
    1756              : 
    1757           48 :     appendShellString(&cmd, connstrbuf.data);
    1758              : 
    1759           48 :     pg_log_info("running \"%s\"", cmd.data);
    1760              : 
    1761           48 :     fflush(NULL);
    1762              : 
    1763           48 :     ret = system(cmd.data);
    1764              : 
    1765           48 :     termPQExpBuffer(&cmd);
    1766           48 :     termPQExpBuffer(&connstrbuf);
    1767              : 
    1768           48 :     return ret;
    1769              : }
    1770              : 
    1771              : /*
    1772              :  * buildShSecLabels
    1773              :  *
    1774              :  * Build SECURITY LABEL command(s) for a shared object
    1775              :  *
    1776              :  * The caller has to provide object type and identity in two separate formats:
    1777              :  * catalog_name (e.g., "pg_database") and object OID, as well as
    1778              :  * type name (e.g., "DATABASE") and object name (not pre-quoted).
    1779              :  *
    1780              :  * The command(s) are appended to "buffer".
    1781              :  */
    1782              : static void
    1783           89 : buildShSecLabels(PGconn *conn, const char *catalog_name, Oid objectId,
    1784              :                  const char *objtype, const char *objname,
    1785              :                  PQExpBuffer buffer)
    1786              : {
    1787           89 :     PQExpBuffer sql = createPQExpBuffer();
    1788              :     PGresult   *res;
    1789              : 
    1790           89 :     buildShSecLabelQuery(catalog_name, objectId, sql);
    1791           89 :     res = executeQuery(conn, sql->data);
    1792           89 :     emitShSecLabels(conn, res, buffer, objtype, objname);
    1793              : 
    1794           89 :     PQclear(res);
    1795           89 :     destroyPQExpBuffer(sql);
    1796           89 : }
    1797              : 
    1798              : /*
    1799              :  * As above for a SQL command (which returns nothing).
    1800              :  */
    1801              : static void
    1802           43 : executeCommand(PGconn *conn, const char *query)
    1803              : {
    1804              :     PGresult   *res;
    1805              : 
    1806           43 :     pg_log_info("executing %s", query);
    1807              : 
    1808           43 :     res = PQexec(conn, query);
    1809           86 :     if (!res ||
    1810           43 :         PQresultStatus(res) != PGRES_COMMAND_OK)
    1811              :     {
    1812            0 :         pg_log_error("query failed: %s", PQerrorMessage(conn));
    1813            0 :         pg_log_error_detail("Query was: %s", query);
    1814            0 :         PQfinish(conn);
    1815            0 :         exit_nicely(1);
    1816              :     }
    1817              : 
    1818           43 :     PQclear(res);
    1819           43 : }
    1820              : 
    1821              : 
    1822              : /*
    1823              :  * dumpTimestamp
    1824              :  */
    1825              : static void
    1826            4 : dumpTimestamp(const char *msg)
    1827              : {
    1828              :     char        buf[64];
    1829            4 :     time_t      now = time(NULL);
    1830              : 
    1831            4 :     if (strftime(buf, sizeof(buf), PGDUMP_STRFTIME_FMT, localtime(&now)) != 0)
    1832            4 :         fprintf(OPF, "-- %s %s\n\n", msg, buf);
    1833            4 : }
    1834              : 
    1835              : /*
    1836              :  * read_dumpall_filters - retrieve database identifier patterns from file
    1837              :  *
    1838              :  * Parse the specified filter file for include and exclude patterns, and add
    1839              :  * them to the relevant lists.  If the filename is "-" then filters will be
    1840              :  * read from STDIN rather than a file.
    1841              :  *
    1842              :  * At the moment, the only allowed filter is for database exclusion.
    1843              :  */
    1844              : static void
    1845            5 : read_dumpall_filters(const char *filename, SimpleStringList *pattern)
    1846              : {
    1847              :     FilterStateData fstate;
    1848              :     char       *objname;
    1849              :     FilterCommandType comtype;
    1850              :     FilterObjectType objtype;
    1851              : 
    1852            5 :     filter_init(&fstate, filename, exit);
    1853              : 
    1854           12 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
    1855              :     {
    1856            3 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
    1857              :         {
    1858            0 :             pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
    1859              :                                 "include",
    1860              :                                 filter_object_type_name(objtype));
    1861            0 :             exit_nicely(1);
    1862              :         }
    1863              : 
    1864            3 :         switch (objtype)
    1865              :         {
    1866            0 :             case FILTER_OBJECT_TYPE_NONE:
    1867            0 :                 break;
    1868            1 :             case FILTER_OBJECT_TYPE_FUNCTION:
    1869              :             case FILTER_OBJECT_TYPE_INDEX:
    1870              :             case FILTER_OBJECT_TYPE_TABLE_DATA:
    1871              :             case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
    1872              :             case FILTER_OBJECT_TYPE_TRIGGER:
    1873              :             case FILTER_OBJECT_TYPE_EXTENSION:
    1874              :             case FILTER_OBJECT_TYPE_FOREIGN_DATA:
    1875              :             case FILTER_OBJECT_TYPE_SCHEMA:
    1876              :             case FILTER_OBJECT_TYPE_TABLE:
    1877              :             case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
    1878            1 :                 pg_log_filter_error(&fstate, _("unsupported filter object"));
    1879            1 :                 exit_nicely(1);
    1880              :                 break;
    1881              : 
    1882            2 :             case FILTER_OBJECT_TYPE_DATABASE:
    1883            2 :                 simple_string_list_append(pattern, objname);
    1884            2 :                 break;
    1885              :         }
    1886              : 
    1887            2 :         if (objname)
    1888            2 :             free(objname);
    1889              :     }
    1890              : 
    1891            2 :     filter_free(&fstate);
    1892            2 : }
        

Generated by: LCOV version 2.0-1