LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_restore.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 448 603 74.3 %
Date: 2025-04-24 13:15:39 Functions: 10 11 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_restore.c
       4             :  *  pg_restore is an utility extracting postgres database definitions
       5             :  *  from a backup archive created by pg_dump/pg_dumpall using the archiver
       6             :  *  interface.
       7             :  *
       8             :  *  pg_restore will read the backup archive and
       9             :  *  dump out a script that reproduces
      10             :  *  the schema of the database in terms of
      11             :  *        user-defined types
      12             :  *        user-defined functions
      13             :  *        tables
      14             :  *        indexes
      15             :  *        aggregates
      16             :  *        operators
      17             :  *        ACL - grant/revoke
      18             :  *
      19             :  * the output script is SQL that is understood by PostgreSQL
      20             :  *
      21             :  * Basic process in a restore operation is:
      22             :  *
      23             :  *  Open the Archive and read the TOC.
      24             :  *  Set flags in TOC entries, and *maybe* reorder them.
      25             :  *  Generate script to stdout
      26             :  *  Exit
      27             :  *
      28             :  * Copyright (c) 2000, Philip Warner
      29             :  *      Rights are granted to use this software in any way so long
      30             :  *      as this notice is not removed.
      31             :  *
      32             :  *  The author is not responsible for loss or damages that may
      33             :  *  result from its use.
      34             :  *
      35             :  *
      36             :  * IDENTIFICATION
      37             :  *      src/bin/pg_dump/pg_restore.c
      38             :  *
      39             :  *-------------------------------------------------------------------------
      40             :  */
      41             : #include "postgres_fe.h"
      42             : 
      43             : #include <ctype.h>
      44             : #include <sys/stat.h>
      45             : #ifdef HAVE_TERMIOS_H
      46             : #include <termios.h>
      47             : #endif
      48             : 
      49             : #include "common/string.h"
      50             : #include "connectdb.h"
      51             : #include "fe_utils/option_utils.h"
      52             : #include "fe_utils/string_utils.h"
      53             : #include "filter.h"
      54             : #include "getopt_long.h"
      55             : #include "parallel.h"
      56             : #include "pg_backup_utils.h"
      57             : 
      58             : static void usage(const char *progname);
      59             : static void read_restore_filters(const char *filename, RestoreOptions *opts);
      60             : static bool file_exists_in_directory(const char *dir, const char *filename);
      61             : static int  restore_one_database(const char *inputFileSpec, RestoreOptions *opts,
      62             :                                  int numWorkers, bool append_data, int num);
      63             : static int  read_one_statement(StringInfo inBuf, FILE *pfile);
      64             : static int  restore_all_databases(PGconn *conn, const char *dumpdirpath,
      65             :                                   SimpleStringList db_exclude_patterns, RestoreOptions *opts, int numWorkers);
      66             : static int  process_global_sql_commands(PGconn *conn, const char *dumpdirpath,
      67             :                                         const char *outfile);
      68             : static void copy_or_print_global_file(const char *outfile, FILE *pfile);
      69             : static int  get_dbnames_list_to_restore(PGconn *conn,
      70             :                                         SimplePtrList *dbname_oid_list,
      71             :                                         SimpleStringList db_exclude_patterns);
      72             : static int  get_dbname_oid_list_from_mfile(const char *dumpdirpath,
      73             :                                            SimplePtrList *dbname_oid_list);
      74             : 
      75             : /*
      76             :  * Stores a database OID and the corresponding name.
      77             :  */
      78             : typedef struct DbOidName
      79             : {
      80             :     Oid         oid;
      81             :     char        str[FLEXIBLE_ARRAY_MEMBER]; /* null-terminated string here */
      82             : } DbOidName;
      83             : 
      84             : 
      85             : int
      86         200 : main(int argc, char **argv)
      87             : {
      88             :     RestoreOptions *opts;
      89             :     int         c;
      90         200 :     int         numWorkers = 1;
      91             :     char       *inputFileSpec;
      92         200 :     bool        data_only = false;
      93         200 :     bool        schema_only = false;
      94         200 :     int         n_errors = 0;
      95         200 :     bool        globals_only = false;
      96         200 :     SimpleStringList db_exclude_patterns = {NULL, NULL};
      97             :     static int  disable_triggers = 0;
      98             :     static int  enable_row_security = 0;
      99             :     static int  if_exists = 0;
     100             :     static int  no_data_for_failed_tables = 0;
     101             :     static int  outputNoTableAm = 0;
     102             :     static int  outputNoTablespaces = 0;
     103             :     static int  use_setsessauth = 0;
     104             :     static int  no_comments = 0;
     105             :     static int  no_data = 0;
     106             :     static int  no_policies = 0;
     107             :     static int  no_publications = 0;
     108             :     static int  no_schema = 0;
     109             :     static int  no_security_labels = 0;
     110             :     static int  no_statistics = 0;
     111             :     static int  no_subscriptions = 0;
     112             :     static int  strict_names = 0;
     113             :     static int  statistics_only = 0;
     114             :     static int  with_data = 0;
     115             :     static int  with_schema = 0;
     116             :     static int  with_statistics = 0;
     117             : 
     118         200 :     struct option cmdopts[] = {
     119             :         {"clean", 0, NULL, 'c'},
     120             :         {"create", 0, NULL, 'C'},
     121             :         {"data-only", 0, NULL, 'a'},
     122             :         {"globals-only", 0, NULL, 'g'},
     123             :         {"dbname", 1, NULL, 'd'},
     124             :         {"exit-on-error", 0, NULL, 'e'},
     125             :         {"exclude-schema", 1, NULL, 'N'},
     126             :         {"file", 1, NULL, 'f'},
     127             :         {"format", 1, NULL, 'F'},
     128             :         {"function", 1, NULL, 'P'},
     129             :         {"host", 1, NULL, 'h'},
     130             :         {"index", 1, NULL, 'I'},
     131             :         {"jobs", 1, NULL, 'j'},
     132             :         {"list", 0, NULL, 'l'},
     133             :         {"no-privileges", 0, NULL, 'x'},
     134             :         {"no-acl", 0, NULL, 'x'},
     135             :         {"no-owner", 0, NULL, 'O'},
     136             :         {"no-reconnect", 0, NULL, 'R'},
     137             :         {"port", 1, NULL, 'p'},
     138             :         {"no-password", 0, NULL, 'w'},
     139             :         {"password", 0, NULL, 'W'},
     140             :         {"schema", 1, NULL, 'n'},
     141             :         {"schema-only", 0, NULL, 's'},
     142             :         {"superuser", 1, NULL, 'S'},
     143             :         {"table", 1, NULL, 't'},
     144             :         {"trigger", 1, NULL, 'T'},
     145             :         {"use-list", 1, NULL, 'L'},
     146             :         {"username", 1, NULL, 'U'},
     147             :         {"verbose", 0, NULL, 'v'},
     148             :         {"single-transaction", 0, NULL, '1'},
     149             : 
     150             :         /*
     151             :          * the following options don't have an equivalent short option letter
     152             :          */
     153             :         {"disable-triggers", no_argument, &disable_triggers, 1},
     154             :         {"enable-row-security", no_argument, &enable_row_security, 1},
     155             :         {"if-exists", no_argument, &if_exists, 1},
     156             :         {"no-data-for-failed-tables", no_argument, &no_data_for_failed_tables, 1},
     157             :         {"no-table-access-method", no_argument, &outputNoTableAm, 1},
     158             :         {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
     159             :         {"role", required_argument, NULL, 2},
     160             :         {"section", required_argument, NULL, 3},
     161             :         {"strict-names", no_argument, &strict_names, 1},
     162             :         {"transaction-size", required_argument, NULL, 5},
     163             :         {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
     164             :         {"no-comments", no_argument, &no_comments, 1},
     165             :         {"no-data", no_argument, &no_data, 1},
     166             :         {"no-policies", no_argument, &no_policies, 1},
     167             :         {"no-publications", no_argument, &no_publications, 1},
     168             :         {"no-schema", no_argument, &no_schema, 1},
     169             :         {"no-security-labels", no_argument, &no_security_labels, 1},
     170             :         {"no-subscriptions", no_argument, &no_subscriptions, 1},
     171             :         {"no-statistics", no_argument, &no_statistics, 1},
     172             :         {"with-data", no_argument, &with_data, 1},
     173             :         {"with-schema", no_argument, &with_schema, 1},
     174             :         {"with-statistics", no_argument, &with_statistics, 1},
     175             :         {"statistics-only", no_argument, &statistics_only, 1},
     176             :         {"filter", required_argument, NULL, 4},
     177             :         {"exclude-database", required_argument, NULL, 6},
     178             : 
     179             :         {NULL, 0, NULL, 0}
     180             :     };
     181             : 
     182         200 :     pg_logging_init(argv[0]);
     183         200 :     pg_logging_set_level(PG_LOG_WARNING);
     184         200 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     185             : 
     186         200 :     init_parallel_dump_utils();
     187             : 
     188         200 :     opts = NewRestoreOptions();
     189             : 
     190         200 :     progname = get_progname(argv[0]);
     191             : 
     192         200 :     if (argc > 1)
     193             :     {
     194         198 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     195             :         {
     196           2 :             usage(progname);
     197           2 :             exit_nicely(0);
     198             :         }
     199         196 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     200             :         {
     201          34 :             puts("pg_restore (PostgreSQL) " PG_VERSION);
     202          34 :             exit_nicely(0);
     203             :         }
     204             :     }
     205             : 
     206         882 :     while ((c = getopt_long(argc, argv, "acCd:ef:F:gh:I:j:lL:n:N:Op:P:RsS:t:T:U:vwWx1",
     207             :                             cmdopts, NULL)) != -1)
     208             :     {
     209         730 :         switch (c)
     210             :         {
     211           4 :             case 'a':           /* Dump data only */
     212           4 :                 data_only = true;
     213           4 :                 break;
     214          34 :             case 'c':           /* clean (i.e., drop) schema prior to create */
     215          34 :                 opts->dropSchema = 1;
     216          34 :                 break;
     217          74 :             case 'C':
     218          74 :                 opts->createDB = 1;
     219          74 :                 break;
     220          68 :             case 'd':
     221          68 :                 opts->cparams.dbname = pg_strdup(optarg);
     222          68 :                 break;
     223          48 :             case 'e':
     224          48 :                 opts->exit_on_error = true;
     225          48 :                 break;
     226          82 :             case 'f':           /* output file name */
     227          82 :                 opts->filename = pg_strdup(optarg);
     228          82 :                 break;
     229          44 :             case 'F':
     230          44 :                 if (strlen(optarg) != 0)
     231          44 :                     opts->formatName = pg_strdup(optarg);
     232          44 :                 break;
     233           6 :             case 'g':
     234             :                 /* restore only global.dat file from directory */
     235           6 :                 globals_only = true;
     236           6 :                 break;
     237          64 :             case 'h':
     238          64 :                 if (strlen(optarg) != 0)
     239          64 :                     opts->cparams.pghost = pg_strdup(optarg);
     240          64 :                 break;
     241          18 :             case 'j':           /* number of restore jobs */
     242          18 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     243             :                                       PG_MAX_JOBS,
     244             :                                       &numWorkers))
     245           2 :                     exit(1);
     246          16 :                 break;
     247             : 
     248          10 :             case 'l':           /* Dump the TOC summary */
     249          10 :                 opts->tocSummary = 1;
     250          10 :                 break;
     251             : 
     252           0 :             case 'L':           /* input TOC summary file name */
     253           0 :                 opts->tocFile = pg_strdup(optarg);
     254           0 :                 break;
     255             : 
     256           0 :             case 'n':           /* Dump data for this schema only */
     257           0 :                 simple_string_list_append(&opts->schemaNames, optarg);
     258           0 :                 break;
     259             : 
     260           0 :             case 'N':           /* Do not dump data for this schema */
     261           0 :                 simple_string_list_append(&opts->schemaExcludeNames, optarg);
     262           0 :                 break;
     263             : 
     264           0 :             case 'O':
     265           0 :                 opts->noOwner = 1;
     266           0 :                 break;
     267             : 
     268          84 :             case 'p':
     269          84 :                 if (strlen(optarg) != 0)
     270          84 :                     opts->cparams.pgport = pg_strdup(optarg);
     271          84 :                 break;
     272           0 :             case 'R':
     273             :                 /* no-op, still accepted for backwards compatibility */
     274           0 :                 break;
     275           0 :             case 'P':           /* Function */
     276           0 :                 opts->selTypes = 1;
     277           0 :                 opts->selFunction = 1;
     278           0 :                 simple_string_list_append(&opts->functionNames, optarg);
     279           0 :                 break;
     280           0 :             case 'I':           /* Index */
     281           0 :                 opts->selTypes = 1;
     282           0 :                 opts->selIndex = 1;
     283           0 :                 simple_string_list_append(&opts->indexNames, optarg);
     284           0 :                 break;
     285           0 :             case 'T':           /* Trigger */
     286           0 :                 opts->selTypes = 1;
     287           0 :                 opts->selTrigger = 1;
     288           0 :                 simple_string_list_append(&opts->triggerNames, optarg);
     289           0 :                 break;
     290           2 :             case 's':           /* dump schema only */
     291           2 :                 schema_only = true;
     292           2 :                 break;
     293           0 :             case 'S':           /* Superuser username */
     294           0 :                 if (strlen(optarg) != 0)
     295           0 :                     opts->superuser = pg_strdup(optarg);
     296           0 :                 break;
     297           0 :             case 't':           /* Dump specified table(s) only */
     298           0 :                 opts->selTypes = 1;
     299           0 :                 opts->selTable = 1;
     300           0 :                 simple_string_list_append(&opts->tableNames, optarg);
     301           0 :                 break;
     302             : 
     303          52 :             case 'U':
     304          52 :                 opts->cparams.username = pg_strdup(optarg);
     305          52 :                 break;
     306             : 
     307          58 :             case 'v':           /* verbose */
     308          58 :                 opts->verbose = 1;
     309          58 :                 pg_logging_increase_verbosity();
     310          58 :                 break;
     311             : 
     312           0 :             case 'w':
     313           0 :                 opts->cparams.promptPassword = TRI_NO;
     314           0 :                 break;
     315             : 
     316           0 :             case 'W':
     317           0 :                 opts->cparams.promptPassword = TRI_YES;
     318           0 :                 break;
     319             : 
     320           0 :             case 'x':           /* skip ACL dump */
     321           0 :                 opts->aclsSkip = 1;
     322           0 :                 break;
     323             : 
     324           4 :             case '1':           /* Restore data in a single transaction */
     325           4 :                 opts->single_txn = true;
     326           4 :                 opts->exit_on_error = true;
     327           4 :                 break;
     328             : 
     329           2 :             case 0:
     330             : 
     331             :                 /*
     332             :                  * This covers the long options without a short equivalent.
     333             :                  */
     334           2 :                 break;
     335             : 
     336           0 :             case 2:             /* SET ROLE */
     337           0 :                 opts->use_role = pg_strdup(optarg);
     338           0 :                 break;
     339             : 
     340           0 :             case 3:             /* section */
     341           0 :                 set_dump_section(optarg, &(opts->dumpSections));
     342           0 :                 break;
     343             : 
     344          20 :             case 4:             /* filter */
     345          20 :                 read_restore_filters(optarg, opts);
     346          12 :                 break;
     347             : 
     348          48 :             case 5:             /* transaction-size */
     349          48 :                 if (!option_parse_int(optarg, "--transaction-size",
     350             :                                       1, INT_MAX,
     351             :                                       &opts->txn_size))
     352           0 :                     exit(1);
     353          48 :                 opts->exit_on_error = true;
     354          48 :                 break;
     355           6 :             case 6:             /* database patterns to skip */
     356           6 :                 simple_string_list_append(&db_exclude_patterns, optarg);
     357           6 :                 break;
     358             : 
     359           2 :             default:
     360             :                 /* getopt_long already emitted a complaint */
     361           2 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     362           2 :                 exit_nicely(1);
     363             :         }
     364             :     }
     365             : 
     366             :     /* Get file name from command line */
     367         152 :     if (optind < argc)
     368         134 :         inputFileSpec = argv[optind++];
     369             :     else
     370          18 :         inputFileSpec = NULL;
     371             : 
     372             :     /* Complain if any arguments remain */
     373         152 :     if (optind < argc)
     374             :     {
     375           2 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     376             :                      argv[optind]);
     377           2 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     378           2 :         exit_nicely(1);
     379             :     }
     380             : 
     381             :     /* Complain if neither -f nor -d was specified (except if dumping TOC) */
     382         150 :     if (!opts->cparams.dbname && !opts->filename && !opts->tocSummary)
     383           2 :         pg_fatal("one of -d/--dbname and -f/--file must be specified");
     384             : 
     385         148 :     if (db_exclude_patterns.head != NULL && globals_only)
     386             :     {
     387           2 :         pg_log_error("option --exclude-database cannot be used together with -g/--globals-only");
     388           2 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     389           2 :         exit_nicely(1);
     390             :     }
     391             : 
     392             :     /* Should get at most one of -d and -f, else user is confused */
     393         146 :     if (opts->cparams.dbname)
     394             :     {
     395          66 :         if (opts->filename)
     396             :         {
     397           2 :             pg_log_error("options -d/--dbname and -f/--file cannot be used together");
     398           2 :             pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     399           2 :             exit_nicely(1);
     400             :         }
     401          64 :         opts->useDB = 1;
     402             :     }
     403             : 
     404             :     /* reject conflicting "-only" options */
     405         144 :     if (data_only && schema_only)
     406           2 :         pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
     407         142 :     if (schema_only && statistics_only)
     408           0 :         pg_fatal("options -s/--schema-only and --statistics-only cannot be used together");
     409         142 :     if (data_only && statistics_only)
     410           0 :         pg_fatal("options -a/--data-only and --statistics-only cannot be used together");
     411             : 
     412             :     /* reject conflicting "-only" and "no-" options */
     413         142 :     if (data_only && no_data)
     414           0 :         pg_fatal("options -a/--data-only and --no-data cannot be used together");
     415         142 :     if (schema_only && no_schema)
     416           0 :         pg_fatal("options -s/--schema-only and --no-schema cannot be used together");
     417         142 :     if (statistics_only && no_statistics)
     418           0 :         pg_fatal("options --statistics-only and --no-statistics cannot be used together");
     419             : 
     420             :     /* reject conflicting "with-" and "no-" options */
     421         142 :     if (with_data && no_data)
     422           0 :         pg_fatal("options --with-data and --no-data cannot be used together");
     423         142 :     if (with_schema && no_schema)
     424           0 :         pg_fatal("options --with-schema and --no-schema cannot be used together");
     425         142 :     if (with_statistics && no_statistics)
     426           0 :         pg_fatal("options --with-statistics and --no-statistics cannot be used together");
     427             : 
     428         142 :     if (data_only && opts->dropSchema)
     429           2 :         pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
     430             : 
     431         140 :     if (opts->single_txn && opts->txn_size > 0)
     432           0 :         pg_fatal("options -1/--single-transaction and --transaction-size cannot be used together");
     433             : 
     434             :     /*
     435             :      * -C is not compatible with -1, because we can't create a database inside
     436             :      * a transaction block.
     437             :      */
     438         140 :     if (opts->createDB && opts->single_txn)
     439           2 :         pg_fatal("options -C/--create and -1/--single-transaction cannot be used together");
     440             : 
     441             :     /* Can't do single-txn mode with multiple connections */
     442         138 :     if (opts->single_txn && numWorkers > 1)
     443           2 :         pg_fatal("cannot specify both --single-transaction and multiple jobs");
     444             : 
     445             :     /*
     446             :      * Set derivative flags. An "-only" option may be overridden by an
     447             :      * explicit "with-" option; e.g. "--schema-only --with-statistics" will
     448             :      * include schema and statistics. Other ambiguous or nonsensical
     449             :      * combinations, e.g. "--schema-only --no-schema", will have already
     450             :      * caused an error in one of the checks above.
     451             :      */
     452         136 :     opts->dumpData = ((opts->dumpData && !schema_only && !statistics_only) ||
     453         272 :                       (data_only || with_data)) && !no_data;
     454         136 :     opts->dumpSchema = ((opts->dumpSchema && !data_only && !statistics_only) ||
     455         272 :                         (schema_only || with_schema)) && !no_schema;
     456         136 :     opts->dumpStatistics = ((opts->dumpStatistics && !schema_only && !data_only) ||
     457         272 :                             (statistics_only || with_statistics)) && !no_statistics;
     458             : 
     459         136 :     opts->disable_triggers = disable_triggers;
     460         136 :     opts->enable_row_security = enable_row_security;
     461         136 :     opts->noDataForFailedTables = no_data_for_failed_tables;
     462         136 :     opts->noTableAm = outputNoTableAm;
     463         136 :     opts->noTablespace = outputNoTablespaces;
     464         136 :     opts->use_setsessauth = use_setsessauth;
     465         136 :     opts->no_comments = no_comments;
     466         136 :     opts->no_policies = no_policies;
     467         136 :     opts->no_publications = no_publications;
     468         136 :     opts->no_security_labels = no_security_labels;
     469         136 :     opts->no_subscriptions = no_subscriptions;
     470             : 
     471         136 :     if (if_exists && !opts->dropSchema)
     472           2 :         pg_fatal("option --if-exists requires option -c/--clean");
     473         134 :     opts->if_exists = if_exists;
     474         134 :     opts->strict_names = strict_names;
     475             : 
     476         134 :     if (opts->formatName)
     477             :     {
     478          88 :         if (pg_strcasecmp(opts->formatName, "c") == 0 ||
     479          44 :             pg_strcasecmp(opts->formatName, "custom") == 0)
     480          24 :             opts->format = archCustom;
     481          40 :         else if (pg_strcasecmp(opts->formatName, "d") == 0 ||
     482          20 :                  pg_strcasecmp(opts->formatName, "directory") == 0)
     483          14 :             opts->format = archDirectory;
     484          12 :         else if (pg_strcasecmp(opts->formatName, "t") == 0 ||
     485           6 :                  pg_strcasecmp(opts->formatName, "tar") == 0)
     486           4 :             opts->format = archTar;
     487           4 :         else if (pg_strcasecmp(opts->formatName, "p") == 0 ||
     488           2 :                  pg_strcasecmp(opts->formatName, "plain") == 0)
     489             :         {
     490             :             /* recognize this for consistency with pg_dump */
     491           0 :             pg_fatal("archive format \"%s\" is not supported; please use psql",
     492             :                      opts->formatName);
     493             :         }
     494             :         else
     495           2 :             pg_fatal("unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"",
     496             :                      opts->formatName);
     497             :     }
     498             : 
     499             :     /*
     500             :      * If toc.dat file is not present in the current path, then check for
     501             :      * global.dat.  If global.dat file is present, then restore all the
     502             :      * databases from map.dat (if it exists), but skip restoring those
     503             :      * matching --exclude-database patterns.
     504             :      */
     505         238 :     if (inputFileSpec != NULL && !file_exists_in_directory(inputFileSpec, "toc.dat") &&
     506         106 :         file_exists_in_directory(inputFileSpec, "global.dat"))
     507          16 :     {
     508          22 :         PGconn     *conn = NULL;    /* Connection to restore global sql
     509             :                                      * commands. */
     510             : 
     511             :         /*
     512             :          * Can only use --list or --use-list options with a single database
     513             :          * dump.
     514             :          */
     515          22 :         if (opts->tocSummary)
     516           2 :             pg_fatal("option -l/--list cannot be used when restoring an archive created by pg_dumpall");
     517          20 :         else if (opts->tocFile)
     518           0 :             pg_fatal("option -L/--use-list cannot be used when restoring an archive created by pg_dumpall");
     519             : 
     520             :         /*
     521             :          * To restore from a pg_dumpall archive, -C (create database) option
     522             :          * must be specified unless we are only restoring globals.
     523             :          */
     524          20 :         if (!globals_only && opts->createDB != 1)
     525             :         {
     526           2 :             pg_log_error("-C/--create option should be specified when restoring an archive created by pg_dumpall");
     527           2 :             pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     528           2 :             pg_log_error_hint("Individual databases can be restored using their specific archives.");
     529           2 :             exit_nicely(1);
     530             :         }
     531             : 
     532             :         /*
     533             :          * Connect to the database to execute global sql commands from
     534             :          * global.dat file.
     535             :          */
     536          18 :         if (opts->cparams.dbname)
     537             :         {
     538           2 :             conn = ConnectDatabase(opts->cparams.dbname, NULL, opts->cparams.pghost,
     539           2 :                                    opts->cparams.pgport, opts->cparams.username, TRI_DEFAULT,
     540             :                                    false, progname, NULL, NULL, NULL, NULL);
     541             : 
     542             : 
     543           2 :             if (!conn)
     544           2 :                 pg_fatal("could not connect to database \"%s\"", opts->cparams.dbname);
     545             :         }
     546             : 
     547             :         /* If globals-only, then return from here. */
     548          16 :         if (globals_only)
     549             :         {
     550             :             /*
     551             :              * Open global.dat file and execute/append all the global sql
     552             :              * commands.
     553             :              */
     554           2 :             n_errors = process_global_sql_commands(conn, inputFileSpec,
     555             :                                                    opts->filename);
     556             : 
     557           2 :             if (conn)
     558           0 :                 PQfinish(conn);
     559             : 
     560           2 :             pg_log_info("database restoring skipped as -g/--globals-only option was specified");
     561             :         }
     562             :         else
     563             :         {
     564             :             /* Now restore all the databases from map.dat */
     565          14 :             n_errors = restore_all_databases(conn, inputFileSpec, db_exclude_patterns,
     566             :                                              opts, numWorkers);
     567             :         }
     568             : 
     569             :         /* Free db pattern list. */
     570          16 :         simple_string_list_destroy(&db_exclude_patterns);
     571             :     }
     572             :     else                        /* process if global.dat file does not exist. */
     573             :     {
     574         110 :         if (db_exclude_patterns.head != NULL)
     575           2 :             pg_fatal("option --exclude-database can be used only when restoring an archive created by pg_dumpall");
     576             : 
     577         108 :         if (globals_only)
     578           2 :             pg_fatal("option -g/--globals-only can be used only when restoring an archive created by pg_dumpall");
     579             : 
     580         106 :         n_errors = restore_one_database(inputFileSpec, opts, numWorkers, false, 0);
     581             :     }
     582             : 
     583             :     /* Done, print a summary of ignored errors during restore. */
     584         122 :     if (n_errors)
     585             :     {
     586           0 :         pg_log_warning("errors ignored on restore: %d", n_errors);
     587           0 :         return 1;
     588             :     }
     589             : 
     590         122 :     return 0;
     591             : }
     592             : 
     593             : /*
     594             :  * restore_one_database
     595             :  *
     596             :  * This will restore one database using toc.dat file.
     597             :  *
     598             :  * returns the number of errors while doing restore.
     599             :  */
     600             : static int
     601         212 : restore_one_database(const char *inputFileSpec, RestoreOptions *opts,
     602             :                      int numWorkers, bool append_data, int num)
     603             : {
     604             :     Archive    *AH;
     605             :     int         n_errors;
     606             : 
     607         212 :     AH = OpenArchive(inputFileSpec, opts->format);
     608             : 
     609         212 :     SetArchiveOptions(AH, NULL, opts);
     610             : 
     611             :     /*
     612             :      * We don't have a connection yet but that doesn't matter. The connection
     613             :      * is initialized to NULL and if we terminate through exit_nicely() while
     614             :      * it's still NULL, the cleanup function will just be a no-op. If we are
     615             :      * restoring multiple databases, then only update AX handle for cleanup as
     616             :      * the previous entry was already in the array and we had closed previous
     617             :      * connection, so we can use the same array slot.
     618             :      */
     619         212 :     if (!append_data || num == 0)
     620         120 :         on_exit_close_archive(AH);
     621             :     else
     622          92 :         replace_on_exit_close_archive(AH);
     623             : 
     624             :     /* Let the archiver know how noisy to be */
     625         212 :     AH->verbose = opts->verbose;
     626             : 
     627             :     /*
     628             :      * Whether to keep submitting sql commands as "pg_restore ... | psql ... "
     629             :      */
     630         212 :     AH->exit_on_error = opts->exit_on_error;
     631             : 
     632         212 :     if (opts->tocFile)
     633           0 :         SortTocFromFile(AH);
     634             : 
     635         212 :     AH->numWorkers = numWorkers;
     636             : 
     637         212 :     if (opts->tocSummary)
     638           8 :         PrintTOCSummary(AH);
     639             :     else
     640             :     {
     641         204 :         ProcessArchiveRestoreOptions(AH);
     642         204 :         RestoreArchive(AH, append_data);
     643             :     }
     644             : 
     645         212 :     n_errors = AH->n_errors;
     646             : 
     647             :     /* AH may be freed in CloseArchive? */
     648         212 :     CloseArchive(AH);
     649             : 
     650         212 :     return n_errors;
     651             : }
     652             : 
     653             : static void
     654           2 : usage(const char *progname)
     655             : {
     656           2 :     printf(_("%s restores a PostgreSQL database from an archive created by pg_dump or pg_dumpall.\n"
     657             :              "If the archive is created by pg_dumpall, then restores multiple databases also.\n\n"), progname);
     658           2 :     printf(_("Usage:\n"));
     659           2 :     printf(_("  %s [OPTION]... [FILE]\n"), progname);
     660             : 
     661           2 :     printf(_("\nGeneral options:\n"));
     662           2 :     printf(_("  -d, --dbname=NAME        connect to database name\n"));
     663           2 :     printf(_("  -f, --file=FILENAME      output file name (- for stdout)\n"));
     664           2 :     printf(_("  -F, --format=c|d|t       backup file format (should be automatic)\n"));
     665           2 :     printf(_("  -l, --list               print summarized TOC of the archive\n"));
     666           2 :     printf(_("  -v, --verbose            verbose mode\n"));
     667           2 :     printf(_("  -V, --version            output version information, then exit\n"));
     668           2 :     printf(_("  -?, --help               show this help, then exit\n"));
     669             : 
     670           2 :     printf(_("\nOptions controlling the restore:\n"));
     671           2 :     printf(_("  -a, --data-only              restore only the data, no schema\n"));
     672           2 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
     673           2 :     printf(_("  -C, --create                 create the target database\n"));
     674           2 :     printf(_("  -e, --exit-on-error          exit on error, default is to continue\n"));
     675           2 :     printf(_("  -g, --globals-only           restore only global objects, no databases\n"));
     676           2 :     printf(_("  -I, --index=NAME             restore named index\n"));
     677           2 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to restore\n"));
     678           2 :     printf(_("  -L, --use-list=FILENAME      use table of contents from this file for\n"
     679             :              "                               selecting/ordering output\n"));
     680           2 :     printf(_("  -n, --schema=NAME            restore only objects in this schema\n"));
     681           2 :     printf(_("  -N, --exclude-schema=NAME    do not restore objects in this schema\n"));
     682           2 :     printf(_("  -O, --no-owner               skip restoration of object ownership\n"));
     683           2 :     printf(_("  -P, --function=NAME(args)    restore named function\n"));
     684           2 :     printf(_("  -s, --schema-only            restore only the schema, no data\n"));
     685           2 :     printf(_("  -S, --superuser=NAME         superuser user name to use for disabling triggers\n"));
     686           2 :     printf(_("  -t, --table=NAME             restore named relation (table, view, etc.)\n"));
     687           2 :     printf(_("  -T, --trigger=NAME           restore named trigger\n"));
     688           2 :     printf(_("  --exclude-database=PATTERN   exclude databases whose name matches with pattern\n"));
     689           2 :     printf(_("  -x, --no-privileges          skip restoration of access privileges (grant/revoke)\n"));
     690           2 :     printf(_("  -1, --single-transaction     restore as a single transaction\n"));
     691           2 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
     692           2 :     printf(_("  --enable-row-security        enable row security\n"));
     693           2 :     printf(_("  --filter=FILENAME            restore or skip objects based on expressions\n"
     694             :              "                               in FILENAME\n"));
     695           2 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
     696           2 :     printf(_("  --no-comments                do not restore comment commands\n"));
     697           2 :     printf(_("  --no-data                    do not restore data\n"));
     698           2 :     printf(_("  --no-data-for-failed-tables  do not restore data of tables that could not be\n"
     699             :              "                               created\n"));
     700           2 :     printf(_("  --no-policies                do not restore row security policies\n"));
     701           2 :     printf(_("  --no-publications            do not restore publications\n"));
     702           2 :     printf(_("  --no-schema                  do not restore schema\n"));
     703           2 :     printf(_("  --no-security-labels         do not restore security labels\n"));
     704           2 :     printf(_("  --no-statistics              do not restore statistics\n"));
     705           2 :     printf(_("  --no-subscriptions           do not restore subscriptions\n"));
     706           2 :     printf(_("  --no-table-access-method     do not restore table access methods\n"));
     707           2 :     printf(_("  --no-tablespaces             do not restore tablespace assignments\n"));
     708           2 :     printf(_("  --section=SECTION            restore named section (pre-data, data, or post-data)\n"));
     709           2 :     printf(_("  --statistics-only            restore only the statistics, not schema or data\n"));
     710           2 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
     711             :              "                               match at least one entity each\n"));
     712           2 :     printf(_("  --transaction-size=N         commit after every N objects\n"));
     713           2 :     printf(_("  --use-set-session-authorization\n"
     714             :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
     715             :              "                               ALTER OWNER commands to set ownership\n"));
     716           2 :     printf(_("  --with-data                  dump the data\n"));
     717           2 :     printf(_("  --with-schema                dump the schema\n"));
     718           2 :     printf(_("  --with-statistics            dump the statistics\n"));
     719             : 
     720           2 :     printf(_("\nConnection options:\n"));
     721           2 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
     722           2 :     printf(_("  -p, --port=PORT          database server port number\n"));
     723           2 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
     724           2 :     printf(_("  -w, --no-password        never prompt for password\n"));
     725           2 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
     726           2 :     printf(_("  --role=ROLENAME          do SET ROLE before restore\n"));
     727             : 
     728           2 :     printf(_("\n"
     729             :              "The options -I, -n, -N, -P, -t, -T, --section, and --exclude-database can be combined\n"
     730             :              "and specified multiple times to select multiple objects.\n"));
     731           2 :     printf(_("\nIf no input file name is supplied, then standard input is used.\n\n"));
     732           2 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     733           2 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
     734           2 : }
     735             : 
     736             : /*
     737             :  * read_restore_filters - retrieve object identifier patterns from file
     738             :  *
     739             :  * Parse the specified filter file for include and exclude patterns, and add
     740             :  * them to the relevant lists.  If the filename is "-" then filters will be
     741             :  * read from STDIN rather than a file.
     742             :  */
     743             : static void
     744          20 : read_restore_filters(const char *filename, RestoreOptions *opts)
     745             : {
     746             :     FilterStateData fstate;
     747             :     char       *objname;
     748             :     FilterCommandType comtype;
     749             :     FilterObjectType objtype;
     750             : 
     751          20 :     filter_init(&fstate, filename, exit_nicely);
     752             : 
     753          34 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
     754             :     {
     755          22 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
     756             :         {
     757          16 :             switch (objtype)
     758             :             {
     759           0 :                 case FILTER_OBJECT_TYPE_NONE:
     760           0 :                     break;
     761           4 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
     762             :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
     763             :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
     764             :                 case FILTER_OBJECT_TYPE_DATABASE:
     765             :                 case FILTER_OBJECT_TYPE_EXTENSION:
     766             :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
     767           4 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
     768             :                                         "include",
     769             :                                         filter_object_type_name(objtype));
     770           4 :                     exit_nicely(1);
     771             : 
     772           4 :                 case FILTER_OBJECT_TYPE_FUNCTION:
     773           4 :                     opts->selTypes = 1;
     774           4 :                     opts->selFunction = 1;
     775           4 :                     simple_string_list_append(&opts->functionNames, objname);
     776           4 :                     break;
     777           2 :                 case FILTER_OBJECT_TYPE_INDEX:
     778           2 :                     opts->selTypes = 1;
     779           2 :                     opts->selIndex = 1;
     780           2 :                     simple_string_list_append(&opts->indexNames, objname);
     781           2 :                     break;
     782           2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
     783           2 :                     simple_string_list_append(&opts->schemaNames, objname);
     784           2 :                     break;
     785           2 :                 case FILTER_OBJECT_TYPE_TABLE:
     786           2 :                     opts->selTypes = 1;
     787           2 :                     opts->selTable = 1;
     788           2 :                     simple_string_list_append(&opts->tableNames, objname);
     789           2 :                     break;
     790           2 :                 case FILTER_OBJECT_TYPE_TRIGGER:
     791           2 :                     opts->selTypes = 1;
     792           2 :                     opts->selTrigger = 1;
     793           2 :                     simple_string_list_append(&opts->triggerNames, objname);
     794           2 :                     break;
     795             :             }
     796          12 :         }
     797           6 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
     798             :         {
     799           6 :             switch (objtype)
     800             :             {
     801           0 :                 case FILTER_OBJECT_TYPE_NONE:
     802           0 :                     break;
     803           4 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
     804             :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
     805             :                 case FILTER_OBJECT_TYPE_DATABASE:
     806             :                 case FILTER_OBJECT_TYPE_EXTENSION:
     807             :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
     808             :                 case FILTER_OBJECT_TYPE_FUNCTION:
     809             :                 case FILTER_OBJECT_TYPE_INDEX:
     810             :                 case FILTER_OBJECT_TYPE_TABLE:
     811             :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
     812             :                 case FILTER_OBJECT_TYPE_TRIGGER:
     813           4 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
     814             :                                         "exclude",
     815             :                                         filter_object_type_name(objtype));
     816           4 :                     exit_nicely(1);
     817             : 
     818           2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
     819           2 :                     simple_string_list_append(&opts->schemaExcludeNames, objname);
     820           2 :                     break;
     821             :             }
     822           2 :         }
     823             :         else
     824             :         {
     825             :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
     826             :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
     827             :         }
     828             : 
     829          14 :         if (objname)
     830          14 :             free(objname);
     831             :     }
     832             : 
     833          12 :     filter_free(&fstate);
     834          12 : }
     835             : 
     836             : /*
     837             :  * file_exists_in_directory
     838             :  *
     839             :  * Returns true if the file exists in the given directory.
     840             :  */
     841             : static bool
     842         448 : file_exists_in_directory(const char *dir, const char *filename)
     843             : {
     844             :     struct stat st;
     845             :     char        buf[MAXPGPATH];
     846             : 
     847         448 :     if (snprintf(buf, MAXPGPATH, "%s/%s", dir, filename) >= MAXPGPATH)
     848           0 :         pg_fatal("directory name too long: \"%s\"", dir);
     849             : 
     850         448 :     return (stat(buf, &st) == 0 && S_ISREG(st.st_mode));
     851             : }
     852             : 
     853             : /*
     854             :  * read_one_statement
     855             :  *
     856             :  * This will start reading from passed file pointer using fgetc and read till
     857             :  * semicolon(sql statement terminator for global.dat file)
     858             :  *
     859             :  * EOF is returned if end-of-file input is seen; time to shut down.
     860             :  */
     861             : 
     862             : static int
     863           0 : read_one_statement(StringInfo inBuf, FILE *pfile)
     864             : {
     865             :     int         c;              /* character read from getc() */
     866             :     int         m;
     867             : 
     868             :     StringInfoData q;
     869             : 
     870           0 :     initStringInfo(&q);
     871             : 
     872           0 :     resetStringInfo(inBuf);
     873             : 
     874             :     /*
     875             :      * Read characters until EOF or the appropriate delimiter is seen.
     876             :      */
     877           0 :     while ((c = fgetc(pfile)) != EOF)
     878             :     {
     879           0 :         if (c != '\'' && c != '"' && c != '\n' && c != ';')
     880             :         {
     881           0 :             appendStringInfoChar(inBuf, (char) c);
     882           0 :             while ((c = fgetc(pfile)) != EOF)
     883             :             {
     884           0 :                 if (c != '\'' && c != '"' && c != ';' && c != '\n')
     885           0 :                     appendStringInfoChar(inBuf, (char) c);
     886             :                 else
     887             :                     break;
     888             :             }
     889             :         }
     890             : 
     891           0 :         if (c == '\'' || c == '"')
     892             :         {
     893           0 :             appendStringInfoChar(&q, (char) c);
     894           0 :             m = c;
     895             : 
     896           0 :             while ((c = fgetc(pfile)) != EOF)
     897             :             {
     898           0 :                 appendStringInfoChar(&q, (char) c);
     899             : 
     900           0 :                 if (c == m)
     901             :                 {
     902           0 :                     appendStringInfoString(inBuf, q.data);
     903           0 :                     resetStringInfo(&q);
     904           0 :                     break;
     905             :                 }
     906             :             }
     907             :         }
     908             : 
     909           0 :         if (c == ';')
     910             :         {
     911           0 :             appendStringInfoChar(inBuf, (char) ';');
     912           0 :             break;
     913             :         }
     914             : 
     915           0 :         if (c == '\n')
     916           0 :             appendStringInfoChar(inBuf, (char) '\n');
     917             :     }
     918             : 
     919           0 :     pg_free(q.data);
     920             : 
     921             :     /* No input before EOF signal means time to quit. */
     922           0 :     if (c == EOF && inBuf->len == 0)
     923           0 :         return EOF;
     924             : 
     925             :     /* return something that's not EOF */
     926           0 :     return 'Q';
     927             : }
     928             : 
     929             : /*
     930             :  * get_dbnames_list_to_restore
     931             :  *
     932             :  * This will mark for skipping any entries from dbname_oid_list that pattern match an
     933             :  * entry in the db_exclude_patterns list.
     934             :  *
     935             :  * Returns the number of database to be restored.
     936             :  *
     937             :  */
     938             : static int
     939          14 : get_dbnames_list_to_restore(PGconn *conn,
     940             :                             SimplePtrList *dbname_oid_list,
     941             :                             SimpleStringList db_exclude_patterns)
     942             : {
     943          14 :     int         count_db = 0;
     944             :     PQExpBuffer query;
     945             :     PGresult   *res;
     946             : 
     947          14 :     query = createPQExpBuffer();
     948             : 
     949          14 :     if (!conn)
     950           0 :         pg_log_info("considering PATTERN as NAME for --exclude-database option as no db connection while doing pg_restore.");
     951             : 
     952             :     /*
     953             :      * Process one by one all dbnames and if specified to skip restoring, then
     954             :      * remove dbname from list.
     955             :      */
     956         122 :     for (SimplePtrListCell *db_cell = dbname_oid_list->head;
     957         108 :          db_cell; db_cell = db_cell->next)
     958             :     {
     959         108 :         DbOidName  *dbidname = (DbOidName *) db_cell->ptr;
     960         108 :         bool        skip_db_restore = false;
     961         108 :         PQExpBuffer db_lit = createPQExpBuffer();
     962             : 
     963         108 :         appendStringLiteralConn(db_lit, dbidname->str, conn);
     964             : 
     965         118 :         for (SimpleStringListCell *pat_cell = db_exclude_patterns.head; pat_cell; pat_cell = pat_cell->next)
     966             :         {
     967             :             /*
     968             :              * If there is an exact match then we don't need to try a pattern
     969             :              * match
     970             :              */
     971          12 :             if (pg_strcasecmp(dbidname->str, pat_cell->val) == 0)
     972           2 :                 skip_db_restore = true;
     973             :             /* Otherwise, try a pattern match if there is a connection */
     974          10 :             else if (conn)
     975             :             {
     976             :                 int         dotcnt;
     977             : 
     978          10 :                 appendPQExpBufferStr(query, "SELECT 1 ");
     979          10 :                 processSQLNamePattern(conn, query, pat_cell->val, false,
     980          10 :                                       false, NULL, db_lit->data,
     981             :                                       NULL, NULL, NULL, &dotcnt);
     982             : 
     983          10 :                 if (dotcnt > 0)
     984             :                 {
     985           0 :                     pg_log_error("improper qualified name (too many dotted names): %s",
     986             :                                  dbidname->str);
     987           0 :                     PQfinish(conn);
     988           0 :                     exit_nicely(1);
     989             :                 }
     990             : 
     991          10 :                 res = executeQuery(conn, query->data);
     992             : 
     993          10 :                 if ((PQresultStatus(res) == PGRES_TUPLES_OK) && PQntuples(res))
     994             :                 {
     995           0 :                     skip_db_restore = true;
     996           0 :                     pg_log_info("database \"%s\" matches exclude pattern: \"%s\"", dbidname->str, pat_cell->val);
     997             :                 }
     998             : 
     999          10 :                 PQclear(res);
    1000          10 :                 resetPQExpBuffer(query);
    1001             :             }
    1002             : 
    1003          12 :             if (skip_db_restore)
    1004           2 :                 break;
    1005             :         }
    1006             : 
    1007         108 :         destroyPQExpBuffer(db_lit);
    1008             : 
    1009             :         /*
    1010             :          * Mark db to be skipped or increment the counter of dbs to be
    1011             :          * restored
    1012             :          */
    1013         108 :         if (skip_db_restore)
    1014             :         {
    1015           2 :             pg_log_info("excluding database \"%s\"", dbidname->str);
    1016           2 :             dbidname->oid = InvalidOid;
    1017             :         }
    1018             :         else
    1019             :         {
    1020         106 :             count_db++;
    1021             :         }
    1022             :     }
    1023             : 
    1024          14 :     destroyPQExpBuffer(query);
    1025             : 
    1026          14 :     return count_db;
    1027             : }
    1028             : 
    1029             : /*
    1030             :  * get_dbname_oid_list_from_mfile
    1031             :  *
    1032             :  * Open map.dat file and read line by line and then prepare a list of database
    1033             :  * names and corresponding db_oid.
    1034             :  *
    1035             :  * Returns, total number of database names in map.dat file.
    1036             :  */
    1037             : static int
    1038          14 : get_dbname_oid_list_from_mfile(const char *dumpdirpath, SimplePtrList *dbname_oid_list)
    1039             : {
    1040             :     StringInfoData linebuf;
    1041             :     FILE       *pfile;
    1042             :     char        map_file_path[MAXPGPATH];
    1043          14 :     int         count = 0;
    1044             : 
    1045             : 
    1046             :     /*
    1047             :      * If there is only global.dat file in dump, then return from here as
    1048             :      * there is no database to restore.
    1049             :      */
    1050          14 :     if (!file_exists_in_directory(dumpdirpath, "map.dat"))
    1051             :     {
    1052           0 :         pg_log_info("database restoring is skipped as \"map.dat\" is not present in \"%s\"", dumpdirpath);
    1053           0 :         return 0;
    1054             :     }
    1055             : 
    1056          14 :     snprintf(map_file_path, MAXPGPATH, "%s/map.dat", dumpdirpath);
    1057             : 
    1058             :     /* Open map.dat file. */
    1059          14 :     pfile = fopen(map_file_path, PG_BINARY_R);
    1060             : 
    1061          14 :     if (pfile == NULL)
    1062           0 :         pg_fatal("could not open \"%s\": %m", map_file_path);
    1063             : 
    1064          14 :     initStringInfo(&linebuf);
    1065             : 
    1066             :     /* Append all the dbname/db_oid combinations to the list. */
    1067         122 :     while (pg_get_line_buf(pfile, &linebuf))
    1068             :     {
    1069         108 :         Oid         db_oid = InvalidOid;
    1070             :         char       *dbname;
    1071             :         DbOidName  *dbidname;
    1072             :         int         namelen;
    1073         108 :         char       *p = linebuf.data;
    1074             : 
    1075             :         /* Extract dboid. */
    1076         536 :         while (isdigit((unsigned char) *p))
    1077         428 :             p++;
    1078         108 :         if (p > linebuf.data && *p == ' ')
    1079             :         {
    1080         108 :             sscanf(linebuf.data, "%u", &db_oid);
    1081         108 :             p++;
    1082             :         }
    1083             : 
    1084             :         /* dbname is the rest of the line */
    1085         108 :         dbname = p;
    1086         108 :         namelen = strlen(dbname);
    1087             : 
    1088             :         /* Report error and exit if the file has any corrupted data. */
    1089         108 :         if (!OidIsValid(db_oid) || namelen <= 1)
    1090           0 :             pg_fatal("invalid entry in \"%s\" at line: %d", map_file_path,
    1091             :                      count + 1);
    1092             : 
    1093         108 :         pg_log_info("found database \"%s\" (OID: %u) in \"%s\"",
    1094             :                     dbname, db_oid, map_file_path);
    1095             : 
    1096         108 :         dbidname = pg_malloc(offsetof(DbOidName, str) + namelen + 1);
    1097         108 :         dbidname->oid = db_oid;
    1098         108 :         strlcpy(dbidname->str, dbname, namelen);
    1099             : 
    1100         108 :         simple_ptr_list_append(dbname_oid_list, dbidname);
    1101         108 :         count++;
    1102             :     }
    1103             : 
    1104             :     /* Close map.dat file. */
    1105          14 :     fclose(pfile);
    1106             : 
    1107          14 :     return count;
    1108             : }
    1109             : 
    1110             : /*
    1111             :  * restore_all_databases
    1112             :  *
    1113             :  * This will restore databases those dumps are present in
    1114             :  * directory based on map.dat file mapping.
    1115             :  *
    1116             :  * This will skip restoring for databases that are specified with
    1117             :  * exclude-database option.
    1118             :  *
    1119             :  * returns, number of errors while doing restore.
    1120             :  */
    1121             : static int
    1122          14 : restore_all_databases(PGconn *conn, const char *dumpdirpath,
    1123             :                       SimpleStringList db_exclude_patterns, RestoreOptions *opts,
    1124             :                       int numWorkers)
    1125             : {
    1126          14 :     SimplePtrList dbname_oid_list = {NULL, NULL};
    1127          14 :     int         num_db_restore = 0;
    1128             :     int         num_total_db;
    1129             :     int         n_errors_total;
    1130          14 :     int         count = 0;
    1131          14 :     char       *connected_db = NULL;
    1132          14 :     bool        dumpData = opts->dumpData;
    1133          14 :     bool        dumpSchema = opts->dumpSchema;
    1134          14 :     bool        dumpStatistics = opts->dumpSchema;
    1135             : 
    1136             :     /* Save db name to reuse it for all the database. */
    1137          14 :     if (opts->cparams.dbname)
    1138           0 :         connected_db = opts->cparams.dbname;
    1139             : 
    1140          14 :     num_total_db = get_dbname_oid_list_from_mfile(dumpdirpath, &dbname_oid_list);
    1141             : 
    1142             :     /* If map.dat has no entries, return after processing global.dat */
    1143          14 :     if (dbname_oid_list.head == NULL)
    1144           0 :         return process_global_sql_commands(conn, dumpdirpath, opts->filename);
    1145             : 
    1146          14 :     pg_log_info("found %d database names in \"map.dat\"", num_total_db);
    1147             : 
    1148          14 :     if (!conn)
    1149             :     {
    1150          14 :         pg_log_info("trying to connect database \"postgres\"");
    1151             : 
    1152          14 :         conn = ConnectDatabase("postgres", NULL, opts->cparams.pghost,
    1153          14 :                                opts->cparams.pgport, opts->cparams.username, TRI_DEFAULT,
    1154             :                                false, progname, NULL, NULL, NULL, NULL);
    1155             : 
    1156             :         /* Try with template1. */
    1157          14 :         if (!conn)
    1158             :         {
    1159           0 :             pg_log_info("trying to connect database \"template1\"");
    1160             : 
    1161           0 :             conn = ConnectDatabase("template1", NULL, opts->cparams.pghost,
    1162           0 :                                    opts->cparams.pgport, opts->cparams.username, TRI_DEFAULT,
    1163             :                                    false, progname, NULL, NULL, NULL, NULL);
    1164             :         }
    1165             :     }
    1166             : 
    1167             :     /*
    1168             :      * filter the db list according to the exclude patterns
    1169             :      */
    1170          14 :     num_db_restore = get_dbnames_list_to_restore(conn, &dbname_oid_list,
    1171             :                                                  db_exclude_patterns);
    1172             : 
    1173             :     /* Open global.dat file and execute/append all the global sql commands. */
    1174          14 :     n_errors_total = process_global_sql_commands(conn, dumpdirpath, opts->filename);
    1175             : 
    1176             :     /* Close the db connection as we are done with globals and patterns. */
    1177          14 :     if (conn)
    1178          14 :         PQfinish(conn);
    1179             : 
    1180             :     /* Exit if no db needs to be restored. */
    1181          14 :     if (dbname_oid_list.head == NULL || num_db_restore == 0)
    1182             :     {
    1183           0 :         pg_log_info("no database needs to restore out of %d databases", num_total_db);
    1184           0 :         return n_errors_total;
    1185             :     }
    1186             : 
    1187          14 :     pg_log_info("need to restore %d databases out of %d databases", num_db_restore, num_total_db);
    1188             : 
    1189             :     /*
    1190             :      * We have a list of databases to restore after processing the
    1191             :      * exclude-database switch(es).  Now we can restore them one by one.
    1192             :      */
    1193         122 :     for (SimplePtrListCell *db_cell = dbname_oid_list.head;
    1194         108 :          db_cell; db_cell = db_cell->next)
    1195             :     {
    1196         108 :         DbOidName  *dbidname = (DbOidName *) db_cell->ptr;
    1197             :         char        subdirpath[MAXPGPATH];
    1198             :         char        subdirdbpath[MAXPGPATH];
    1199             :         char        dbfilename[MAXPGPATH];
    1200             :         int         n_errors;
    1201             : 
    1202             :         /* ignore dbs marked for skipping */
    1203         108 :         if (dbidname->oid == InvalidOid)
    1204           2 :             continue;
    1205             : 
    1206             :         /*
    1207             :          * We need to reset override_dbname so that objects can be restored
    1208             :          * into an already created database. (used with -d/--dbname option)
    1209             :          */
    1210         106 :         if (opts->cparams.override_dbname)
    1211             :         {
    1212           0 :             pfree(opts->cparams.override_dbname);
    1213           0 :             opts->cparams.override_dbname = NULL;
    1214             :         }
    1215             : 
    1216         106 :         snprintf(subdirdbpath, MAXPGPATH, "%s/databases", dumpdirpath);
    1217             : 
    1218             :         /*
    1219             :          * Look for the database dump file/dir. If there is an {oid}.tar or
    1220             :          * {oid}.dmp file, use it. Otherwise try to use a directory called
    1221             :          * {oid}
    1222             :          */
    1223         106 :         snprintf(dbfilename, MAXPGPATH, "%u.tar", dbidname->oid);
    1224         106 :         if (file_exists_in_directory(subdirdbpath, dbfilename))
    1225          16 :             snprintf(subdirpath, MAXPGPATH, "%s/databases/%u.tar", dumpdirpath, dbidname->oid);
    1226             :         else
    1227             :         {
    1228          90 :             snprintf(dbfilename, MAXPGPATH, "%u.dmp", dbidname->oid);
    1229             : 
    1230          90 :             if (file_exists_in_directory(subdirdbpath, dbfilename))
    1231          16 :                 snprintf(subdirpath, MAXPGPATH, "%s/databases/%u.dmp", dumpdirpath, dbidname->oid);
    1232             :             else
    1233          74 :                 snprintf(subdirpath, MAXPGPATH, "%s/databases/%u", dumpdirpath, dbidname->oid);
    1234             :         }
    1235             : 
    1236         106 :         pg_log_info("restoring database \"%s\"", dbidname->str);
    1237             : 
    1238             :         /* If database is already created, then don't set createDB flag. */
    1239         106 :         if (opts->cparams.dbname)
    1240             :         {
    1241             :             PGconn     *test_conn;
    1242             : 
    1243           0 :             test_conn = ConnectDatabase(dbidname->str, NULL, opts->cparams.pghost,
    1244           0 :                                         opts->cparams.pgport, opts->cparams.username, TRI_DEFAULT,
    1245             :                                         false, progname, NULL, NULL, NULL, NULL);
    1246           0 :             if (test_conn)
    1247             :             {
    1248           0 :                 PQfinish(test_conn);
    1249             : 
    1250             :                 /* Use already created database for connection. */
    1251           0 :                 opts->createDB = 0;
    1252           0 :                 opts->cparams.dbname = dbidname->str;
    1253             :             }
    1254             :             else
    1255             :             {
    1256             :                 /* we'll have to create it */
    1257           0 :                 opts->createDB = 1;
    1258           0 :                 opts->cparams.dbname = connected_db;
    1259             :             }
    1260             :         }
    1261             : 
    1262             :         /*
    1263             :          * Reset flags - might have been reset in pg_backup_archiver.c by the
    1264             :          * previous restore.
    1265             :          */
    1266         106 :         opts->dumpData = dumpData;
    1267         106 :         opts->dumpSchema = dumpSchema;
    1268         106 :         opts->dumpStatistics = dumpStatistics;
    1269             : 
    1270             :         /* Restore the single database. */
    1271         106 :         n_errors = restore_one_database(subdirpath, opts, numWorkers, true, count);
    1272             : 
    1273             :         /* Print a summary of ignored errors during single database restore. */
    1274         106 :         if (n_errors)
    1275             :         {
    1276           0 :             n_errors_total += n_errors;
    1277           0 :             pg_log_warning("errors ignored on database \"%s\" restore: %d", dbidname->str, n_errors);
    1278             :         }
    1279             : 
    1280         106 :         count++;
    1281             :     }
    1282             : 
    1283             :     /* Log number of processed databases. */
    1284          14 :     pg_log_info("number of restored databases is %d", num_db_restore);
    1285             : 
    1286             :     /* Free dbname and dboid list. */
    1287          14 :     simple_ptr_list_destroy(&dbname_oid_list);
    1288             : 
    1289          14 :     return n_errors_total;
    1290             : }
    1291             : 
    1292             : /*
    1293             :  * process_global_sql_commands
    1294             :  *
    1295             :  * Open global.dat and execute or copy the sql commands one by one.
    1296             :  *
    1297             :  * If outfile is not NULL, copy all sql commands into outfile rather than
    1298             :  * executing them.
    1299             :  *
    1300             :  * Returns the number of errors while processing global.dat
    1301             :  */
    1302             : static int
    1303          16 : process_global_sql_commands(PGconn *conn, const char *dumpdirpath, const char *outfile)
    1304             : {
    1305             :     char        global_file_path[MAXPGPATH];
    1306             :     PGresult   *result;
    1307             :     StringInfoData sqlstatement,
    1308             :                 user_create;
    1309             :     FILE       *pfile;
    1310          16 :     int         n_errors = 0;
    1311             : 
    1312          16 :     snprintf(global_file_path, MAXPGPATH, "%s/global.dat", dumpdirpath);
    1313             : 
    1314             :     /* Open global.dat file. */
    1315          16 :     pfile = fopen(global_file_path, PG_BINARY_R);
    1316             : 
    1317          16 :     if (pfile == NULL)
    1318           0 :         pg_fatal("could not open \"%s\": %m", global_file_path);
    1319             : 
    1320             :     /*
    1321             :      * If outfile is given, then just copy all global.dat file data into
    1322             :      * outfile.
    1323             :      */
    1324          16 :     if (outfile)
    1325             :     {
    1326          16 :         copy_or_print_global_file(outfile, pfile);
    1327          16 :         return 0;
    1328             :     }
    1329             : 
    1330             :     /* Init sqlstatement to append commands. */
    1331           0 :     initStringInfo(&sqlstatement);
    1332             : 
    1333             :     /* creation statement for our current role */
    1334           0 :     initStringInfo(&user_create);
    1335           0 :     appendStringInfoString(&user_create, "CREATE ROLE ");
    1336             :     /* should use fmtId here, but we don't know the encoding */
    1337           0 :     appendStringInfoString(&user_create, PQuser(conn));
    1338           0 :     appendStringInfoChar(&user_create, ';');
    1339             : 
    1340             :     /* Process file till EOF and execute sql statements. */
    1341           0 :     while (read_one_statement(&sqlstatement, pfile) != EOF)
    1342             :     {
    1343             :         /* don't try to create the role we are connected as */
    1344           0 :         if (strstr(sqlstatement.data, user_create.data))
    1345           0 :             continue;
    1346             : 
    1347           0 :         pg_log_info("executing query: %s", sqlstatement.data);
    1348           0 :         result = PQexec(conn, sqlstatement.data);
    1349             : 
    1350           0 :         switch (PQresultStatus(result))
    1351             :         {
    1352           0 :             case PGRES_COMMAND_OK:
    1353             :             case PGRES_TUPLES_OK:
    1354             :             case PGRES_EMPTY_QUERY:
    1355           0 :                 break;
    1356           0 :             default:
    1357           0 :                 n_errors++;
    1358           0 :                 pg_log_error("could not execute query: \"%s\" \nCommand was: \"%s\"", PQerrorMessage(conn), sqlstatement.data);
    1359             :         }
    1360           0 :         PQclear(result);
    1361             :     }
    1362             : 
    1363             :     /* Print a summary of ignored errors during global.dat. */
    1364           0 :     if (n_errors)
    1365           0 :         pg_log_warning("ignored %d errors in \"%s\"", n_errors, global_file_path);
    1366             : 
    1367           0 :     fclose(pfile);
    1368             : 
    1369           0 :     return n_errors;
    1370             : }
    1371             : 
    1372             : /*
    1373             :  * copy_or_print_global_file
    1374             :  *
    1375             :  * Copy global.dat into the output file.  If "-" is used as outfile,
    1376             :  * then print commands to stdout.
    1377             :  */
    1378             : static void
    1379          16 : copy_or_print_global_file(const char *outfile, FILE *pfile)
    1380             : {
    1381             :     char        out_file_path[MAXPGPATH];
    1382             :     FILE       *OPF;
    1383             :     int         c;
    1384             : 
    1385             :     /* "-" is used for stdout. */
    1386          16 :     if (strcmp(outfile, "-") == 0)
    1387           0 :         OPF = stdout;
    1388             :     else
    1389             :     {
    1390          16 :         snprintf(out_file_path, MAXPGPATH, "%s", outfile);
    1391          16 :         OPF = fopen(out_file_path, PG_BINARY_W);
    1392             : 
    1393          16 :         if (OPF == NULL)
    1394             :         {
    1395           0 :             fclose(pfile);
    1396           0 :             pg_fatal("could not open file: \"%s\"", outfile);
    1397             :         }
    1398             :     }
    1399             : 
    1400             :     /* Append global.dat into output file or print to stdout. */
    1401       37744 :     while ((c = fgetc(pfile)) != EOF)
    1402       37728 :         fputc(c, OPF);
    1403             : 
    1404          16 :     fclose(pfile);
    1405             : 
    1406             :     /* Close output file. */
    1407          16 :     if (strcmp(outfile, "-") != 0)
    1408          16 :         fclose(OPF);
    1409          16 : }

Generated by: LCOV version 1.14