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

Generated by: LCOV version 2.0-1