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

Generated by: LCOV version 2.3.2-1