LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_backup_archiver.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 2394 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 96 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * pg_backup_archiver.c
       4              :  *
       5              :  *      Private implementation of the archiver routines.
       6              :  *
       7              :  *      See the headers to pg_restore for more details.
       8              :  *
       9              :  * Copyright (c) 2000, Philip Warner
      10              :  *      Rights are granted to use this software in any way so long
      11              :  *      as this notice is not removed.
      12              :  *
      13              :  *      The author is not responsible for loss or damages that may
      14              :  *      result from its use.
      15              :  *
      16              :  *
      17              :  * IDENTIFICATION
      18              :  *              src/bin/pg_dump/pg_backup_archiver.c
      19              :  *
      20              :  *-------------------------------------------------------------------------
      21              :  */
      22              : #include "postgres_fe.h"
      23              : 
      24              : #include <ctype.h>
      25              : #include <fcntl.h>
      26              : #include <unistd.h>
      27              : #include <sys/stat.h>
      28              : #include <sys/wait.h>
      29              : #ifdef WIN32
      30              : #include <io.h>
      31              : #endif
      32              : 
      33              : #include "catalog/pg_class_d.h"
      34              : #include "catalog/pg_largeobject_metadata_d.h"
      35              : #include "catalog/pg_shdepend_d.h"
      36              : #include "common/string.h"
      37              : #include "compress_io.h"
      38              : #include "dumputils.h"
      39              : #include "fe_utils/string_utils.h"
      40              : #include "lib/binaryheap.h"
      41              : #include "lib/stringinfo.h"
      42              : #include "libpq/libpq-fs.h"
      43              : #include "parallel.h"
      44              : #include "pg_backup_archiver.h"
      45              : #include "pg_backup_db.h"
      46              : #include "pg_backup_utils.h"
      47              : 
      48              : #define TEXT_DUMP_HEADER "--\n-- PostgreSQL database dump\n--\n\n"
      49              : #define TEXT_DUMPALL_HEADER "--\n-- PostgreSQL database cluster dump\n--\n\n"
      50              : 
      51              : #define TOC_PREFIX_NONE         ""
      52              : #define TOC_PREFIX_DATA         "Data for "
      53              : #define TOC_PREFIX_STATS        "Statistics for "
      54              : 
      55              : static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
      56              :                                                            const pg_compress_specification compression_spec,
      57              :                                                            bool dosync, ArchiveMode mode,
      58              :                                                            SetupWorkerPtrType setupWorkerPtr,
      59              :                                                            DataDirSyncMethod sync_method);
      60              : static void _getObjectDescription(PQExpBuffer buf, const TocEntry *te);
      61              : static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, const char *pfx);
      62              : static void _doSetFixedOutputState(ArchiveHandle *AH);
      63              : static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
      64              : static void _reconnectToDB(ArchiveHandle *AH, const char *dbname);
      65              : static void _becomeUser(ArchiveHandle *AH, const char *user);
      66              : static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
      67              : static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
      68              : static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
      69              : static void _selectTableAccessMethod(ArchiveHandle *AH, const char *tableam);
      70              : static void _printTableAccessMethodNoStorage(ArchiveHandle *AH,
      71              :                                                                                          TocEntry *te);
      72              : static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
      73              : static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
      74              : static void processSearchPathEntry(ArchiveHandle *AH, TocEntry *te);
      75              : static int      _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH);
      76              : static RestorePass _tocEntryRestorePass(TocEntry *te);
      77              : static bool _tocEntryIsACL(TocEntry *te);
      78              : static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te);
      79              : static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te);
      80              : static bool is_load_via_partition_root(TocEntry *te);
      81              : static void buildTocEntryArrays(ArchiveHandle *AH);
      82              : static void _moveBefore(TocEntry *pos, TocEntry *te);
      83              : static int      _discoverArchiveFormat(ArchiveHandle *AH);
      84              : 
      85              : static int      RestoringToDB(ArchiveHandle *AH);
      86              : static void dump_lo_buf(ArchiveHandle *AH);
      87              : static void dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim);
      88              : static void SetOutput(ArchiveHandle *AH, const char *filename,
      89              :                                           const pg_compress_specification compression_spec);
      90              : static CompressFileHandle *SaveOutput(ArchiveHandle *AH);
      91              : static void RestoreOutput(ArchiveHandle *AH, CompressFileHandle *savedOutput);
      92              : 
      93              : static int      restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel);
      94              : static void restore_toc_entries_prefork(ArchiveHandle *AH,
      95              :                                                                                 TocEntry *pending_list);
      96              : static void restore_toc_entries_parallel(ArchiveHandle *AH,
      97              :                                                                                  ParallelState *pstate,
      98              :                                                                                  TocEntry *pending_list);
      99              : static void restore_toc_entries_postfork(ArchiveHandle *AH,
     100              :                                                                                  TocEntry *pending_list);
     101              : static void pending_list_header_init(TocEntry *l);
     102              : static void pending_list_append(TocEntry *l, TocEntry *te);
     103              : static void pending_list_remove(TocEntry *te);
     104              : static int      TocEntrySizeCompareQsort(const void *p1, const void *p2);
     105              : static int      TocEntrySizeCompareBinaryheap(void *p1, void *p2, void *arg);
     106              : static void move_to_ready_heap(TocEntry *pending_list,
     107              :                                                            binaryheap *ready_heap,
     108              :                                                            RestorePass pass);
     109              : static TocEntry *pop_next_work_item(binaryheap *ready_heap,
     110              :                                                                         ParallelState *pstate);
     111              : static void mark_dump_job_done(ArchiveHandle *AH,
     112              :                                                            TocEntry *te,
     113              :                                                            int status,
     114              :                                                            void *callback_data);
     115              : static void mark_restore_job_done(ArchiveHandle *AH,
     116              :                                                                   TocEntry *te,
     117              :                                                                   int status,
     118              :                                                                   void *callback_data);
     119              : static void fix_dependencies(ArchiveHandle *AH);
     120              : static bool has_lock_conflicts(TocEntry *te1, TocEntry *te2);
     121              : static void repoint_table_dependencies(ArchiveHandle *AH);
     122              : static void identify_locking_dependencies(ArchiveHandle *AH, TocEntry *te);
     123              : static void reduce_dependencies(ArchiveHandle *AH, TocEntry *te,
     124              :                                                                 binaryheap *ready_heap);
     125              : static void mark_create_done(ArchiveHandle *AH, TocEntry *te);
     126              : static void inhibit_data_for_failed_table(ArchiveHandle *AH, TocEntry *te);
     127              : 
     128              : static void StrictNamesCheck(RestoreOptions *ropt);
     129              : 
     130              : 
     131              : /*
     132              :  * Allocate a new DumpOptions block containing all default values.
     133              :  */
     134              : DumpOptions *
     135            0 : NewDumpOptions(void)
     136              : {
     137            0 :         DumpOptions *opts = (DumpOptions *) pg_malloc(sizeof(DumpOptions));
     138              : 
     139            0 :         InitDumpOptions(opts);
     140            0 :         return opts;
     141            0 : }
     142              : 
     143              : /*
     144              :  * Initialize a DumpOptions struct to all default values
     145              :  */
     146              : void
     147            0 : InitDumpOptions(DumpOptions *opts)
     148              : {
     149            0 :         memset(opts, 0, sizeof(DumpOptions));
     150              :         /* set any fields that shouldn't default to zeroes */
     151            0 :         opts->include_everything = true;
     152            0 :         opts->cparams.promptPassword = TRI_DEFAULT;
     153            0 :         opts->dumpSections = DUMP_UNSECTIONED;
     154            0 :         opts->dumpSchema = true;
     155            0 :         opts->dumpData = true;
     156            0 :         opts->dumpStatistics = false;
     157            0 : }
     158              : 
     159              : /*
     160              :  * Create a freshly allocated DumpOptions with options equivalent to those
     161              :  * found in the given RestoreOptions.
     162              :  */
     163              : DumpOptions *
     164            0 : dumpOptionsFromRestoreOptions(RestoreOptions *ropt)
     165              : {
     166            0 :         DumpOptions *dopt = NewDumpOptions();
     167              : 
     168              :         /* this is the inverse of what's at the end of pg_dump.c's main() */
     169            0 :         dopt->cparams.dbname = ropt->cparams.dbname ? pg_strdup(ropt->cparams.dbname) : NULL;
     170            0 :         dopt->cparams.pgport = ropt->cparams.pgport ? pg_strdup(ropt->cparams.pgport) : NULL;
     171            0 :         dopt->cparams.pghost = ropt->cparams.pghost ? pg_strdup(ropt->cparams.pghost) : NULL;
     172            0 :         dopt->cparams.username = ropt->cparams.username ? pg_strdup(ropt->cparams.username) : NULL;
     173            0 :         dopt->cparams.promptPassword = ropt->cparams.promptPassword;
     174            0 :         dopt->outputClean = ropt->dropSchema;
     175            0 :         dopt->dumpData = ropt->dumpData;
     176            0 :         dopt->dumpSchema = ropt->dumpSchema;
     177            0 :         dopt->dumpSections = ropt->dumpSections;
     178            0 :         dopt->dumpStatistics = ropt->dumpStatistics;
     179            0 :         dopt->if_exists = ropt->if_exists;
     180            0 :         dopt->column_inserts = ropt->column_inserts;
     181            0 :         dopt->aclsSkip = ropt->aclsSkip;
     182            0 :         dopt->outputSuperuser = ropt->superuser;
     183            0 :         dopt->outputCreateDB = ropt->createDB;
     184            0 :         dopt->outputNoOwner = ropt->noOwner;
     185            0 :         dopt->outputNoTableAm = ropt->noTableAm;
     186            0 :         dopt->outputNoTablespaces = ropt->noTablespace;
     187            0 :         dopt->disable_triggers = ropt->disable_triggers;
     188            0 :         dopt->use_setsessauth = ropt->use_setsessauth;
     189            0 :         dopt->disable_dollar_quoting = ropt->disable_dollar_quoting;
     190            0 :         dopt->dump_inserts = ropt->dump_inserts;
     191            0 :         dopt->no_comments = ropt->no_comments;
     192            0 :         dopt->no_policies = ropt->no_policies;
     193            0 :         dopt->no_publications = ropt->no_publications;
     194            0 :         dopt->no_security_labels = ropt->no_security_labels;
     195            0 :         dopt->no_subscriptions = ropt->no_subscriptions;
     196            0 :         dopt->lockWaitTimeout = ropt->lockWaitTimeout;
     197            0 :         dopt->include_everything = ropt->include_everything;
     198            0 :         dopt->enable_row_security = ropt->enable_row_security;
     199            0 :         dopt->sequence_data = ropt->sequence_data;
     200            0 :         dopt->restrict_key = ropt->restrict_key ? pg_strdup(ropt->restrict_key) : NULL;
     201              : 
     202            0 :         return dopt;
     203            0 : }
     204              : 
     205              : 
     206              : /*
     207              :  *      Wrapper functions.
     208              :  *
     209              :  *      The objective is to make writing new formats and dumpers as simple
     210              :  *      as possible, if necessary at the expense of extra function calls etc.
     211              :  *
     212              :  */
     213              : 
     214              : /*
     215              :  * The dump worker setup needs lots of knowledge of the internals of pg_dump,
     216              :  * so it's defined in pg_dump.c and passed into OpenArchive. The restore worker
     217              :  * setup doesn't need to know anything much, so it's defined here.
     218              :  */
     219              : static void
     220            0 : setupRestoreWorker(Archive *AHX)
     221              : {
     222            0 :         ArchiveHandle *AH = (ArchiveHandle *) AHX;
     223              : 
     224            0 :         AH->ReopenPtr(AH);
     225            0 : }
     226              : 
     227              : 
     228              : /* Create a new archive */
     229              : /* Public */
     230              : Archive *
     231            0 : CreateArchive(const char *FileSpec, const ArchiveFormat fmt,
     232              :                           const pg_compress_specification compression_spec,
     233              :                           bool dosync, ArchiveMode mode,
     234              :                           SetupWorkerPtrType setupDumpWorker,
     235              :                           DataDirSyncMethod sync_method)
     236              : 
     237              : {
     238            0 :         ArchiveHandle *AH = _allocAH(FileSpec, fmt, compression_spec,
     239            0 :                                                                  dosync, mode, setupDumpWorker, sync_method);
     240              : 
     241            0 :         return (Archive *) AH;
     242            0 : }
     243              : 
     244              : /* Open an existing archive */
     245              : /* Public */
     246              : Archive *
     247            0 : OpenArchive(const char *FileSpec, const ArchiveFormat fmt)
     248              : {
     249            0 :         ArchiveHandle *AH;
     250            0 :         pg_compress_specification compression_spec = {0};
     251              : 
     252            0 :         compression_spec.algorithm = PG_COMPRESSION_NONE;
     253            0 :         AH = _allocAH(FileSpec, fmt, compression_spec, true,
     254              :                                   archModeRead, setupRestoreWorker,
     255              :                                   DATA_DIR_SYNC_METHOD_FSYNC);
     256              : 
     257            0 :         return (Archive *) AH;
     258            0 : }
     259              : 
     260              : /* Public */
     261              : void
     262            0 : CloseArchive(Archive *AHX)
     263              : {
     264            0 :         ArchiveHandle *AH = (ArchiveHandle *) AHX;
     265              : 
     266            0 :         AH->ClosePtr(AH);
     267              : 
     268              :         /* Close the output */
     269            0 :         errno = 0;
     270            0 :         if (!EndCompressFileHandle(AH->OF))
     271            0 :                 pg_fatal("could not close output file: %m");
     272            0 : }
     273              : 
     274              : /* Public */
     275              : void
     276            0 : SetArchiveOptions(Archive *AH, DumpOptions *dopt, RestoreOptions *ropt)
     277              : {
     278              :         /* Caller can omit dump options, in which case we synthesize them */
     279            0 :         if (dopt == NULL && ropt != NULL)
     280            0 :                 dopt = dumpOptionsFromRestoreOptions(ropt);
     281              : 
     282              :         /* Save options for later access */
     283            0 :         AH->dopt = dopt;
     284            0 :         AH->ropt = ropt;
     285            0 : }
     286              : 
     287              : /* Public */
     288              : void
     289            0 : ProcessArchiveRestoreOptions(Archive *AHX)
     290              : {
     291            0 :         ArchiveHandle *AH = (ArchiveHandle *) AHX;
     292            0 :         RestoreOptions *ropt = AH->public.ropt;
     293            0 :         TocEntry   *te;
     294            0 :         teSection       curSection;
     295              : 
     296              :         /* Decide which TOC entries will be dumped/restored, and mark them */
     297            0 :         curSection = SECTION_PRE_DATA;
     298            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
     299              :         {
     300              :                 /*
     301              :                  * When writing an archive, we also take this opportunity to check
     302              :                  * that we have generated the entries in a sane order that respects
     303              :                  * the section divisions.  When reading, don't complain, since buggy
     304              :                  * old versions of pg_dump might generate out-of-order archives.
     305              :                  */
     306            0 :                 if (AH->mode != archModeRead)
     307              :                 {
     308            0 :                         switch (te->section)
     309              :                         {
     310              :                                 case SECTION_NONE:
     311              :                                         /* ok to be anywhere */
     312              :                                         break;
     313              :                                 case SECTION_PRE_DATA:
     314            0 :                                         if (curSection != SECTION_PRE_DATA)
     315            0 :                                                 pg_log_warning("archive items not in correct section order");
     316            0 :                                         break;
     317              :                                 case SECTION_DATA:
     318            0 :                                         if (curSection == SECTION_POST_DATA)
     319            0 :                                                 pg_log_warning("archive items not in correct section order");
     320            0 :                                         break;
     321              :                                 case SECTION_POST_DATA:
     322              :                                         /* ok no matter which section we were in */
     323              :                                         break;
     324              :                                 default:
     325            0 :                                         pg_fatal("unexpected section code %d",
     326              :                                                          (int) te->section);
     327            0 :                                         break;
     328              :                         }
     329            0 :                 }
     330              : 
     331            0 :                 if (te->section != SECTION_NONE)
     332            0 :                         curSection = te->section;
     333              : 
     334            0 :                 te->reqs = _tocEntryRequired(te, curSection, AH);
     335            0 :         }
     336              : 
     337              :         /* Enforce strict names checking */
     338            0 :         if (ropt->strict_names)
     339            0 :                 StrictNamesCheck(ropt);
     340            0 : }
     341              : 
     342              : /* Public */
     343              : void
     344            0 : RestoreArchive(Archive *AHX)
     345              : {
     346            0 :         ArchiveHandle *AH = (ArchiveHandle *) AHX;
     347            0 :         RestoreOptions *ropt = AH->public.ropt;
     348            0 :         bool            parallel_mode;
     349            0 :         TocEntry   *te;
     350            0 :         CompressFileHandle *sav;
     351              : 
     352            0 :         AH->stage = STAGE_INITIALIZING;
     353              : 
     354              :         /*
     355              :          * If we're going to do parallel restore, there are some restrictions.
     356              :          */
     357            0 :         parallel_mode = (AH->public.numWorkers > 1 && ropt->useDB);
     358            0 :         if (parallel_mode)
     359              :         {
     360              :                 /* We haven't got round to making this work for all archive formats */
     361            0 :                 if (AH->ClonePtr == NULL || AH->ReopenPtr == NULL)
     362            0 :                         pg_fatal("parallel restore is not supported with this archive file format");
     363              : 
     364              :                 /* Doesn't work if the archive represents dependencies as OIDs */
     365            0 :                 if (AH->version < K_VERS_1_8)
     366            0 :                         pg_fatal("parallel restore is not supported with archives made by pre-8.0 pg_dump");
     367              : 
     368              :                 /*
     369              :                  * It's also not gonna work if we can't reopen the input file, so
     370              :                  * let's try that immediately.
     371              :                  */
     372            0 :                 AH->ReopenPtr(AH);
     373            0 :         }
     374              : 
     375              :         /*
     376              :          * Make sure we won't need (de)compression we haven't got
     377              :          */
     378            0 :         if (AH->PrintTocDataPtr != NULL)
     379              :         {
     380            0 :                 for (te = AH->toc->next; te != AH->toc; te = te->next)
     381              :                 {
     382            0 :                         if (te->hadDumper && (te->reqs & REQ_DATA) != 0)
     383              :                         {
     384            0 :                                 char       *errmsg = supports_compression(AH->compression_spec);
     385              : 
     386            0 :                                 if (errmsg)
     387            0 :                                         pg_fatal("cannot restore from compressed archive (%s)",
     388              :                                                          errmsg);
     389              :                                 else
     390            0 :                                         break;
     391            0 :                         }
     392            0 :                 }
     393            0 :         }
     394              : 
     395              :         /*
     396              :          * Prepare index arrays, so we can assume we have them throughout restore.
     397              :          * It's possible we already did this, though.
     398              :          */
     399            0 :         if (AH->tocsByDumpId == NULL)
     400            0 :                 buildTocEntryArrays(AH);
     401              : 
     402              :         /*
     403              :          * If we're using a DB connection, then connect it.
     404              :          */
     405            0 :         if (ropt->useDB)
     406              :         {
     407            0 :                 pg_log_info("connecting to database for restore");
     408            0 :                 if (AH->version < K_VERS_1_3)
     409            0 :                         pg_fatal("direct database connections are not supported in pre-1.3 archives");
     410              : 
     411              :                 /*
     412              :                  * We don't want to guess at whether the dump will successfully
     413              :                  * restore; allow the attempt regardless of the version of the restore
     414              :                  * target.
     415              :                  */
     416            0 :                 AHX->minRemoteVersion = 0;
     417            0 :                 AHX->maxRemoteVersion = 9999999;
     418              : 
     419            0 :                 ConnectDatabaseAhx(AHX, &ropt->cparams, false);
     420              : 
     421              :                 /*
     422              :                  * If we're talking to the DB directly, don't send comments since they
     423              :                  * obscure SQL when displaying errors
     424              :                  */
     425            0 :                 AH->noTocComments = 1;
     426            0 :         }
     427              : 
     428              :         /*
     429              :          * Work out if we have an implied schema-less restore. This can happen if
     430              :          * the dump excluded the schema or the user has used a toc list to exclude
     431              :          * all of the schema data. All we do is look for schema entries - if none
     432              :          * are found then we unset the dumpSchema flag.
     433              :          *
     434              :          * We could scan for wanted TABLE entries, but that is not the same as
     435              :          * data-only. At this stage, it seems unnecessary (6-Mar-2001).
     436              :          */
     437            0 :         if (ropt->dumpSchema)
     438              :         {
     439            0 :                 bool            no_schema_found = true;
     440              : 
     441            0 :                 for (te = AH->toc->next; te != AH->toc; te = te->next)
     442              :                 {
     443            0 :                         if ((te->reqs & REQ_SCHEMA) != 0)
     444              :                         {
     445            0 :                                 no_schema_found = false;
     446            0 :                                 break;
     447              :                         }
     448            0 :                 }
     449            0 :                 if (no_schema_found)
     450              :                 {
     451            0 :                         ropt->dumpSchema = false;
     452            0 :                         pg_log_info("implied no-schema restore");
     453            0 :                 }
     454            0 :         }
     455              : 
     456              :         /*
     457              :          * Setup the output file if necessary.
     458              :          */
     459            0 :         sav = SaveOutput(AH);
     460            0 :         if (ropt->filename || ropt->compression_spec.algorithm != PG_COMPRESSION_NONE)
     461            0 :                 SetOutput(AH, ropt->filename, ropt->compression_spec);
     462              : 
     463            0 :         ahprintf(AH, "--\n-- PostgreSQL database dump\n--\n\n");
     464              : 
     465              :         /*
     466              :          * If generating plain-text output, enter restricted mode to block any
     467              :          * unexpected psql meta-commands.  A malicious source might try to inject
     468              :          * a variety of things via bogus responses to queries.  While we cannot
     469              :          * prevent such sources from affecting the destination at restore time, we
     470              :          * can block psql meta-commands so that the client machine that runs psql
     471              :          * with the dump output remains unaffected.
     472              :          */
     473            0 :         if (ropt->restrict_key)
     474            0 :                 ahprintf(AH, "\\restrict %s\n\n", ropt->restrict_key);
     475              : 
     476            0 :         if (AH->archiveRemoteVersion)
     477            0 :                 ahprintf(AH, "-- Dumped from database version %s\n",
     478            0 :                                  AH->archiveRemoteVersion);
     479            0 :         if (AH->archiveDumpVersion)
     480            0 :                 ahprintf(AH, "-- Dumped by pg_dump version %s\n",
     481            0 :                                  AH->archiveDumpVersion);
     482              : 
     483            0 :         ahprintf(AH, "\n");
     484              : 
     485            0 :         if (AH->public.verbose)
     486            0 :                 dumpTimestamp(AH, "Started on", AH->createDate);
     487              : 
     488            0 :         if (ropt->single_txn)
     489              :         {
     490            0 :                 if (AH->connection)
     491            0 :                         StartTransaction(AHX);
     492              :                 else
     493            0 :                         ahprintf(AH, "BEGIN;\n\n");
     494            0 :         }
     495              : 
     496              :         /*
     497              :          * Establish important parameter values right away.
     498              :          */
     499            0 :         _doSetFixedOutputState(AH);
     500              : 
     501            0 :         AH->stage = STAGE_PROCESSING;
     502              : 
     503              :         /*
     504              :          * Drop the items at the start, in reverse order
     505              :          */
     506            0 :         if (ropt->dropSchema)
     507              :         {
     508            0 :                 for (te = AH->toc->prev; te != AH->toc; te = te->prev)
     509              :                 {
     510            0 :                         AH->currentTE = te;
     511              : 
     512              :                         /*
     513              :                          * In createDB mode, issue a DROP *only* for the database as a
     514              :                          * whole.  Issuing drops against anything else would be wrong,
     515              :                          * because at this point we're connected to the wrong database.
     516              :                          * (The DATABASE PROPERTIES entry, if any, should be treated like
     517              :                          * the DATABASE entry.)
     518              :                          */
     519            0 :                         if (ropt->createDB)
     520              :                         {
     521            0 :                                 if (strcmp(te->desc, "DATABASE") != 0 &&
     522            0 :                                         strcmp(te->desc, "DATABASE PROPERTIES") != 0)
     523            0 :                                         continue;
     524            0 :                         }
     525              : 
     526              :                         /* Otherwise, drop anything that's selected and has a dropStmt */
     527            0 :                         if (((te->reqs & (REQ_SCHEMA | REQ_DATA)) != 0) && te->dropStmt)
     528              :                         {
     529            0 :                                 bool            not_allowed_in_txn = false;
     530              : 
     531            0 :                                 pg_log_info("dropping %s %s", te->desc, te->tag);
     532              : 
     533              :                                 /*
     534              :                                  * In --transaction-size mode, we have to temporarily exit our
     535              :                                  * transaction block to drop objects that can't be dropped
     536              :                                  * within a transaction.
     537              :                                  */
     538            0 :                                 if (ropt->txn_size > 0)
     539              :                                 {
     540            0 :                                         if (strcmp(te->desc, "DATABASE") == 0 ||
     541            0 :                                                 strcmp(te->desc, "DATABASE PROPERTIES") == 0)
     542              :                                         {
     543            0 :                                                 not_allowed_in_txn = true;
     544            0 :                                                 if (AH->connection)
     545            0 :                                                         CommitTransaction(AHX);
     546              :                                                 else
     547            0 :                                                         ahprintf(AH, "COMMIT;\n");
     548            0 :                                         }
     549            0 :                                 }
     550              : 
     551              :                                 /* Select owner and schema as necessary */
     552            0 :                                 _becomeOwner(AH, te);
     553            0 :                                 _selectOutputSchema(AH, te->namespace);
     554              : 
     555              :                                 /*
     556              :                                  * Now emit the DROP command, if the object has one.  Note we
     557              :                                  * don't necessarily emit it verbatim; at this point we add an
     558              :                                  * appropriate IF EXISTS clause, if the user requested it.
     559              :                                  */
     560            0 :                                 if (strcmp(te->desc, "BLOB METADATA") == 0)
     561              :                                 {
     562              :                                         /* We must generate the per-blob commands */
     563            0 :                                         if (ropt->if_exists)
     564            0 :                                                 IssueCommandPerBlob(AH, te,
     565              :                                                                                         "SELECT pg_catalog.lo_unlink(oid) "
     566              :                                                                                         "FROM pg_catalog.pg_largeobject_metadata "
     567              :                                                                                         "WHERE oid = '", "'");
     568              :                                         else
     569            0 :                                                 IssueCommandPerBlob(AH, te,
     570              :                                                                                         "SELECT pg_catalog.lo_unlink('",
     571              :                                                                                         "')");
     572            0 :                                 }
     573            0 :                                 else if (*te->dropStmt != '\0')
     574              :                                 {
     575            0 :                                         if (!ropt->if_exists ||
     576            0 :                                                 strncmp(te->dropStmt, "--", 2) == 0)
     577              :                                         {
     578              :                                                 /*
     579              :                                                  * Without --if-exists, or if it's just a comment (as
     580              :                                                  * happens for the public schema), print the dropStmt
     581              :                                                  * as-is.
     582              :                                                  */
     583            0 :                                                 ahprintf(AH, "%s", te->dropStmt);
     584            0 :                                         }
     585              :                                         else
     586              :                                         {
     587              :                                                 /*
     588              :                                                  * Inject an appropriate spelling of "if exists".  For
     589              :                                                  * old-style large objects, we have a routine that
     590              :                                                  * knows how to do it, without depending on
     591              :                                                  * te->dropStmt; use that.  For other objects we need
     592              :                                                  * to parse the command.
     593              :                                                  */
     594            0 :                                                 if (strcmp(te->desc, "BLOB") == 0)
     595              :                                                 {
     596            0 :                                                         DropLOIfExists(AH, te->catalogId.oid);
     597            0 :                                                 }
     598              :                                                 else
     599              :                                                 {
     600            0 :                                                         char       *dropStmt = pg_strdup(te->dropStmt);
     601            0 :                                                         char       *dropStmtOrig = dropStmt;
     602            0 :                                                         PQExpBuffer ftStmt = createPQExpBuffer();
     603              : 
     604              :                                                         /*
     605              :                                                          * Need to inject IF EXISTS clause after ALTER
     606              :                                                          * TABLE part in ALTER TABLE .. DROP statement
     607              :                                                          */
     608            0 :                                                         if (strncmp(dropStmt, "ALTER TABLE", 11) == 0)
     609              :                                                         {
     610            0 :                                                                 appendPQExpBufferStr(ftStmt,
     611              :                                                                                                          "ALTER TABLE IF EXISTS");
     612            0 :                                                                 dropStmt = dropStmt + 11;
     613            0 :                                                         }
     614              : 
     615              :                                                         /*
     616              :                                                          * ALTER TABLE..ALTER COLUMN..DROP DEFAULT does
     617              :                                                          * not support the IF EXISTS clause, and therefore
     618              :                                                          * we simply emit the original command for DEFAULT
     619              :                                                          * objects (modulo the adjustment made above).
     620              :                                                          *
     621              :                                                          * Likewise, don't mess with DATABASE PROPERTIES.
     622              :                                                          *
     623              :                                                          * If we used CREATE OR REPLACE VIEW as a means of
     624              :                                                          * quasi-dropping an ON SELECT rule, that should
     625              :                                                          * be emitted unchanged as well.
     626              :                                                          *
     627              :                                                          * For other object types, we need to extract the
     628              :                                                          * first part of the DROP which includes the
     629              :                                                          * object type.  Most of the time this matches
     630              :                                                          * te->desc, so search for that; however for the
     631              :                                                          * different kinds of CONSTRAINTs, we know to
     632              :                                                          * search for hardcoded "DROP CONSTRAINT" instead.
     633              :                                                          */
     634            0 :                                                         if (strcmp(te->desc, "DEFAULT") == 0 ||
     635            0 :                                                                 strcmp(te->desc, "DATABASE PROPERTIES") == 0 ||
     636            0 :                                                                 strncmp(dropStmt, "CREATE OR REPLACE VIEW", 22) == 0)
     637            0 :                                                                 appendPQExpBufferStr(ftStmt, dropStmt);
     638              :                                                         else
     639              :                                                         {
     640            0 :                                                                 char            buffer[40];
     641            0 :                                                                 char       *mark;
     642              : 
     643            0 :                                                                 if (strcmp(te->desc, "CONSTRAINT") == 0 ||
     644            0 :                                                                         strcmp(te->desc, "CHECK CONSTRAINT") == 0 ||
     645            0 :                                                                         strcmp(te->desc, "FK CONSTRAINT") == 0)
     646            0 :                                                                         strcpy(buffer, "DROP CONSTRAINT");
     647              :                                                                 else
     648            0 :                                                                         snprintf(buffer, sizeof(buffer), "DROP %s",
     649            0 :                                                                                          te->desc);
     650              : 
     651            0 :                                                                 mark = strstr(dropStmt, buffer);
     652              : 
     653            0 :                                                                 if (mark)
     654              :                                                                 {
     655            0 :                                                                         *mark = '\0';
     656            0 :                                                                         appendPQExpBuffer(ftStmt, "%s%s IF EXISTS%s",
     657            0 :                                                                                                           dropStmt, buffer,
     658            0 :                                                                                                           mark + strlen(buffer));
     659            0 :                                                                 }
     660              :                                                                 else
     661              :                                                                 {
     662              :                                                                         /* complain and emit unmodified command */
     663            0 :                                                                         pg_log_warning("could not find where to insert IF EXISTS in statement \"%s\"",
     664              :                                                                                                    dropStmtOrig);
     665            0 :                                                                         appendPQExpBufferStr(ftStmt, dropStmt);
     666              :                                                                 }
     667            0 :                                                         }
     668              : 
     669            0 :                                                         ahprintf(AH, "%s", ftStmt->data);
     670              : 
     671            0 :                                                         destroyPQExpBuffer(ftStmt);
     672            0 :                                                         pg_free(dropStmtOrig);
     673            0 :                                                 }
     674              :                                         }
     675            0 :                                 }
     676              : 
     677              :                                 /*
     678              :                                  * In --transaction-size mode, re-establish the transaction
     679              :                                  * block if needed; otherwise, commit after every N drops.
     680              :                                  */
     681            0 :                                 if (ropt->txn_size > 0)
     682              :                                 {
     683            0 :                                         if (not_allowed_in_txn)
     684              :                                         {
     685            0 :                                                 if (AH->connection)
     686            0 :                                                         StartTransaction(AHX);
     687              :                                                 else
     688            0 :                                                         ahprintf(AH, "BEGIN;\n");
     689            0 :                                                 AH->txnCount = 0;
     690            0 :                                         }
     691            0 :                                         else if (++AH->txnCount >= ropt->txn_size)
     692              :                                         {
     693            0 :                                                 if (AH->connection)
     694              :                                                 {
     695            0 :                                                         CommitTransaction(AHX);
     696            0 :                                                         StartTransaction(AHX);
     697            0 :                                                 }
     698              :                                                 else
     699            0 :                                                         ahprintf(AH, "COMMIT;\nBEGIN;\n");
     700            0 :                                                 AH->txnCount = 0;
     701            0 :                                         }
     702            0 :                                 }
     703            0 :                         }
     704            0 :                 }
     705              : 
     706              :                 /*
     707              :                  * _selectOutputSchema may have set currSchema to reflect the effect
     708              :                  * of a "SET search_path" command it emitted.  However, by now we may
     709              :                  * have dropped that schema; or it might not have existed in the first
     710              :                  * place.  In either case the effective value of search_path will not
     711              :                  * be what we think.  Forcibly reset currSchema so that we will
     712              :                  * re-establish the search_path setting when needed (after creating
     713              :                  * the schema).
     714              :                  *
     715              :                  * If we treated users as pg_dump'able objects then we'd need to reset
     716              :                  * currUser here too.
     717              :                  */
     718            0 :                 free(AH->currSchema);
     719            0 :                 AH->currSchema = NULL;
     720            0 :         }
     721              : 
     722            0 :         if (parallel_mode)
     723              :         {
     724              :                 /*
     725              :                  * In parallel mode, turn control over to the parallel-restore logic.
     726              :                  */
     727            0 :                 ParallelState *pstate;
     728            0 :                 TocEntry        pending_list;
     729              : 
     730              :                 /* The archive format module may need some setup for this */
     731            0 :                 if (AH->PrepParallelRestorePtr)
     732            0 :                         AH->PrepParallelRestorePtr(AH);
     733              : 
     734            0 :                 pending_list_header_init(&pending_list);
     735              : 
     736              :                 /* This runs PRE_DATA items and then disconnects from the database */
     737            0 :                 restore_toc_entries_prefork(AH, &pending_list);
     738            0 :                 Assert(AH->connection == NULL);
     739              : 
     740              :                 /* ParallelBackupStart() will actually fork the processes */
     741            0 :                 pstate = ParallelBackupStart(AH);
     742            0 :                 restore_toc_entries_parallel(AH, pstate, &pending_list);
     743            0 :                 ParallelBackupEnd(AH, pstate);
     744              : 
     745              :                 /* reconnect the leader and see if we missed something */
     746            0 :                 restore_toc_entries_postfork(AH, &pending_list);
     747            0 :                 Assert(AH->connection != NULL);
     748            0 :         }
     749              :         else
     750              :         {
     751              :                 /*
     752              :                  * In serial mode, process everything in three phases: normal items,
     753              :                  * then ACLs, then post-ACL items.  We might be able to skip one or
     754              :                  * both extra phases in some cases, eg data-only restores.
     755              :                  */
     756            0 :                 bool            haveACL = false;
     757            0 :                 bool            havePostACL = false;
     758              : 
     759            0 :                 for (te = AH->toc->next; te != AH->toc; te = te->next)
     760              :                 {
     761            0 :                         if ((te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS)) == 0)
     762            0 :                                 continue;               /* ignore if not to be dumped at all */
     763              : 
     764            0 :                         switch (_tocEntryRestorePass(te))
     765              :                         {
     766              :                                 case RESTORE_PASS_MAIN:
     767            0 :                                         (void) restore_toc_entry(AH, te, false);
     768            0 :                                         break;
     769              :                                 case RESTORE_PASS_ACL:
     770            0 :                                         haveACL = true;
     771            0 :                                         break;
     772              :                                 case RESTORE_PASS_POST_ACL:
     773            0 :                                         havePostACL = true;
     774            0 :                                         break;
     775              :                         }
     776            0 :                 }
     777              : 
     778            0 :                 if (haveACL)
     779              :                 {
     780            0 :                         for (te = AH->toc->next; te != AH->toc; te = te->next)
     781              :                         {
     782            0 :                                 if ((te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS)) != 0 &&
     783            0 :                                         _tocEntryRestorePass(te) == RESTORE_PASS_ACL)
     784            0 :                                         (void) restore_toc_entry(AH, te, false);
     785            0 :                         }
     786            0 :                 }
     787              : 
     788            0 :                 if (havePostACL)
     789              :                 {
     790            0 :                         for (te = AH->toc->next; te != AH->toc; te = te->next)
     791              :                         {
     792            0 :                                 if ((te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS)) != 0 &&
     793            0 :                                         _tocEntryRestorePass(te) == RESTORE_PASS_POST_ACL)
     794            0 :                                         (void) restore_toc_entry(AH, te, false);
     795            0 :                         }
     796            0 :                 }
     797            0 :         }
     798              : 
     799              :         /*
     800              :          * Close out any persistent transaction we may have.  While these two
     801              :          * cases are started in different places, we can end both cases here.
     802              :          */
     803            0 :         if (ropt->single_txn || ropt->txn_size > 0)
     804              :         {
     805            0 :                 if (AH->connection)
     806            0 :                         CommitTransaction(AHX);
     807              :                 else
     808            0 :                         ahprintf(AH, "COMMIT;\n\n");
     809            0 :         }
     810              : 
     811            0 :         if (AH->public.verbose)
     812            0 :                 dumpTimestamp(AH, "Completed on", time(NULL));
     813              : 
     814            0 :         ahprintf(AH, "--\n-- PostgreSQL database dump complete\n--\n\n");
     815              : 
     816              :         /*
     817              :          * If generating plain-text output, exit restricted mode at the very end
     818              :          * of the script. This is not pro forma; in particular, pg_dumpall
     819              :          * requires this when transitioning from one database to another.
     820              :          */
     821            0 :         if (ropt->restrict_key)
     822            0 :                 ahprintf(AH, "\\unrestrict %s\n\n", ropt->restrict_key);
     823              : 
     824              :         /*
     825              :          * Clean up & we're done.
     826              :          */
     827            0 :         AH->stage = STAGE_FINALIZING;
     828              : 
     829            0 :         if (ropt->filename || ropt->compression_spec.algorithm != PG_COMPRESSION_NONE)
     830            0 :                 RestoreOutput(AH, sav);
     831              : 
     832            0 :         if (ropt->useDB)
     833            0 :                 DisconnectDatabase(&AH->public);
     834            0 : }
     835              : 
     836              : /*
     837              :  * Restore a single TOC item.  Used in both parallel and non-parallel restore;
     838              :  * is_parallel is true if we are in a worker child process.
     839              :  *
     840              :  * Returns 0 normally, but WORKER_CREATE_DONE or WORKER_INHIBIT_DATA if
     841              :  * the parallel parent has to make the corresponding status update.
     842              :  */
     843              : static int
     844            0 : restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
     845              : {
     846            0 :         RestoreOptions *ropt = AH->public.ropt;
     847            0 :         int                     status = WORKER_OK;
     848            0 :         int                     reqs;
     849            0 :         bool            defnDumped;
     850              : 
     851            0 :         AH->currentTE = te;
     852              : 
     853              :         /* Dump any relevant dump warnings to stderr */
     854            0 :         if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
     855              :         {
     856            0 :                 if (ropt->dumpSchema && te->defn != NULL && strlen(te->defn) != 0)
     857            0 :                         pg_log_warning("warning from original dump file: %s", te->defn);
     858            0 :                 else if (te->copyStmt != NULL && strlen(te->copyStmt) != 0)
     859            0 :                         pg_log_warning("warning from original dump file: %s", te->copyStmt);
     860            0 :         }
     861              : 
     862              :         /* Work out what, if anything, we want from this entry */
     863            0 :         reqs = te->reqs;
     864              : 
     865            0 :         defnDumped = false;
     866              : 
     867              :         /*
     868              :          * If it has a schema component that we want, then process that
     869              :          */
     870            0 :         if ((reqs & REQ_SCHEMA) != 0)
     871              :         {
     872            0 :                 bool            object_is_db = false;
     873              : 
     874              :                 /*
     875              :                  * In --transaction-size mode, must exit our transaction block to
     876              :                  * create a database or set its properties.
     877              :                  */
     878            0 :                 if (strcmp(te->desc, "DATABASE") == 0 ||
     879            0 :                         strcmp(te->desc, "DATABASE PROPERTIES") == 0)
     880              :                 {
     881            0 :                         object_is_db = true;
     882            0 :                         if (ropt->txn_size > 0)
     883              :                         {
     884            0 :                                 if (AH->connection)
     885            0 :                                         CommitTransaction(&AH->public);
     886              :                                 else
     887            0 :                                         ahprintf(AH, "COMMIT;\n\n");
     888            0 :                         }
     889            0 :                 }
     890              : 
     891              :                 /* Show namespace in log message if available */
     892            0 :                 if (te->namespace)
     893            0 :                         pg_log_info("creating %s \"%s.%s\"",
     894              :                                                 te->desc, te->namespace, te->tag);
     895              :                 else
     896            0 :                         pg_log_info("creating %s \"%s\"",
     897              :                                                 te->desc, te->tag);
     898              : 
     899            0 :                 _printTocEntry(AH, te, TOC_PREFIX_NONE);
     900            0 :                 defnDumped = true;
     901              : 
     902            0 :                 if (strcmp(te->desc, "TABLE") == 0)
     903              :                 {
     904            0 :                         if (AH->lastErrorTE == te)
     905              :                         {
     906              :                                 /*
     907              :                                  * We failed to create the table. If
     908              :                                  * --no-data-for-failed-tables was given, mark the
     909              :                                  * corresponding TABLE DATA to be ignored.
     910              :                                  *
     911              :                                  * In the parallel case this must be done in the parent, so we
     912              :                                  * just set the return value.
     913              :                                  */
     914            0 :                                 if (ropt->noDataForFailedTables)
     915              :                                 {
     916            0 :                                         if (is_parallel)
     917            0 :                                                 status = WORKER_INHIBIT_DATA;
     918              :                                         else
     919            0 :                                                 inhibit_data_for_failed_table(AH, te);
     920            0 :                                 }
     921            0 :                         }
     922              :                         else
     923              :                         {
     924              :                                 /*
     925              :                                  * We created the table successfully.  Mark the corresponding
     926              :                                  * TABLE DATA for possible truncation.
     927              :                                  *
     928              :                                  * In the parallel case this must be done in the parent, so we
     929              :                                  * just set the return value.
     930              :                                  */
     931            0 :                                 if (is_parallel)
     932            0 :                                         status = WORKER_CREATE_DONE;
     933              :                                 else
     934            0 :                                         mark_create_done(AH, te);
     935              :                         }
     936            0 :                 }
     937              : 
     938              :                 /*
     939              :                  * If we created a DB, connect to it.  Also, if we changed DB
     940              :                  * properties, reconnect to ensure that relevant GUC settings are
     941              :                  * applied to our session.  (That also restarts the transaction block
     942              :                  * in --transaction-size mode.)
     943              :                  */
     944            0 :                 if (object_is_db)
     945              :                 {
     946            0 :                         pg_log_info("connecting to new database \"%s\"", te->tag);
     947            0 :                         _reconnectToDB(AH, te->tag);
     948            0 :                 }
     949            0 :         }
     950              : 
     951              :         /*
     952              :          * If it has a data component that we want, then process that
     953              :          */
     954            0 :         if ((reqs & REQ_DATA) != 0)
     955              :         {
     956              :                 /*
     957              :                  * hadDumper will be set if there is genuine data component for this
     958              :                  * node. Otherwise, we need to check the defn field for statements
     959              :                  * that need to be executed in data-only restores.
     960              :                  */
     961            0 :                 if (te->hadDumper)
     962              :                 {
     963              :                         /*
     964              :                          * If we can output the data, then restore it.
     965              :                          */
     966            0 :                         if (AH->PrintTocDataPtr != NULL)
     967              :                         {
     968            0 :                                 _printTocEntry(AH, te, TOC_PREFIX_DATA);
     969              : 
     970            0 :                                 if (strcmp(te->desc, "BLOBS") == 0 ||
     971            0 :                                         strcmp(te->desc, "BLOB COMMENTS") == 0)
     972              :                                 {
     973            0 :                                         pg_log_info("processing %s", te->desc);
     974              : 
     975            0 :                                         _selectOutputSchema(AH, "pg_catalog");
     976              : 
     977              :                                         /* Send BLOB COMMENTS data to ExecuteSimpleCommands() */
     978            0 :                                         if (strcmp(te->desc, "BLOB COMMENTS") == 0)
     979            0 :                                                 AH->outputKind = OUTPUT_OTHERDATA;
     980              : 
     981            0 :                                         AH->PrintTocDataPtr(AH, te);
     982              : 
     983            0 :                                         AH->outputKind = OUTPUT_SQLCMDS;
     984            0 :                                 }
     985              :                                 else
     986              :                                 {
     987            0 :                                         bool            use_truncate;
     988              : 
     989            0 :                                         _disableTriggersIfNecessary(AH, te);
     990              : 
     991              :                                         /* Select owner and schema as necessary */
     992            0 :                                         _becomeOwner(AH, te);
     993            0 :                                         _selectOutputSchema(AH, te->namespace);
     994              : 
     995            0 :                                         pg_log_info("processing data for table \"%s.%s\"",
     996              :                                                                 te->namespace, te->tag);
     997              : 
     998              :                                         /*
     999              :                                          * In parallel restore, if we created the table earlier in
    1000              :                                          * this run (so that we know it is empty) and we are not
    1001              :                                          * restoring a load-via-partition-root data item then we
    1002              :                                          * wrap the COPY in a transaction and precede it with a
    1003              :                                          * TRUNCATE.  If wal_level is set to minimal this prevents
    1004              :                                          * WAL-logging the COPY.  This obtains a speedup similar
    1005              :                                          * to that from using single_txn mode in non-parallel
    1006              :                                          * restores.
    1007              :                                          *
    1008              :                                          * We mustn't do this for load-via-partition-root cases
    1009              :                                          * because some data might get moved across partition
    1010              :                                          * boundaries, risking deadlock and/or loss of previously
    1011              :                                          * loaded data.  (We assume that all partitions of a
    1012              :                                          * partitioned table will be treated the same way.)
    1013              :                                          */
    1014            0 :                                         use_truncate = is_parallel && te->created &&
    1015            0 :                                                 !is_load_via_partition_root(te);
    1016              : 
    1017            0 :                                         if (use_truncate)
    1018              :                                         {
    1019              :                                                 /*
    1020              :                                                  * Parallel restore is always talking directly to a
    1021              :                                                  * server, so no need to see if we should issue BEGIN.
    1022              :                                                  */
    1023            0 :                                                 StartTransaction(&AH->public);
    1024              : 
    1025              :                                                 /*
    1026              :                                                  * Issue TRUNCATE with ONLY so that child tables are
    1027              :                                                  * not wiped.
    1028              :                                                  */
    1029            0 :                                                 ahprintf(AH, "TRUNCATE TABLE ONLY %s;\n\n",
    1030            0 :                                                                  fmtQualifiedId(te->namespace, te->tag));
    1031            0 :                                         }
    1032              : 
    1033              :                                         /*
    1034              :                                          * If we have a copy statement, use it.
    1035              :                                          */
    1036            0 :                                         if (te->copyStmt && strlen(te->copyStmt) > 0)
    1037              :                                         {
    1038            0 :                                                 ahprintf(AH, "%s", te->copyStmt);
    1039            0 :                                                 AH->outputKind = OUTPUT_COPYDATA;
    1040            0 :                                         }
    1041              :                                         else
    1042            0 :                                                 AH->outputKind = OUTPUT_OTHERDATA;
    1043              : 
    1044            0 :                                         AH->PrintTocDataPtr(AH, te);
    1045              : 
    1046              :                                         /*
    1047              :                                          * Terminate COPY if needed.
    1048              :                                          */
    1049            0 :                                         if (AH->outputKind == OUTPUT_COPYDATA &&
    1050            0 :                                                 RestoringToDB(AH))
    1051            0 :                                                 EndDBCopyMode(&AH->public, te->tag);
    1052            0 :                                         AH->outputKind = OUTPUT_SQLCMDS;
    1053              : 
    1054              :                                         /* close out the transaction started above */
    1055            0 :                                         if (use_truncate)
    1056            0 :                                                 CommitTransaction(&AH->public);
    1057              : 
    1058            0 :                                         _enableTriggersIfNecessary(AH, te);
    1059            0 :                                 }
    1060            0 :                         }
    1061            0 :                 }
    1062            0 :                 else if (!defnDumped)
    1063              :                 {
    1064              :                         /* If we haven't already dumped the defn part, do so now */
    1065            0 :                         pg_log_info("executing %s %s", te->desc, te->tag);
    1066            0 :                         _printTocEntry(AH, te, TOC_PREFIX_NONE);
    1067            0 :                 }
    1068            0 :         }
    1069              : 
    1070              :         /*
    1071              :          * If it has a statistics component that we want, then process that
    1072              :          */
    1073            0 :         if ((reqs & REQ_STATS) != 0)
    1074            0 :                 _printTocEntry(AH, te, TOC_PREFIX_STATS);
    1075              : 
    1076              :         /*
    1077              :          * If we emitted anything for this TOC entry, that counts as one action
    1078              :          * against the transaction-size limit.  Commit if it's time to.
    1079              :          */
    1080            0 :         if ((reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS)) != 0 && ropt->txn_size > 0)
    1081              :         {
    1082            0 :                 if (++AH->txnCount >= ropt->txn_size)
    1083              :                 {
    1084            0 :                         if (AH->connection)
    1085              :                         {
    1086            0 :                                 CommitTransaction(&AH->public);
    1087            0 :                                 StartTransaction(&AH->public);
    1088            0 :                         }
    1089              :                         else
    1090            0 :                                 ahprintf(AH, "COMMIT;\nBEGIN;\n\n");
    1091            0 :                         AH->txnCount = 0;
    1092            0 :                 }
    1093            0 :         }
    1094              : 
    1095            0 :         if (AH->public.n_errors > 0 && status == WORKER_OK)
    1096            0 :                 status = WORKER_IGNORED_ERRORS;
    1097              : 
    1098            0 :         return status;
    1099            0 : }
    1100              : 
    1101              : /*
    1102              :  * Allocate a new RestoreOptions block.
    1103              :  * This is mainly so we can initialize it, but also for future expansion,
    1104              :  */
    1105              : RestoreOptions *
    1106            0 : NewRestoreOptions(void)
    1107              : {
    1108            0 :         RestoreOptions *opts;
    1109              : 
    1110            0 :         opts = (RestoreOptions *) pg_malloc0(sizeof(RestoreOptions));
    1111              : 
    1112              :         /* set any fields that shouldn't default to zeroes */
    1113            0 :         opts->format = archUnknown;
    1114            0 :         opts->cparams.promptPassword = TRI_DEFAULT;
    1115            0 :         opts->dumpSections = DUMP_UNSECTIONED;
    1116            0 :         opts->compression_spec.algorithm = PG_COMPRESSION_NONE;
    1117            0 :         opts->compression_spec.level = 0;
    1118            0 :         opts->dumpSchema = true;
    1119            0 :         opts->dumpData = true;
    1120            0 :         opts->dumpStatistics = true;
    1121              : 
    1122            0 :         return opts;
    1123            0 : }
    1124              : 
    1125              : static void
    1126            0 : _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te)
    1127              : {
    1128            0 :         RestoreOptions *ropt = AH->public.ropt;
    1129              : 
    1130              :         /* This hack is only needed in a data-only restore */
    1131            0 :         if (ropt->dumpSchema || !ropt->disable_triggers)
    1132            0 :                 return;
    1133              : 
    1134            0 :         pg_log_info("disabling triggers for %s", te->tag);
    1135              : 
    1136              :         /*
    1137              :          * Become superuser if possible, since they are the only ones who can
    1138              :          * disable constraint triggers.  If -S was not given, assume the initial
    1139              :          * user identity is a superuser.  (XXX would it be better to become the
    1140              :          * table owner?)
    1141              :          */
    1142            0 :         _becomeUser(AH, ropt->superuser);
    1143              : 
    1144              :         /*
    1145              :          * Disable them.
    1146              :          */
    1147            0 :         ahprintf(AH, "ALTER TABLE %s DISABLE TRIGGER ALL;\n\n",
    1148            0 :                          fmtQualifiedId(te->namespace, te->tag));
    1149            0 : }
    1150              : 
    1151              : static void
    1152            0 : _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te)
    1153              : {
    1154            0 :         RestoreOptions *ropt = AH->public.ropt;
    1155              : 
    1156              :         /* This hack is only needed in a data-only restore */
    1157            0 :         if (ropt->dumpSchema || !ropt->disable_triggers)
    1158            0 :                 return;
    1159              : 
    1160            0 :         pg_log_info("enabling triggers for %s", te->tag);
    1161              : 
    1162              :         /*
    1163              :          * Become superuser if possible, since they are the only ones who can
    1164              :          * disable constraint triggers.  If -S was not given, assume the initial
    1165              :          * user identity is a superuser.  (XXX would it be better to become the
    1166              :          * table owner?)
    1167              :          */
    1168            0 :         _becomeUser(AH, ropt->superuser);
    1169              : 
    1170              :         /*
    1171              :          * Enable them.
    1172              :          */
    1173            0 :         ahprintf(AH, "ALTER TABLE %s ENABLE TRIGGER ALL;\n\n",
    1174            0 :                          fmtQualifiedId(te->namespace, te->tag));
    1175            0 : }
    1176              : 
    1177              : /*
    1178              :  * Detect whether a TABLE DATA TOC item is performing "load via partition
    1179              :  * root", that is the target table is an ancestor partition rather than the
    1180              :  * table the TOC item is nominally for.
    1181              :  *
    1182              :  * In newer archive files this can be detected by checking for a special
    1183              :  * comment placed in te->defn.  In older files we have to fall back to seeing
    1184              :  * if the COPY statement targets the named table or some other one.  This
    1185              :  * will not work for data dumped as INSERT commands, so we could give a false
    1186              :  * negative in that case; fortunately, that's a rarely-used option.
    1187              :  */
    1188              : static bool
    1189            0 : is_load_via_partition_root(TocEntry *te)
    1190              : {
    1191            0 :         if (te->defn &&
    1192            0 :                 strncmp(te->defn, "-- load via partition root ", 27) == 0)
    1193            0 :                 return true;
    1194            0 :         if (te->copyStmt && *te->copyStmt)
    1195              :         {
    1196            0 :                 PQExpBuffer copyStmt = createPQExpBuffer();
    1197            0 :                 bool            result;
    1198              : 
    1199              :                 /*
    1200              :                  * Build the initial part of the COPY as it would appear if the
    1201              :                  * nominal target table is the actual target.  If we see anything
    1202              :                  * else, it must be a load-via-partition-root case.
    1203              :                  */
    1204            0 :                 appendPQExpBuffer(copyStmt, "COPY %s ",
    1205            0 :                                                   fmtQualifiedId(te->namespace, te->tag));
    1206            0 :                 result = strncmp(te->copyStmt, copyStmt->data, copyStmt->len) != 0;
    1207            0 :                 destroyPQExpBuffer(copyStmt);
    1208            0 :                 return result;
    1209            0 :         }
    1210              :         /* Assume it's not load-via-partition-root */
    1211            0 :         return false;
    1212            0 : }
    1213              : 
    1214              : /*
    1215              :  * This is a routine that is part of the dumper interface, hence the 'Archive*' parameter.
    1216              :  */
    1217              : 
    1218              : /* Public */
    1219              : void
    1220            0 : WriteData(Archive *AHX, const void *data, size_t dLen)
    1221              : {
    1222            0 :         ArchiveHandle *AH = (ArchiveHandle *) AHX;
    1223              : 
    1224            0 :         if (!AH->currToc)
    1225            0 :                 pg_fatal("internal error -- WriteData cannot be called outside the context of a DataDumper routine");
    1226              : 
    1227            0 :         AH->WriteDataPtr(AH, data, dLen);
    1228            0 : }
    1229              : 
    1230              : /*
    1231              :  * Create a new TOC entry. The TOC was designed as a TOC, but is now the
    1232              :  * repository for all metadata. But the name has stuck.
    1233              :  *
    1234              :  * The new entry is added to the Archive's TOC list.  Most callers can ignore
    1235              :  * the result value because nothing else need be done, but a few want to
    1236              :  * manipulate the TOC entry further.
    1237              :  */
    1238              : 
    1239              : /* Public */
    1240              : TocEntry *
    1241            0 : ArchiveEntry(Archive *AHX, CatalogId catalogId, DumpId dumpId,
    1242              :                          ArchiveOpts *opts)
    1243              : {
    1244            0 :         ArchiveHandle *AH = (ArchiveHandle *) AHX;
    1245            0 :         TocEntry   *newToc;
    1246              : 
    1247            0 :         newToc = (TocEntry *) pg_malloc0(sizeof(TocEntry));
    1248              : 
    1249            0 :         AH->tocCount++;
    1250            0 :         if (dumpId > AH->maxDumpId)
    1251            0 :                 AH->maxDumpId = dumpId;
    1252              : 
    1253            0 :         newToc->prev = AH->toc->prev;
    1254            0 :         newToc->next = AH->toc;
    1255            0 :         AH->toc->prev->next = newToc;
    1256            0 :         AH->toc->prev = newToc;
    1257              : 
    1258            0 :         newToc->catalogId = catalogId;
    1259            0 :         newToc->dumpId = dumpId;
    1260            0 :         newToc->section = opts->section;
    1261              : 
    1262            0 :         newToc->tag = pg_strdup(opts->tag);
    1263            0 :         newToc->namespace = opts->namespace ? pg_strdup(opts->namespace) : NULL;
    1264            0 :         newToc->tablespace = opts->tablespace ? pg_strdup(opts->tablespace) : NULL;
    1265            0 :         newToc->tableam = opts->tableam ? pg_strdup(opts->tableam) : NULL;
    1266            0 :         newToc->relkind = opts->relkind;
    1267            0 :         newToc->owner = opts->owner ? pg_strdup(opts->owner) : NULL;
    1268            0 :         newToc->desc = pg_strdup(opts->description);
    1269            0 :         newToc->defn = opts->createStmt ? pg_strdup(opts->createStmt) : NULL;
    1270            0 :         newToc->dropStmt = opts->dropStmt ? pg_strdup(opts->dropStmt) : NULL;
    1271            0 :         newToc->copyStmt = opts->copyStmt ? pg_strdup(opts->copyStmt) : NULL;
    1272              : 
    1273            0 :         if (opts->nDeps > 0)
    1274              :         {
    1275            0 :                 newToc->dependencies = (DumpId *) pg_malloc(opts->nDeps * sizeof(DumpId));
    1276            0 :                 memcpy(newToc->dependencies, opts->deps, opts->nDeps * sizeof(DumpId));
    1277            0 :                 newToc->nDeps = opts->nDeps;
    1278            0 :         }
    1279              :         else
    1280              :         {
    1281            0 :                 newToc->dependencies = NULL;
    1282            0 :                 newToc->nDeps = 0;
    1283              :         }
    1284              : 
    1285            0 :         newToc->dataDumper = opts->dumpFn;
    1286            0 :         newToc->dataDumperArg = opts->dumpArg;
    1287            0 :         newToc->hadDumper = opts->dumpFn ? true : false;
    1288              : 
    1289            0 :         newToc->defnDumper = opts->defnFn;
    1290            0 :         newToc->defnDumperArg = opts->defnArg;
    1291              : 
    1292            0 :         newToc->formatData = NULL;
    1293            0 :         newToc->dataLength = 0;
    1294              : 
    1295            0 :         if (AH->ArchiveEntryPtr != NULL)
    1296            0 :                 AH->ArchiveEntryPtr(AH, newToc);
    1297              : 
    1298            0 :         return newToc;
    1299            0 : }
    1300              : 
    1301              : /* Public */
    1302              : void
    1303            0 : PrintTOCSummary(Archive *AHX)
    1304              : {
    1305            0 :         ArchiveHandle *AH = (ArchiveHandle *) AHX;
    1306            0 :         RestoreOptions *ropt = AH->public.ropt;
    1307            0 :         TocEntry   *te;
    1308            0 :         pg_compress_specification out_compression_spec = {0};
    1309            0 :         teSection       curSection;
    1310            0 :         CompressFileHandle *sav;
    1311            0 :         const char *fmtName;
    1312            0 :         char            stamp_str[64];
    1313              : 
    1314              :         /* TOC is always uncompressed */
    1315            0 :         out_compression_spec.algorithm = PG_COMPRESSION_NONE;
    1316              : 
    1317            0 :         sav = SaveOutput(AH);
    1318            0 :         if (ropt->filename)
    1319            0 :                 SetOutput(AH, ropt->filename, out_compression_spec);
    1320              : 
    1321            0 :         if (strftime(stamp_str, sizeof(stamp_str), PGDUMP_STRFTIME_FMT,
    1322            0 :                                  localtime(&AH->createDate)) == 0)
    1323            0 :                 strcpy(stamp_str, "[unknown]");
    1324              : 
    1325            0 :         ahprintf(AH, ";\n; Archive created at %s\n", stamp_str);
    1326            0 :         ahprintf(AH, ";     dbname: %s\n;     TOC Entries: %d\n;     Compression: %s\n",
    1327            0 :                          sanitize_line(AH->archdbname, false),
    1328            0 :                          AH->tocCount,
    1329            0 :                          get_compress_algorithm_name(AH->compression_spec.algorithm));
    1330              : 
    1331            0 :         switch (AH->format)
    1332              :         {
    1333              :                 case archCustom:
    1334            0 :                         fmtName = "CUSTOM";
    1335            0 :                         break;
    1336              :                 case archDirectory:
    1337            0 :                         fmtName = "DIRECTORY";
    1338            0 :                         break;
    1339              :                 case archTar:
    1340            0 :                         fmtName = "TAR";
    1341            0 :                         break;
    1342              :                 default:
    1343            0 :                         fmtName = "UNKNOWN";
    1344            0 :         }
    1345              : 
    1346            0 :         ahprintf(AH, ";     Dump Version: %d.%d-%d\n",
    1347            0 :                          ARCHIVE_MAJOR(AH->version), ARCHIVE_MINOR(AH->version), ARCHIVE_REV(AH->version));
    1348            0 :         ahprintf(AH, ";     Format: %s\n", fmtName);
    1349            0 :         ahprintf(AH, ";     Integer: %zu bytes\n", AH->intSize);
    1350            0 :         ahprintf(AH, ";     Offset: %zu bytes\n", AH->offSize);
    1351            0 :         if (AH->archiveRemoteVersion)
    1352            0 :                 ahprintf(AH, ";     Dumped from database version: %s\n",
    1353            0 :                                  AH->archiveRemoteVersion);
    1354            0 :         if (AH->archiveDumpVersion)
    1355            0 :                 ahprintf(AH, ";     Dumped by pg_dump version: %s\n",
    1356            0 :                                  AH->archiveDumpVersion);
    1357              : 
    1358            0 :         ahprintf(AH, ";\n;\n; Selected TOC Entries:\n;\n");
    1359              : 
    1360            0 :         curSection = SECTION_PRE_DATA;
    1361            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
    1362              :         {
    1363              :                 /* This bit must match ProcessArchiveRestoreOptions' marking logic */
    1364            0 :                 if (te->section != SECTION_NONE)
    1365            0 :                         curSection = te->section;
    1366            0 :                 te->reqs = _tocEntryRequired(te, curSection, AH);
    1367              :                 /* Now, should we print it? */
    1368            0 :                 if (ropt->verbose ||
    1369            0 :                         (te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS)) != 0)
    1370              :                 {
    1371            0 :                         char       *sanitized_name;
    1372            0 :                         char       *sanitized_schema;
    1373            0 :                         char       *sanitized_owner;
    1374              : 
    1375              :                         /*
    1376              :                          */
    1377            0 :                         sanitized_name = sanitize_line(te->tag, false);
    1378            0 :                         sanitized_schema = sanitize_line(te->namespace, true);
    1379            0 :                         sanitized_owner = sanitize_line(te->owner, false);
    1380              : 
    1381            0 :                         ahprintf(AH, "%d; %u %u %s %s %s %s\n", te->dumpId,
    1382            0 :                                          te->catalogId.tableoid, te->catalogId.oid,
    1383            0 :                                          te->desc, sanitized_schema, sanitized_name,
    1384            0 :                                          sanitized_owner);
    1385              : 
    1386            0 :                         free(sanitized_name);
    1387            0 :                         free(sanitized_schema);
    1388            0 :                         free(sanitized_owner);
    1389            0 :                 }
    1390            0 :                 if (ropt->verbose && te->nDeps > 0)
    1391              :                 {
    1392            0 :                         int                     i;
    1393              : 
    1394            0 :                         ahprintf(AH, ";\tdepends on:");
    1395            0 :                         for (i = 0; i < te->nDeps; i++)
    1396            0 :                                 ahprintf(AH, " %d", te->dependencies[i]);
    1397            0 :                         ahprintf(AH, "\n");
    1398            0 :                 }
    1399            0 :         }
    1400              : 
    1401              :         /* Enforce strict names checking */
    1402            0 :         if (ropt->strict_names)
    1403            0 :                 StrictNamesCheck(ropt);
    1404              : 
    1405            0 :         if (ropt->filename)
    1406            0 :                 RestoreOutput(AH, sav);
    1407            0 : }
    1408              : 
    1409              : /***********
    1410              :  * Large Object Archival
    1411              :  ***********/
    1412              : 
    1413              : /* Called by a dumper to signal start of a LO */
    1414              : int
    1415            0 : StartLO(Archive *AHX, Oid oid)
    1416              : {
    1417            0 :         ArchiveHandle *AH = (ArchiveHandle *) AHX;
    1418              : 
    1419            0 :         if (!AH->StartLOPtr)
    1420            0 :                 pg_fatal("large-object output not supported in chosen format");
    1421              : 
    1422            0 :         AH->StartLOPtr(AH, AH->currToc, oid);
    1423              : 
    1424            0 :         return 1;
    1425            0 : }
    1426              : 
    1427              : /* Called by a dumper to signal end of a LO */
    1428              : int
    1429            0 : EndLO(Archive *AHX, Oid oid)
    1430              : {
    1431            0 :         ArchiveHandle *AH = (ArchiveHandle *) AHX;
    1432              : 
    1433            0 :         if (AH->EndLOPtr)
    1434            0 :                 AH->EndLOPtr(AH, AH->currToc, oid);
    1435              : 
    1436            0 :         return 1;
    1437            0 : }
    1438              : 
    1439              : /**********
    1440              :  * Large Object Restoration
    1441              :  **********/
    1442              : 
    1443              : /*
    1444              :  * Called by a format handler before a group of LOs is restored
    1445              :  */
    1446              : void
    1447            0 : StartRestoreLOs(ArchiveHandle *AH)
    1448              : {
    1449            0 :         RestoreOptions *ropt = AH->public.ropt;
    1450              : 
    1451              :         /*
    1452              :          * LOs must be restored within a transaction block, since we need the LO
    1453              :          * handle to stay open while we write it.  Establish a transaction unless
    1454              :          * there's one being used globally.
    1455              :          */
    1456            0 :         if (!(ropt->single_txn || ropt->txn_size > 0))
    1457              :         {
    1458            0 :                 if (AH->connection)
    1459            0 :                         StartTransaction(&AH->public);
    1460              :                 else
    1461            0 :                         ahprintf(AH, "BEGIN;\n\n");
    1462            0 :         }
    1463              : 
    1464            0 :         AH->loCount = 0;
    1465            0 : }
    1466              : 
    1467              : /*
    1468              :  * Called by a format handler after a group of LOs is restored
    1469              :  */
    1470              : void
    1471            0 : EndRestoreLOs(ArchiveHandle *AH)
    1472              : {
    1473            0 :         RestoreOptions *ropt = AH->public.ropt;
    1474              : 
    1475            0 :         if (!(ropt->single_txn || ropt->txn_size > 0))
    1476              :         {
    1477            0 :                 if (AH->connection)
    1478            0 :                         CommitTransaction(&AH->public);
    1479              :                 else
    1480            0 :                         ahprintf(AH, "COMMIT;\n\n");
    1481            0 :         }
    1482              : 
    1483            0 :         pg_log_info(ngettext("restored %d large object",
    1484              :                                                  "restored %d large objects",
    1485              :                                                  AH->loCount),
    1486              :                                 AH->loCount);
    1487            0 : }
    1488              : 
    1489              : 
    1490              : /*
    1491              :  * Called by a format handler to initiate restoration of a LO
    1492              :  */
    1493              : void
    1494            0 : StartRestoreLO(ArchiveHandle *AH, Oid oid, bool drop)
    1495              : {
    1496            0 :         bool            old_lo_style = (AH->version < K_VERS_1_12);
    1497            0 :         Oid                     loOid;
    1498              : 
    1499            0 :         AH->loCount++;
    1500              : 
    1501              :         /* Initialize the LO Buffer */
    1502            0 :         if (AH->lo_buf == NULL)
    1503              :         {
    1504              :                 /* First time through (in this process) so allocate the buffer */
    1505            0 :                 AH->lo_buf_size = LOBBUFSIZE;
    1506            0 :                 AH->lo_buf = pg_malloc(LOBBUFSIZE);
    1507            0 :         }
    1508            0 :         AH->lo_buf_used = 0;
    1509              : 
    1510            0 :         pg_log_info("restoring large object with OID %u", oid);
    1511              : 
    1512              :         /* With an old archive we must do drop and create logic here */
    1513            0 :         if (old_lo_style && drop)
    1514            0 :                 DropLOIfExists(AH, oid);
    1515              : 
    1516            0 :         if (AH->connection)
    1517              :         {
    1518            0 :                 if (old_lo_style)
    1519              :                 {
    1520            0 :                         loOid = lo_create(AH->connection, oid);
    1521            0 :                         if (loOid == 0 || loOid != oid)
    1522            0 :                                 pg_fatal("could not create large object %u: %s",
    1523              :                                                  oid, PQerrorMessage(AH->connection));
    1524            0 :                 }
    1525            0 :                 AH->loFd = lo_open(AH->connection, oid, INV_WRITE);
    1526            0 :                 if (AH->loFd == -1)
    1527            0 :                         pg_fatal("could not open large object %u: %s",
    1528              :                                          oid, PQerrorMessage(AH->connection));
    1529            0 :         }
    1530              :         else
    1531              :         {
    1532            0 :                 if (old_lo_style)
    1533            0 :                         ahprintf(AH, "SELECT pg_catalog.lo_open(pg_catalog.lo_create('%u'), %d);\n",
    1534            0 :                                          oid, INV_WRITE);
    1535              :                 else
    1536            0 :                         ahprintf(AH, "SELECT pg_catalog.lo_open('%u', %d);\n",
    1537            0 :                                          oid, INV_WRITE);
    1538              :         }
    1539              : 
    1540            0 :         AH->writingLO = true;
    1541            0 : }
    1542              : 
    1543              : void
    1544            0 : EndRestoreLO(ArchiveHandle *AH, Oid oid)
    1545              : {
    1546            0 :         if (AH->lo_buf_used > 0)
    1547              :         {
    1548              :                 /* Write remaining bytes from the LO buffer */
    1549            0 :                 dump_lo_buf(AH);
    1550            0 :         }
    1551              : 
    1552            0 :         AH->writingLO = false;
    1553              : 
    1554            0 :         if (AH->connection)
    1555              :         {
    1556            0 :                 lo_close(AH->connection, AH->loFd);
    1557            0 :                 AH->loFd = -1;
    1558            0 :         }
    1559              :         else
    1560              :         {
    1561            0 :                 ahprintf(AH, "SELECT pg_catalog.lo_close(0);\n\n");
    1562              :         }
    1563            0 : }
    1564              : 
    1565              : /***********
    1566              :  * Sorting and Reordering
    1567              :  ***********/
    1568              : 
    1569              : void
    1570            0 : SortTocFromFile(Archive *AHX)
    1571              : {
    1572            0 :         ArchiveHandle *AH = (ArchiveHandle *) AHX;
    1573            0 :         RestoreOptions *ropt = AH->public.ropt;
    1574            0 :         FILE       *fh;
    1575            0 :         StringInfoData linebuf;
    1576              : 
    1577              :         /* Allocate space for the 'wanted' array, and init it */
    1578            0 :         ropt->idWanted = (bool *) pg_malloc0(sizeof(bool) * AH->maxDumpId);
    1579              : 
    1580              :         /* Setup the file */
    1581            0 :         fh = fopen(ropt->tocFile, PG_BINARY_R);
    1582            0 :         if (!fh)
    1583            0 :                 pg_fatal("could not open TOC file \"%s\": %m", ropt->tocFile);
    1584              : 
    1585            0 :         initStringInfo(&linebuf);
    1586              : 
    1587            0 :         while (pg_get_line_buf(fh, &linebuf))
    1588              :         {
    1589            0 :                 char       *cmnt;
    1590            0 :                 char       *endptr;
    1591            0 :                 DumpId          id;
    1592            0 :                 TocEntry   *te;
    1593              : 
    1594              :                 /* Truncate line at comment, if any */
    1595            0 :                 cmnt = strchr(linebuf.data, ';');
    1596            0 :                 if (cmnt != NULL)
    1597              :                 {
    1598            0 :                         cmnt[0] = '\0';
    1599            0 :                         linebuf.len = cmnt - linebuf.data;
    1600            0 :                 }
    1601              : 
    1602              :                 /* Ignore if all blank */
    1603            0 :                 if (strspn(linebuf.data, " \t\r\n") == linebuf.len)
    1604            0 :                         continue;
    1605              : 
    1606              :                 /* Get an ID, check it's valid and not already seen */
    1607            0 :                 id = strtol(linebuf.data, &endptr, 10);
    1608            0 :                 if (endptr == linebuf.data || id <= 0 || id > AH->maxDumpId ||
    1609            0 :                         ropt->idWanted[id - 1])
    1610              :                 {
    1611            0 :                         pg_log_warning("line ignored: %s", linebuf.data);
    1612            0 :                         continue;
    1613              :                 }
    1614              : 
    1615              :                 /* Find TOC entry */
    1616            0 :                 te = getTocEntryByDumpId(AH, id);
    1617            0 :                 if (!te)
    1618            0 :                         pg_fatal("could not find entry for ID %d",
    1619              :                                          id);
    1620              : 
    1621              :                 /* Mark it wanted */
    1622            0 :                 ropt->idWanted[id - 1] = true;
    1623              : 
    1624              :                 /*
    1625              :                  * Move each item to the end of the list as it is selected, so that
    1626              :                  * they are placed in the desired order.  Any unwanted items will end
    1627              :                  * up at the front of the list, which may seem unintuitive but it's
    1628              :                  * what we need.  In an ordinary serial restore that makes no
    1629              :                  * difference, but in a parallel restore we need to mark unrestored
    1630              :                  * items' dependencies as satisfied before we start examining
    1631              :                  * restorable items.  Otherwise they could have surprising
    1632              :                  * side-effects on the order in which restorable items actually get
    1633              :                  * restored.
    1634              :                  */
    1635            0 :                 _moveBefore(AH->toc, te);
    1636            0 :         }
    1637              : 
    1638            0 :         pg_free(linebuf.data);
    1639              : 
    1640            0 :         if (fclose(fh) != 0)
    1641            0 :                 pg_fatal("could not close TOC file: %m");
    1642            0 : }
    1643              : 
    1644              : /**********************
    1645              :  * Convenience functions that look like standard IO functions
    1646              :  * for writing data when in dump mode.
    1647              :  **********************/
    1648              : 
    1649              : /* Public */
    1650              : void
    1651            0 : archputs(const char *s, Archive *AH)
    1652              : {
    1653            0 :         WriteData(AH, s, strlen(s));
    1654            0 : }
    1655              : 
    1656              : /* Public */
    1657              : int
    1658            0 : archprintf(Archive *AH, const char *fmt,...)
    1659              : {
    1660            0 :         int                     save_errno = errno;
    1661            0 :         char       *p;
    1662            0 :         size_t          len = 128;              /* initial assumption about buffer size */
    1663            0 :         size_t          cnt;
    1664              : 
    1665            0 :         for (;;)
    1666              :         {
    1667            0 :                 va_list         args;
    1668              : 
    1669              :                 /* Allocate work buffer. */
    1670            0 :                 p = (char *) pg_malloc(len);
    1671              : 
    1672              :                 /* Try to format the data. */
    1673            0 :                 errno = save_errno;
    1674            0 :                 va_start(args, fmt);
    1675            0 :                 cnt = pvsnprintf(p, len, fmt, args);
    1676            0 :                 va_end(args);
    1677              : 
    1678            0 :                 if (cnt < len)
    1679            0 :                         break;                          /* success */
    1680              : 
    1681              :                 /* Release buffer and loop around to try again with larger len. */
    1682            0 :                 free(p);
    1683            0 :                 len = cnt;
    1684            0 :         }
    1685              : 
    1686            0 :         WriteData(AH, p, cnt);
    1687            0 :         free(p);
    1688            0 :         return (int) cnt;
    1689            0 : }
    1690              : 
    1691              : 
    1692              : /*******************************
    1693              :  * Stuff below here should be 'private' to the archiver routines
    1694              :  *******************************/
    1695              : 
    1696              : static void
    1697            0 : SetOutput(ArchiveHandle *AH, const char *filename,
    1698              :                   const pg_compress_specification compression_spec)
    1699              : {
    1700            0 :         CompressFileHandle *CFH;
    1701            0 :         const char *mode;
    1702            0 :         int                     fn = -1;
    1703              : 
    1704            0 :         if (filename)
    1705              :         {
    1706            0 :                 if (strcmp(filename, "-") == 0)
    1707            0 :                         fn = fileno(stdout);
    1708            0 :         }
    1709            0 :         else if (AH->FH)
    1710            0 :                 fn = fileno(AH->FH);
    1711            0 :         else if (AH->fSpec)
    1712              :         {
    1713            0 :                 filename = AH->fSpec;
    1714            0 :         }
    1715              :         else
    1716            0 :                 fn = fileno(stdout);
    1717              : 
    1718            0 :         if (AH->mode == archModeAppend)
    1719            0 :                 mode = PG_BINARY_A;
    1720              :         else
    1721            0 :                 mode = PG_BINARY_W;
    1722              : 
    1723            0 :         CFH = InitCompressFileHandle(compression_spec);
    1724              : 
    1725            0 :         if (!CFH->open_func(filename, fn, mode, CFH))
    1726              :         {
    1727            0 :                 if (filename)
    1728            0 :                         pg_fatal("could not open output file \"%s\": %m", filename);
    1729              :                 else
    1730            0 :                         pg_fatal("could not open output file: %m");
    1731            0 :         }
    1732              : 
    1733            0 :         AH->OF = CFH;
    1734            0 : }
    1735              : 
    1736              : static CompressFileHandle *
    1737            0 : SaveOutput(ArchiveHandle *AH)
    1738              : {
    1739            0 :         return (CompressFileHandle *) AH->OF;
    1740              : }
    1741              : 
    1742              : static void
    1743            0 : RestoreOutput(ArchiveHandle *AH, CompressFileHandle *savedOutput)
    1744              : {
    1745            0 :         errno = 0;
    1746            0 :         if (!EndCompressFileHandle(AH->OF))
    1747            0 :                 pg_fatal("could not close output file: %m");
    1748              : 
    1749            0 :         AH->OF = savedOutput;
    1750            0 : }
    1751              : 
    1752              : 
    1753              : 
    1754              : /*
    1755              :  *      Print formatted text to the output file (usually stdout).
    1756              :  */
    1757              : int
    1758            0 : ahprintf(ArchiveHandle *AH, const char *fmt,...)
    1759              : {
    1760            0 :         int                     save_errno = errno;
    1761            0 :         char       *p;
    1762            0 :         size_t          len = 128;              /* initial assumption about buffer size */
    1763            0 :         size_t          cnt;
    1764              : 
    1765            0 :         for (;;)
    1766              :         {
    1767            0 :                 va_list         args;
    1768              : 
    1769              :                 /* Allocate work buffer. */
    1770            0 :                 p = (char *) pg_malloc(len);
    1771              : 
    1772              :                 /* Try to format the data. */
    1773            0 :                 errno = save_errno;
    1774            0 :                 va_start(args, fmt);
    1775            0 :                 cnt = pvsnprintf(p, len, fmt, args);
    1776            0 :                 va_end(args);
    1777              : 
    1778            0 :                 if (cnt < len)
    1779            0 :                         break;                          /* success */
    1780              : 
    1781              :                 /* Release buffer and loop around to try again with larger len. */
    1782            0 :                 free(p);
    1783            0 :                 len = cnt;
    1784            0 :         }
    1785              : 
    1786            0 :         ahwrite(p, 1, cnt, AH);
    1787            0 :         free(p);
    1788            0 :         return (int) cnt;
    1789            0 : }
    1790              : 
    1791              : /*
    1792              :  * Single place for logic which says 'We are restoring to a direct DB connection'.
    1793              :  */
    1794              : static int
    1795            0 : RestoringToDB(ArchiveHandle *AH)
    1796              : {
    1797            0 :         RestoreOptions *ropt = AH->public.ropt;
    1798              : 
    1799            0 :         return (ropt && ropt->useDB && AH->connection);
    1800            0 : }
    1801              : 
    1802              : /*
    1803              :  * Dump the current contents of the LO data buffer while writing a LO
    1804              :  */
    1805              : static void
    1806            0 : dump_lo_buf(ArchiveHandle *AH)
    1807              : {
    1808            0 :         if (AH->connection)
    1809              :         {
    1810            0 :                 int                     res;
    1811              : 
    1812            0 :                 res = lo_write(AH->connection, AH->loFd, AH->lo_buf, AH->lo_buf_used);
    1813            0 :                 pg_log_debug(ngettext("wrote %zu byte of large object data (result = %d)",
    1814              :                                                           "wrote %zu bytes of large object data (result = %d)",
    1815              :                                                           AH->lo_buf_used),
    1816              :                                          AH->lo_buf_used, res);
    1817              :                 /* We assume there are no short writes, only errors */
    1818            0 :                 if (res != AH->lo_buf_used)
    1819            0 :                         warn_or_exit_horribly(AH, "could not write to large object: %s",
    1820            0 :                                                                   PQerrorMessage(AH->connection));
    1821            0 :         }
    1822              :         else
    1823              :         {
    1824            0 :                 PQExpBuffer buf = createPQExpBuffer();
    1825              : 
    1826            0 :                 appendByteaLiteralAHX(buf,
    1827              :                                                           (const unsigned char *) AH->lo_buf,
    1828              :                                                           AH->lo_buf_used,
    1829              :                                                           AH);
    1830              : 
    1831              :                 /* Hack: turn off writingLO so ahwrite doesn't recurse to here */
    1832            0 :                 AH->writingLO = false;
    1833            0 :                 ahprintf(AH, "SELECT pg_catalog.lowrite(0, %s);\n", buf->data);
    1834            0 :                 AH->writingLO = true;
    1835              : 
    1836            0 :                 destroyPQExpBuffer(buf);
    1837            0 :         }
    1838            0 :         AH->lo_buf_used = 0;
    1839            0 : }
    1840              : 
    1841              : 
    1842              : /*
    1843              :  *      Write buffer to the output file (usually stdout). This is used for
    1844              :  *      outputting 'restore' scripts etc. It is even possible for an archive
    1845              :  *      format to create a custom output routine to 'fake' a restore if it
    1846              :  *      wants to generate a script (see TAR output).
    1847              :  */
    1848              : void
    1849            0 : ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
    1850              : {
    1851            0 :         int                     bytes_written = 0;
    1852              : 
    1853            0 :         if (AH->writingLO)
    1854              :         {
    1855            0 :                 size_t          remaining = size * nmemb;
    1856              : 
    1857            0 :                 while (AH->lo_buf_used + remaining > AH->lo_buf_size)
    1858              :                 {
    1859            0 :                         size_t          avail = AH->lo_buf_size - AH->lo_buf_used;
    1860              : 
    1861            0 :                         memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, avail);
    1862            0 :                         ptr = (const char *) ptr + avail;
    1863            0 :                         remaining -= avail;
    1864            0 :                         AH->lo_buf_used += avail;
    1865            0 :                         dump_lo_buf(AH);
    1866            0 :                 }
    1867              : 
    1868            0 :                 memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining);
    1869            0 :                 AH->lo_buf_used += remaining;
    1870              : 
    1871            0 :                 bytes_written = size * nmemb;
    1872            0 :         }
    1873            0 :         else if (AH->CustomOutPtr)
    1874            0 :                 bytes_written = AH->CustomOutPtr(AH, ptr, size * nmemb);
    1875              : 
    1876              :         /*
    1877              :          * If we're doing a restore, and it's direct to DB, and we're connected
    1878              :          * then send it to the DB.
    1879              :          */
    1880            0 :         else if (RestoringToDB(AH))
    1881            0 :                 bytes_written = ExecuteSqlCommandBuf(&AH->public, (const char *) ptr, size * nmemb);
    1882              :         else
    1883              :         {
    1884            0 :                 CompressFileHandle *CFH = (CompressFileHandle *) AH->OF;
    1885              : 
    1886            0 :                 CFH->write_func(ptr, size * nmemb, CFH);
    1887            0 :                 bytes_written = size * nmemb;
    1888            0 :         }
    1889              : 
    1890            0 :         if (bytes_written != size * nmemb)
    1891            0 :                 WRITE_ERROR_EXIT;
    1892            0 : }
    1893              : 
    1894              : /* on some error, we may decide to go on... */
    1895              : void
    1896            0 : warn_or_exit_horribly(ArchiveHandle *AH, const char *fmt,...)
    1897              : {
    1898            0 :         va_list         ap;
    1899              : 
    1900            0 :         switch (AH->stage)
    1901              :         {
    1902              : 
    1903              :                 case STAGE_NONE:
    1904              :                         /* Do nothing special */
    1905              :                         break;
    1906              : 
    1907              :                 case STAGE_INITIALIZING:
    1908            0 :                         if (AH->stage != AH->lastErrorStage)
    1909            0 :                                 pg_log_info("while INITIALIZING:");
    1910            0 :                         break;
    1911              : 
    1912              :                 case STAGE_PROCESSING:
    1913            0 :                         if (AH->stage != AH->lastErrorStage)
    1914            0 :                                 pg_log_info("while PROCESSING TOC:");
    1915            0 :                         break;
    1916              : 
    1917              :                 case STAGE_FINALIZING:
    1918            0 :                         if (AH->stage != AH->lastErrorStage)
    1919            0 :                                 pg_log_info("while FINALIZING:");
    1920            0 :                         break;
    1921              :         }
    1922            0 :         if (AH->currentTE != NULL && AH->currentTE != AH->lastErrorTE)
    1923              :         {
    1924            0 :                 pg_log_info("from TOC entry %d; %u %u %s %s %s",
    1925              :                                         AH->currentTE->dumpId,
    1926              :                                         AH->currentTE->catalogId.tableoid,
    1927              :                                         AH->currentTE->catalogId.oid,
    1928              :                                         AH->currentTE->desc ? AH->currentTE->desc : "(no desc)",
    1929              :                                         AH->currentTE->tag ? AH->currentTE->tag : "(no tag)",
    1930              :                                         AH->currentTE->owner ? AH->currentTE->owner : "(no owner)");
    1931            0 :         }
    1932            0 :         AH->lastErrorStage = AH->stage;
    1933            0 :         AH->lastErrorTE = AH->currentTE;
    1934              : 
    1935            0 :         va_start(ap, fmt);
    1936            0 :         pg_log_generic_v(PG_LOG_ERROR, PG_LOG_PRIMARY, fmt, ap);
    1937            0 :         va_end(ap);
    1938              : 
    1939            0 :         if (AH->public.exit_on_error)
    1940            0 :                 exit_nicely(1);
    1941              :         else
    1942            0 :                 AH->public.n_errors++;
    1943            0 : }
    1944              : 
    1945              : #ifdef NOT_USED
    1946              : 
    1947              : static void
    1948              : _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
    1949              : {
    1950              :         /* Unlink te from list */
    1951              :         te->prev->next = te->next;
    1952              :         te->next->prev = te->prev;
    1953              : 
    1954              :         /* and insert it after "pos" */
    1955              :         te->prev = pos;
    1956              :         te->next = pos->next;
    1957              :         pos->next->prev = te;
    1958              :         pos->next = te;
    1959              : }
    1960              : #endif
    1961              : 
    1962              : static void
    1963            0 : _moveBefore(TocEntry *pos, TocEntry *te)
    1964              : {
    1965              :         /* Unlink te from list */
    1966            0 :         te->prev->next = te->next;
    1967            0 :         te->next->prev = te->prev;
    1968              : 
    1969              :         /* and insert it before "pos" */
    1970            0 :         te->prev = pos->prev;
    1971            0 :         te->next = pos;
    1972            0 :         pos->prev->next = te;
    1973            0 :         pos->prev = te;
    1974            0 : }
    1975              : 
    1976              : /*
    1977              :  * Build index arrays for the TOC list
    1978              :  *
    1979              :  * This should be invoked only after we have created or read in all the TOC
    1980              :  * items.
    1981              :  *
    1982              :  * The arrays are indexed by dump ID (so entry zero is unused).  Note that the
    1983              :  * array entries run only up to maxDumpId.  We might see dependency dump IDs
    1984              :  * beyond that (if the dump was partial); so always check the array bound
    1985              :  * before trying to touch an array entry.
    1986              :  */
    1987              : static void
    1988            0 : buildTocEntryArrays(ArchiveHandle *AH)
    1989              : {
    1990            0 :         DumpId          maxDumpId = AH->maxDumpId;
    1991            0 :         TocEntry   *te;
    1992              : 
    1993            0 :         AH->tocsByDumpId = (TocEntry **) pg_malloc0((maxDumpId + 1) * sizeof(TocEntry *));
    1994            0 :         AH->tableDataId = (DumpId *) pg_malloc0((maxDumpId + 1) * sizeof(DumpId));
    1995              : 
    1996            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
    1997              :         {
    1998              :                 /* this check is purely paranoia, maxDumpId should be correct */
    1999            0 :                 if (te->dumpId <= 0 || te->dumpId > maxDumpId)
    2000            0 :                         pg_fatal("bad dumpId");
    2001              : 
    2002              :                 /* tocsByDumpId indexes all TOCs by their dump ID */
    2003            0 :                 AH->tocsByDumpId[te->dumpId] = te;
    2004              : 
    2005              :                 /*
    2006              :                  * tableDataId provides the TABLE DATA item's dump ID for each TABLE
    2007              :                  * TOC entry that has a DATA item.  We compute this by reversing the
    2008              :                  * TABLE DATA item's dependency, knowing that a TABLE DATA item has
    2009              :                  * just one dependency and it is the TABLE item.
    2010              :                  */
    2011            0 :                 if (strcmp(te->desc, "TABLE DATA") == 0 && te->nDeps > 0)
    2012              :                 {
    2013            0 :                         DumpId          tableId = te->dependencies[0];
    2014              : 
    2015              :                         /*
    2016              :                          * The TABLE item might not have been in the archive, if this was
    2017              :                          * a data-only dump; but its dump ID should be less than its data
    2018              :                          * item's dump ID, so there should be a place for it in the array.
    2019              :                          */
    2020            0 :                         if (tableId <= 0 || tableId > maxDumpId)
    2021            0 :                                 pg_fatal("bad table dumpId for TABLE DATA item");
    2022              : 
    2023            0 :                         AH->tableDataId[tableId] = te->dumpId;
    2024            0 :                 }
    2025            0 :         }
    2026            0 : }
    2027              : 
    2028              : TocEntry *
    2029            0 : getTocEntryByDumpId(ArchiveHandle *AH, DumpId id)
    2030              : {
    2031              :         /* build index arrays if we didn't already */
    2032            0 :         if (AH->tocsByDumpId == NULL)
    2033            0 :                 buildTocEntryArrays(AH);
    2034              : 
    2035            0 :         if (id > 0 && id <= AH->maxDumpId)
    2036            0 :                 return AH->tocsByDumpId[id];
    2037              : 
    2038            0 :         return NULL;
    2039            0 : }
    2040              : 
    2041              : int
    2042            0 : TocIDRequired(ArchiveHandle *AH, DumpId id)
    2043              : {
    2044            0 :         TocEntry   *te = getTocEntryByDumpId(AH, id);
    2045              : 
    2046            0 :         if (!te)
    2047            0 :                 return 0;
    2048              : 
    2049            0 :         return te->reqs;
    2050            0 : }
    2051              : 
    2052              : size_t
    2053            0 : WriteOffset(ArchiveHandle *AH, pgoff_t o, int wasSet)
    2054              : {
    2055            0 :         int                     off;
    2056              : 
    2057              :         /* Save the flag */
    2058            0 :         AH->WriteBytePtr(AH, wasSet);
    2059              : 
    2060              :         /* Write out pgoff_t smallest byte first, prevents endian mismatch */
    2061            0 :         for (off = 0; off < sizeof(pgoff_t); off++)
    2062              :         {
    2063            0 :                 AH->WriteBytePtr(AH, o & 0xFF);
    2064            0 :                 o >>= 8;
    2065            0 :         }
    2066            0 :         return sizeof(pgoff_t) + 1;
    2067            0 : }
    2068              : 
    2069              : int
    2070            0 : ReadOffset(ArchiveHandle *AH, pgoff_t *o)
    2071              : {
    2072            0 :         int                     i;
    2073            0 :         int                     off;
    2074            0 :         int                     offsetFlg;
    2075              : 
    2076              :         /* Initialize to zero */
    2077            0 :         *o = 0;
    2078              : 
    2079              :         /* Check for old version */
    2080            0 :         if (AH->version < K_VERS_1_7)
    2081              :         {
    2082              :                 /* Prior versions wrote offsets using WriteInt */
    2083            0 :                 i = ReadInt(AH);
    2084              :                 /* -1 means not set */
    2085            0 :                 if (i < 0)
    2086            0 :                         return K_OFFSET_POS_NOT_SET;
    2087            0 :                 else if (i == 0)
    2088            0 :                         return K_OFFSET_NO_DATA;
    2089              : 
    2090              :                 /* Cast to pgoff_t because it was written as an int. */
    2091            0 :                 *o = (pgoff_t) i;
    2092            0 :                 return K_OFFSET_POS_SET;
    2093              :         }
    2094              : 
    2095              :         /*
    2096              :          * Read the flag indicating the state of the data pointer. Check if valid
    2097              :          * and die if not.
    2098              :          *
    2099              :          * This used to be handled by a negative or zero pointer, now we use an
    2100              :          * extra byte specifically for the state.
    2101              :          */
    2102            0 :         offsetFlg = AH->ReadBytePtr(AH) & 0xFF;
    2103              : 
    2104            0 :         switch (offsetFlg)
    2105              :         {
    2106              :                 case K_OFFSET_POS_NOT_SET:
    2107              :                 case K_OFFSET_NO_DATA:
    2108              :                 case K_OFFSET_POS_SET:
    2109              : 
    2110            0 :                         break;
    2111              : 
    2112              :                 default:
    2113            0 :                         pg_fatal("unexpected data offset flag %d", offsetFlg);
    2114            0 :         }
    2115              : 
    2116              :         /*
    2117              :          * Read the bytes
    2118              :          */
    2119            0 :         for (off = 0; off < AH->offSize; off++)
    2120              :         {
    2121            0 :                 if (off < sizeof(pgoff_t))
    2122            0 :                         *o |= ((pgoff_t) (AH->ReadBytePtr(AH))) << (off * 8);
    2123              :                 else
    2124              :                 {
    2125            0 :                         if (AH->ReadBytePtr(AH) != 0)
    2126            0 :                                 pg_fatal("file offset in dump file is too large");
    2127              :                 }
    2128            0 :         }
    2129              : 
    2130            0 :         return offsetFlg;
    2131            0 : }
    2132              : 
    2133              : size_t
    2134            0 : WriteInt(ArchiveHandle *AH, int i)
    2135              : {
    2136            0 :         int                     b;
    2137              : 
    2138              :         /*
    2139              :          * This is a bit yucky, but I don't want to make the binary format very
    2140              :          * dependent on representation, and not knowing much about it, I write out
    2141              :          * a sign byte. If you change this, don't forget to change the file
    2142              :          * version #, and modify ReadInt to read the new format AS WELL AS the old
    2143              :          * formats.
    2144              :          */
    2145              : 
    2146              :         /* SIGN byte */
    2147            0 :         if (i < 0)
    2148              :         {
    2149            0 :                 AH->WriteBytePtr(AH, 1);
    2150            0 :                 i = -i;
    2151            0 :         }
    2152              :         else
    2153            0 :                 AH->WriteBytePtr(AH, 0);
    2154              : 
    2155            0 :         for (b = 0; b < AH->intSize; b++)
    2156              :         {
    2157            0 :                 AH->WriteBytePtr(AH, i & 0xFF);
    2158            0 :                 i >>= 8;
    2159            0 :         }
    2160              : 
    2161            0 :         return AH->intSize + 1;
    2162            0 : }
    2163              : 
    2164              : int
    2165            0 : ReadInt(ArchiveHandle *AH)
    2166              : {
    2167            0 :         int                     res = 0;
    2168            0 :         int                     bv,
    2169              :                                 b;
    2170            0 :         int                     sign = 0;               /* Default positive */
    2171            0 :         int                     bitShift = 0;
    2172              : 
    2173            0 :         if (AH->version > K_VERS_1_0)
    2174              :                 /* Read a sign byte */
    2175            0 :                 sign = AH->ReadBytePtr(AH);
    2176              : 
    2177            0 :         for (b = 0; b < AH->intSize; b++)
    2178              :         {
    2179            0 :                 bv = AH->ReadBytePtr(AH) & 0xFF;
    2180            0 :                 if (bv != 0)
    2181            0 :                         res = res + (bv << bitShift);
    2182            0 :                 bitShift += 8;
    2183            0 :         }
    2184              : 
    2185            0 :         if (sign)
    2186            0 :                 res = -res;
    2187              : 
    2188            0 :         return res;
    2189            0 : }
    2190              : 
    2191              : size_t
    2192            0 : WriteStr(ArchiveHandle *AH, const char *c)
    2193              : {
    2194            0 :         size_t          res;
    2195              : 
    2196            0 :         if (c)
    2197              :         {
    2198            0 :                 int                     len = strlen(c);
    2199              : 
    2200            0 :                 res = WriteInt(AH, len);
    2201            0 :                 AH->WriteBufPtr(AH, c, len);
    2202            0 :                 res += len;
    2203            0 :         }
    2204              :         else
    2205            0 :                 res = WriteInt(AH, -1);
    2206              : 
    2207            0 :         return res;
    2208            0 : }
    2209              : 
    2210              : char *
    2211            0 : ReadStr(ArchiveHandle *AH)
    2212              : {
    2213            0 :         char       *buf;
    2214            0 :         int                     l;
    2215              : 
    2216            0 :         l = ReadInt(AH);
    2217            0 :         if (l < 0)
    2218            0 :                 buf = NULL;
    2219              :         else
    2220              :         {
    2221            0 :                 buf = (char *) pg_malloc(l + 1);
    2222            0 :                 AH->ReadBufPtr(AH, buf, l);
    2223              : 
    2224            0 :                 buf[l] = '\0';
    2225              :         }
    2226              : 
    2227            0 :         return buf;
    2228            0 : }
    2229              : 
    2230              : static bool
    2231            0 : _fileExistsInDirectory(const char *dir, const char *filename)
    2232              : {
    2233            0 :         struct stat st;
    2234            0 :         char            buf[MAXPGPATH];
    2235              : 
    2236            0 :         if (snprintf(buf, MAXPGPATH, "%s/%s", dir, filename) >= MAXPGPATH)
    2237            0 :                 pg_fatal("directory name too long: \"%s\"", dir);
    2238              : 
    2239            0 :         return (stat(buf, &st) == 0 && S_ISREG(st.st_mode));
    2240            0 : }
    2241              : 
    2242              : static int
    2243            0 : _discoverArchiveFormat(ArchiveHandle *AH)
    2244              : {
    2245            0 :         FILE       *fh;
    2246            0 :         char            sig[6];                 /* More than enough */
    2247            0 :         size_t          cnt;
    2248            0 :         int                     wantClose = 0;
    2249              : 
    2250            0 :         pg_log_debug("attempting to ascertain archive format");
    2251              : 
    2252            0 :         free(AH->lookahead);
    2253              : 
    2254            0 :         AH->readHeader = 0;
    2255            0 :         AH->lookaheadSize = 512;
    2256            0 :         AH->lookahead = pg_malloc0(512);
    2257            0 :         AH->lookaheadLen = 0;
    2258            0 :         AH->lookaheadPos = 0;
    2259              : 
    2260            0 :         if (AH->fSpec)
    2261              :         {
    2262            0 :                 struct stat st;
    2263              : 
    2264            0 :                 wantClose = 1;
    2265              : 
    2266              :                 /*
    2267              :                  * Check if the specified archive is a directory. If so, check if
    2268              :                  * there's a "toc.dat" (or "toc.dat.{gz,lz4,zst}") file in it.
    2269              :                  */
    2270            0 :                 if (stat(AH->fSpec, &st) == 0 && S_ISDIR(st.st_mode))
    2271              :                 {
    2272            0 :                         AH->format = archDirectory;
    2273            0 :                         if (_fileExistsInDirectory(AH->fSpec, "toc.dat"))
    2274            0 :                                 return AH->format;
    2275              : #ifdef HAVE_LIBZ
    2276            0 :                         if (_fileExistsInDirectory(AH->fSpec, "toc.dat.gz"))
    2277            0 :                                 return AH->format;
    2278              : #endif
    2279              : #ifdef USE_LZ4
    2280            0 :                         if (_fileExistsInDirectory(AH->fSpec, "toc.dat.lz4"))
    2281            0 :                                 return AH->format;
    2282              : #endif
    2283              : #ifdef USE_ZSTD
    2284            0 :                         if (_fileExistsInDirectory(AH->fSpec, "toc.dat.zst"))
    2285            0 :                                 return AH->format;
    2286              : #endif
    2287            0 :                         pg_fatal("directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)",
    2288              :                                          AH->fSpec);
    2289            0 :                         fh = NULL;                      /* keep compiler quiet */
    2290            0 :                 }
    2291              :                 else
    2292              :                 {
    2293            0 :                         fh = fopen(AH->fSpec, PG_BINARY_R);
    2294            0 :                         if (!fh)
    2295            0 :                                 pg_fatal("could not open input file \"%s\": %m", AH->fSpec);
    2296              :                 }
    2297            0 :         }
    2298              :         else
    2299              :         {
    2300            0 :                 fh = stdin;
    2301            0 :                 if (!fh)
    2302            0 :                         pg_fatal("could not open input file: %m");
    2303              :         }
    2304              : 
    2305            0 :         if ((cnt = fread(sig, 1, 5, fh)) != 5)
    2306              :         {
    2307            0 :                 if (ferror(fh))
    2308            0 :                         pg_fatal("could not read input file: %m");
    2309              :                 else
    2310            0 :                         pg_fatal("input file is too short (read %zu, expected 5)", cnt);
    2311            0 :         }
    2312              : 
    2313              :         /* Save it, just in case we need it later */
    2314            0 :         memcpy(&AH->lookahead[0], sig, 5);
    2315            0 :         AH->lookaheadLen = 5;
    2316              : 
    2317            0 :         if (strncmp(sig, "PGDMP", 5) == 0)
    2318              :         {
    2319              :                 /* It's custom format, stop here */
    2320            0 :                 AH->format = archCustom;
    2321            0 :                 AH->readHeader = 1;
    2322            0 :         }
    2323              :         else
    2324              :         {
    2325              :                 /*
    2326              :                  * *Maybe* we have a tar archive format file or a text dump ... So,
    2327              :                  * read first 512 byte header...
    2328              :                  */
    2329            0 :                 cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh);
    2330              :                 /* read failure is checked below */
    2331            0 :                 AH->lookaheadLen += cnt;
    2332              : 
    2333            0 :                 if (AH->lookaheadLen >= strlen(TEXT_DUMPALL_HEADER) &&
    2334            0 :                         (strncmp(AH->lookahead, TEXT_DUMP_HEADER, strlen(TEXT_DUMP_HEADER)) == 0 ||
    2335            0 :                          strncmp(AH->lookahead, TEXT_DUMPALL_HEADER, strlen(TEXT_DUMPALL_HEADER)) == 0))
    2336              :                 {
    2337              :                         /*
    2338              :                          * looks like it's probably a text format dump. so suggest they
    2339              :                          * try psql
    2340              :                          */
    2341            0 :                         pg_fatal("input file appears to be a text format dump. Please use psql.");
    2342            0 :                 }
    2343              : 
    2344            0 :                 if (AH->lookaheadLen != 512)
    2345              :                 {
    2346            0 :                         if (feof(fh))
    2347            0 :                                 pg_fatal("input file does not appear to be a valid archive (too short?)");
    2348              :                         else
    2349            0 :                                 READ_ERROR_EXIT(fh);
    2350            0 :                 }
    2351              : 
    2352            0 :                 if (!isValidTarHeader(AH->lookahead))
    2353            0 :                         pg_fatal("input file does not appear to be a valid archive");
    2354              : 
    2355            0 :                 AH->format = archTar;
    2356              :         }
    2357              : 
    2358              :         /* Close the file if we opened it */
    2359            0 :         if (wantClose)
    2360              :         {
    2361            0 :                 if (fclose(fh) != 0)
    2362            0 :                         pg_fatal("could not close input file: %m");
    2363              :                 /* Forget lookahead, since we'll re-read header after re-opening */
    2364            0 :                 AH->readHeader = 0;
    2365            0 :                 AH->lookaheadLen = 0;
    2366            0 :         }
    2367              : 
    2368            0 :         return AH->format;
    2369            0 : }
    2370              : 
    2371              : 
    2372              : /*
    2373              :  * Allocate an archive handle
    2374              :  */
    2375              : static ArchiveHandle *
    2376            0 : _allocAH(const char *FileSpec, const ArchiveFormat fmt,
    2377              :                  const pg_compress_specification compression_spec,
    2378              :                  bool dosync, ArchiveMode mode,
    2379              :                  SetupWorkerPtrType setupWorkerPtr, DataDirSyncMethod sync_method)
    2380              : {
    2381            0 :         ArchiveHandle *AH;
    2382            0 :         CompressFileHandle *CFH;
    2383            0 :         pg_compress_specification out_compress_spec = {0};
    2384              : 
    2385            0 :         pg_log_debug("allocating AH for %s, format %d",
    2386              :                                  FileSpec ? FileSpec : "(stdio)", fmt);
    2387              : 
    2388            0 :         AH = (ArchiveHandle *) pg_malloc0(sizeof(ArchiveHandle));
    2389              : 
    2390            0 :         AH->version = K_VERS_SELF;
    2391              : 
    2392              :         /* initialize for backwards compatible string processing */
    2393            0 :         AH->public.encoding = 0;     /* PG_SQL_ASCII */
    2394            0 :         AH->public.std_strings = false;
    2395              : 
    2396              :         /* sql error handling */
    2397            0 :         AH->public.exit_on_error = true;
    2398            0 :         AH->public.n_errors = 0;
    2399              : 
    2400            0 :         AH->archiveDumpVersion = PG_VERSION;
    2401              : 
    2402            0 :         AH->createDate = time(NULL);
    2403              : 
    2404            0 :         AH->intSize = sizeof(int);
    2405            0 :         AH->offSize = sizeof(pgoff_t);
    2406            0 :         if (FileSpec)
    2407              :         {
    2408            0 :                 AH->fSpec = pg_strdup(FileSpec);
    2409              : 
    2410              :                 /*
    2411              :                  * Not used; maybe later....
    2412              :                  *
    2413              :                  * AH->workDir = pg_strdup(FileSpec); for(i=strlen(FileSpec) ; i > 0 ;
    2414              :                  * i--) if (AH->workDir[i-1] == '/')
    2415              :                  */
    2416            0 :         }
    2417              :         else
    2418            0 :                 AH->fSpec = NULL;
    2419              : 
    2420            0 :         AH->currUser = NULL;         /* unknown */
    2421            0 :         AH->currSchema = NULL;               /* ditto */
    2422            0 :         AH->currTablespace = NULL;   /* ditto */
    2423            0 :         AH->currTableAm = NULL;              /* ditto */
    2424              : 
    2425            0 :         AH->toc = (TocEntry *) pg_malloc0(sizeof(TocEntry));
    2426              : 
    2427            0 :         AH->toc->next = AH->toc;
    2428            0 :         AH->toc->prev = AH->toc;
    2429              : 
    2430            0 :         AH->mode = mode;
    2431            0 :         AH->compression_spec = compression_spec;
    2432            0 :         AH->dosync = dosync;
    2433            0 :         AH->sync_method = sync_method;
    2434              : 
    2435            0 :         memset(&(AH->sqlparse), 0, sizeof(AH->sqlparse));
    2436              : 
    2437              :         /* Open stdout with no compression for AH output handle */
    2438            0 :         out_compress_spec.algorithm = PG_COMPRESSION_NONE;
    2439            0 :         CFH = InitCompressFileHandle(out_compress_spec);
    2440            0 :         if (!CFH->open_func(NULL, fileno(stdout), PG_BINARY_A, CFH))
    2441            0 :                 pg_fatal("could not open stdout for appending: %m");
    2442            0 :         AH->OF = CFH;
    2443              : 
    2444              :         /*
    2445              :          * On Windows, we need to use binary mode to read/write non-text files,
    2446              :          * which include all archive formats as well as compressed plain text.
    2447              :          * Force stdin/stdout into binary mode if that is what we are using.
    2448              :          */
    2449              : #ifdef WIN32
    2450              :         if ((fmt != archNull || compression_spec.algorithm != PG_COMPRESSION_NONE) &&
    2451              :                 (AH->fSpec == NULL || strcmp(AH->fSpec, "") == 0))
    2452              :         {
    2453              :                 if (mode == archModeWrite)
    2454              :                         _setmode(fileno(stdout), O_BINARY);
    2455              :                 else
    2456              :                         _setmode(fileno(stdin), O_BINARY);
    2457              :         }
    2458              : #endif
    2459              : 
    2460            0 :         AH->SetupWorkerPtr = setupWorkerPtr;
    2461              : 
    2462            0 :         if (fmt == archUnknown)
    2463            0 :                 AH->format = _discoverArchiveFormat(AH);
    2464              :         else
    2465            0 :                 AH->format = fmt;
    2466              : 
    2467            0 :         switch (AH->format)
    2468              :         {
    2469              :                 case archCustom:
    2470            0 :                         InitArchiveFmt_Custom(AH);
    2471            0 :                         break;
    2472              : 
    2473              :                 case archNull:
    2474            0 :                         InitArchiveFmt_Null(AH);
    2475            0 :                         break;
    2476              : 
    2477              :                 case archDirectory:
    2478            0 :                         InitArchiveFmt_Directory(AH);
    2479            0 :                         break;
    2480              : 
    2481              :                 case archTar:
    2482            0 :                         InitArchiveFmt_Tar(AH);
    2483            0 :                         break;
    2484              : 
    2485              :                 default:
    2486            0 :                         pg_fatal("unrecognized file format \"%d\"", AH->format);
    2487            0 :         }
    2488              : 
    2489            0 :         return AH;
    2490            0 : }
    2491              : 
    2492              : /*
    2493              :  * Write out all data (tables & LOs)
    2494              :  */
    2495              : void
    2496            0 : WriteDataChunks(ArchiveHandle *AH, ParallelState *pstate)
    2497              : {
    2498            0 :         TocEntry   *te;
    2499              : 
    2500            0 :         if (pstate && pstate->numWorkers > 1)
    2501              :         {
    2502              :                 /*
    2503              :                  * In parallel mode, this code runs in the leader process.  We
    2504              :                  * construct an array of candidate TEs, then sort it into decreasing
    2505              :                  * size order, then dispatch each TE to a data-transfer worker.  By
    2506              :                  * dumping larger tables first, we avoid getting into a situation
    2507              :                  * where we're down to one job and it's big, losing parallelism.
    2508              :                  */
    2509            0 :                 TocEntry  **tes;
    2510            0 :                 int                     ntes;
    2511              : 
    2512            0 :                 tes = (TocEntry **) pg_malloc(AH->tocCount * sizeof(TocEntry *));
    2513            0 :                 ntes = 0;
    2514            0 :                 for (te = AH->toc->next; te != AH->toc; te = te->next)
    2515              :                 {
    2516              :                         /* Consider only TEs with dataDumper functions ... */
    2517            0 :                         if (!te->dataDumper)
    2518            0 :                                 continue;
    2519              :                         /* ... and ignore ones not enabled for dump */
    2520            0 :                         if ((te->reqs & REQ_DATA) == 0)
    2521            0 :                                 continue;
    2522              : 
    2523            0 :                         tes[ntes++] = te;
    2524            0 :                 }
    2525              : 
    2526            0 :                 if (ntes > 1)
    2527            0 :                         qsort(tes, ntes, sizeof(TocEntry *), TocEntrySizeCompareQsort);
    2528              : 
    2529            0 :                 for (int i = 0; i < ntes; i++)
    2530            0 :                         DispatchJobForTocEntry(AH, pstate, tes[i], ACT_DUMP,
    2531              :                                                                    mark_dump_job_done, NULL);
    2532              : 
    2533            0 :                 pg_free(tes);
    2534              : 
    2535              :                 /* Now wait for workers to finish. */
    2536            0 :                 WaitForWorkers(AH, pstate, WFW_ALL_IDLE);
    2537            0 :         }
    2538              :         else
    2539              :         {
    2540              :                 /* Non-parallel mode: just dump all candidate TEs sequentially. */
    2541            0 :                 for (te = AH->toc->next; te != AH->toc; te = te->next)
    2542              :                 {
    2543              :                         /* Must have same filter conditions as above */
    2544            0 :                         if (!te->dataDumper)
    2545            0 :                                 continue;
    2546            0 :                         if ((te->reqs & REQ_DATA) == 0)
    2547            0 :                                 continue;
    2548              : 
    2549            0 :                         WriteDataChunksForTocEntry(AH, te);
    2550            0 :                 }
    2551              :         }
    2552            0 : }
    2553              : 
    2554              : 
    2555              : /*
    2556              :  * Callback function that's invoked in the leader process after a step has
    2557              :  * been parallel dumped.
    2558              :  *
    2559              :  * We don't need to do anything except check for worker failure.
    2560              :  */
    2561              : static void
    2562            0 : mark_dump_job_done(ArchiveHandle *AH,
    2563              :                                    TocEntry *te,
    2564              :                                    int status,
    2565              :                                    void *callback_data)
    2566              : {
    2567            0 :         pg_log_info("finished item %d %s %s",
    2568              :                                 te->dumpId, te->desc, te->tag);
    2569              : 
    2570            0 :         if (status != 0)
    2571            0 :                 pg_fatal("worker process failed: exit code %d",
    2572              :                                  status);
    2573            0 : }
    2574              : 
    2575              : 
    2576              : void
    2577            0 : WriteDataChunksForTocEntry(ArchiveHandle *AH, TocEntry *te)
    2578              : {
    2579            0 :         StartDataPtrType startPtr;
    2580            0 :         EndDataPtrType endPtr;
    2581              : 
    2582            0 :         AH->currToc = te;
    2583              : 
    2584            0 :         if (strcmp(te->desc, "BLOBS") == 0)
    2585              :         {
    2586            0 :                 startPtr = AH->StartLOsPtr;
    2587            0 :                 endPtr = AH->EndLOsPtr;
    2588            0 :         }
    2589              :         else
    2590              :         {
    2591            0 :                 startPtr = AH->StartDataPtr;
    2592            0 :                 endPtr = AH->EndDataPtr;
    2593              :         }
    2594              : 
    2595            0 :         if (startPtr != NULL)
    2596            0 :                 (*startPtr) (AH, te);
    2597              : 
    2598              :         /*
    2599              :          * The user-provided DataDumper routine needs to call AH->WriteData
    2600              :          */
    2601            0 :         te->dataDumper((Archive *) AH, te->dataDumperArg);
    2602              : 
    2603            0 :         if (endPtr != NULL)
    2604            0 :                 (*endPtr) (AH, te);
    2605              : 
    2606            0 :         AH->currToc = NULL;
    2607            0 : }
    2608              : 
    2609              : void
    2610            0 : WriteToc(ArchiveHandle *AH)
    2611              : {
    2612            0 :         TocEntry   *te;
    2613            0 :         char            workbuf[32];
    2614            0 :         int                     tocCount;
    2615            0 :         int                     i;
    2616              : 
    2617              :         /* count entries that will actually be dumped */
    2618            0 :         tocCount = 0;
    2619            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
    2620              :         {
    2621            0 :                 if ((te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS | REQ_SPECIAL)) != 0)
    2622            0 :                         tocCount++;
    2623            0 :         }
    2624              : 
    2625              :         /* printf("%d TOC Entries to save\n", tocCount); */
    2626              : 
    2627            0 :         WriteInt(AH, tocCount);
    2628              : 
    2629            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
    2630              :         {
    2631            0 :                 if ((te->reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS | REQ_SPECIAL)) == 0)
    2632            0 :                         continue;
    2633              : 
    2634            0 :                 WriteInt(AH, te->dumpId);
    2635            0 :                 WriteInt(AH, te->dataDumper ? 1 : 0);
    2636              : 
    2637              :                 /* OID is recorded as a string for historical reasons */
    2638            0 :                 sprintf(workbuf, "%u", te->catalogId.tableoid);
    2639            0 :                 WriteStr(AH, workbuf);
    2640            0 :                 sprintf(workbuf, "%u", te->catalogId.oid);
    2641            0 :                 WriteStr(AH, workbuf);
    2642              : 
    2643            0 :                 WriteStr(AH, te->tag);
    2644            0 :                 WriteStr(AH, te->desc);
    2645            0 :                 WriteInt(AH, te->section);
    2646              : 
    2647            0 :                 if (te->defnLen)
    2648              :                 {
    2649              :                         /*
    2650              :                          * defnLen should only be set for custom format's second call to
    2651              :                          * WriteToc(), which rewrites the TOC in place to update data
    2652              :                          * offsets.  Instead of calling the defnDumper a second time
    2653              :                          * (which could involve re-executing queries), just skip writing
    2654              :                          * the entry.  While regenerating the definition should
    2655              :                          * theoretically produce the same result as before, it's expensive
    2656              :                          * and feels risky.
    2657              :                          *
    2658              :                          * The custom format only calls WriteToc() a second time if
    2659              :                          * fseeko() is usable (see _CloseArchive() in pg_backup_custom.c),
    2660              :                          * so we can safely use it without checking.  For other formats,
    2661              :                          * we fail because one of our assumptions must no longer hold
    2662              :                          * true.
    2663              :                          *
    2664              :                          * XXX This is a layering violation, but the alternative is an
    2665              :                          * awkward and complicated callback infrastructure for this
    2666              :                          * special case.  This might be worth revisiting in the future.
    2667              :                          */
    2668            0 :                         if (AH->format != archCustom)
    2669            0 :                                 pg_fatal("unexpected TOC entry in WriteToc(): %d %s %s",
    2670              :                                                  te->dumpId, te->desc, te->tag);
    2671              : 
    2672            0 :                         if (fseeko(AH->FH, te->defnLen, SEEK_CUR) != 0)
    2673            0 :                                 pg_fatal("error during file seek: %m");
    2674            0 :                 }
    2675            0 :                 else if (te->defnDumper)
    2676              :                 {
    2677            0 :                         char       *defn = te->defnDumper((Archive *) AH, te->defnDumperArg, te);
    2678              : 
    2679            0 :                         te->defnLen = WriteStr(AH, defn);
    2680            0 :                         pg_free(defn);
    2681            0 :                 }
    2682              :                 else
    2683            0 :                         WriteStr(AH, te->defn);
    2684              : 
    2685            0 :                 WriteStr(AH, te->dropStmt);
    2686            0 :                 WriteStr(AH, te->copyStmt);
    2687            0 :                 WriteStr(AH, te->namespace);
    2688            0 :                 WriteStr(AH, te->tablespace);
    2689            0 :                 WriteStr(AH, te->tableam);
    2690            0 :                 WriteInt(AH, te->relkind);
    2691            0 :                 WriteStr(AH, te->owner);
    2692            0 :                 WriteStr(AH, "false");
    2693              : 
    2694              :                 /* Dump list of dependencies */
    2695            0 :                 for (i = 0; i < te->nDeps; i++)
    2696              :                 {
    2697            0 :                         sprintf(workbuf, "%d", te->dependencies[i]);
    2698            0 :                         WriteStr(AH, workbuf);
    2699            0 :                 }
    2700            0 :                 WriteStr(AH, NULL);             /* Terminate List */
    2701              : 
    2702            0 :                 if (AH->WriteExtraTocPtr)
    2703            0 :                         AH->WriteExtraTocPtr(AH, te);
    2704            0 :         }
    2705            0 : }
    2706              : 
    2707              : void
    2708            0 : ReadToc(ArchiveHandle *AH)
    2709              : {
    2710            0 :         int                     i;
    2711            0 :         char       *tmp;
    2712            0 :         DumpId     *deps;
    2713            0 :         int                     depIdx;
    2714            0 :         int                     depSize;
    2715            0 :         TocEntry   *te;
    2716            0 :         bool            is_supported;
    2717              : 
    2718            0 :         AH->tocCount = ReadInt(AH);
    2719            0 :         AH->maxDumpId = 0;
    2720              : 
    2721            0 :         for (i = 0; i < AH->tocCount; i++)
    2722              :         {
    2723            0 :                 te = (TocEntry *) pg_malloc0(sizeof(TocEntry));
    2724            0 :                 te->dumpId = ReadInt(AH);
    2725              : 
    2726            0 :                 if (te->dumpId > AH->maxDumpId)
    2727            0 :                         AH->maxDumpId = te->dumpId;
    2728              : 
    2729              :                 /* Sanity check */
    2730            0 :                 if (te->dumpId <= 0)
    2731            0 :                         pg_fatal("entry ID %d out of range -- perhaps a corrupt TOC",
    2732              :                                          te->dumpId);
    2733              : 
    2734            0 :                 te->hadDumper = ReadInt(AH);
    2735              : 
    2736            0 :                 if (AH->version >= K_VERS_1_8)
    2737              :                 {
    2738            0 :                         tmp = ReadStr(AH);
    2739            0 :                         sscanf(tmp, "%u", &te->catalogId.tableoid);
    2740            0 :                         free(tmp);
    2741            0 :                 }
    2742              :                 else
    2743            0 :                         te->catalogId.tableoid = InvalidOid;
    2744            0 :                 tmp = ReadStr(AH);
    2745            0 :                 sscanf(tmp, "%u", &te->catalogId.oid);
    2746            0 :                 free(tmp);
    2747              : 
    2748            0 :                 te->tag = ReadStr(AH);
    2749            0 :                 te->desc = ReadStr(AH);
    2750              : 
    2751            0 :                 if (AH->version >= K_VERS_1_11)
    2752              :                 {
    2753            0 :                         te->section = ReadInt(AH);
    2754            0 :                 }
    2755              :                 else
    2756              :                 {
    2757              :                         /*
    2758              :                          * Rules for pre-8.4 archives wherein pg_dump hasn't classified
    2759              :                          * the entries into sections.  This list need not cover entry
    2760              :                          * types added later than 8.4.
    2761              :                          */
    2762            0 :                         if (strcmp(te->desc, "COMMENT") == 0 ||
    2763            0 :                                 strcmp(te->desc, "ACL") == 0 ||
    2764            0 :                                 strcmp(te->desc, "ACL LANGUAGE") == 0)
    2765            0 :                                 te->section = SECTION_NONE;
    2766            0 :                         else if (strcmp(te->desc, "TABLE DATA") == 0 ||
    2767            0 :                                          strcmp(te->desc, "BLOBS") == 0 ||
    2768            0 :                                          strcmp(te->desc, "BLOB COMMENTS") == 0)
    2769            0 :                                 te->section = SECTION_DATA;
    2770            0 :                         else if (strcmp(te->desc, "CONSTRAINT") == 0 ||
    2771            0 :                                          strcmp(te->desc, "CHECK CONSTRAINT") == 0 ||
    2772            0 :                                          strcmp(te->desc, "FK CONSTRAINT") == 0 ||
    2773            0 :                                          strcmp(te->desc, "INDEX") == 0 ||
    2774            0 :                                          strcmp(te->desc, "RULE") == 0 ||
    2775            0 :                                          strcmp(te->desc, "TRIGGER") == 0)
    2776            0 :                                 te->section = SECTION_POST_DATA;
    2777              :                         else
    2778            0 :                                 te->section = SECTION_PRE_DATA;
    2779              :                 }
    2780              : 
    2781            0 :                 te->defn = ReadStr(AH);
    2782            0 :                 te->dropStmt = ReadStr(AH);
    2783              : 
    2784            0 :                 if (AH->version >= K_VERS_1_3)
    2785            0 :                         te->copyStmt = ReadStr(AH);
    2786              : 
    2787            0 :                 if (AH->version >= K_VERS_1_6)
    2788            0 :                         te->namespace = ReadStr(AH);
    2789              : 
    2790            0 :                 if (AH->version >= K_VERS_1_10)
    2791            0 :                         te->tablespace = ReadStr(AH);
    2792              : 
    2793            0 :                 if (AH->version >= K_VERS_1_14)
    2794            0 :                         te->tableam = ReadStr(AH);
    2795              : 
    2796            0 :                 if (AH->version >= K_VERS_1_16)
    2797            0 :                         te->relkind = ReadInt(AH);
    2798              : 
    2799            0 :                 te->owner = ReadStr(AH);
    2800            0 :                 is_supported = true;
    2801            0 :                 if (AH->version < K_VERS_1_9)
    2802            0 :                         is_supported = false;
    2803              :                 else
    2804              :                 {
    2805            0 :                         tmp = ReadStr(AH);
    2806              : 
    2807            0 :                         if (strcmp(tmp, "true") == 0)
    2808            0 :                                 is_supported = false;
    2809              : 
    2810            0 :                         free(tmp);
    2811              :                 }
    2812              : 
    2813            0 :                 if (!is_supported)
    2814            0 :                         pg_log_warning("restoring tables WITH OIDS is not supported anymore");
    2815              : 
    2816              :                 /* Read TOC entry dependencies */
    2817            0 :                 if (AH->version >= K_VERS_1_5)
    2818              :                 {
    2819            0 :                         depSize = 100;
    2820            0 :                         deps = (DumpId *) pg_malloc(sizeof(DumpId) * depSize);
    2821            0 :                         depIdx = 0;
    2822            0 :                         for (;;)
    2823              :                         {
    2824            0 :                                 tmp = ReadStr(AH);
    2825            0 :                                 if (!tmp)
    2826            0 :                                         break;          /* end of list */
    2827            0 :                                 if (depIdx >= depSize)
    2828              :                                 {
    2829            0 :                                         depSize *= 2;
    2830            0 :                                         deps = (DumpId *) pg_realloc(deps, sizeof(DumpId) * depSize);
    2831            0 :                                 }
    2832            0 :                                 sscanf(tmp, "%d", &deps[depIdx]);
    2833            0 :                                 free(tmp);
    2834            0 :                                 depIdx++;
    2835              :                         }
    2836              : 
    2837            0 :                         if (depIdx > 0)              /* We have a non-null entry */
    2838              :                         {
    2839            0 :                                 deps = (DumpId *) pg_realloc(deps, sizeof(DumpId) * depIdx);
    2840            0 :                                 te->dependencies = deps;
    2841            0 :                                 te->nDeps = depIdx;
    2842            0 :                         }
    2843              :                         else
    2844              :                         {
    2845            0 :                                 free(deps);
    2846            0 :                                 te->dependencies = NULL;
    2847            0 :                                 te->nDeps = 0;
    2848              :                         }
    2849            0 :                 }
    2850              :                 else
    2851              :                 {
    2852            0 :                         te->dependencies = NULL;
    2853            0 :                         te->nDeps = 0;
    2854              :                 }
    2855            0 :                 te->dataLength = 0;
    2856              : 
    2857            0 :                 if (AH->ReadExtraTocPtr)
    2858            0 :                         AH->ReadExtraTocPtr(AH, te);
    2859              : 
    2860            0 :                 pg_log_debug("read TOC entry %d (ID %d) for %s %s",
    2861              :                                          i, te->dumpId, te->desc, te->tag);
    2862              : 
    2863              :                 /* link completed entry into TOC circular list */
    2864            0 :                 te->prev = AH->toc->prev;
    2865            0 :                 AH->toc->prev->next = te;
    2866            0 :                 AH->toc->prev = te;
    2867            0 :                 te->next = AH->toc;
    2868              : 
    2869              :                 /* special processing immediately upon read for some items */
    2870            0 :                 if (strcmp(te->desc, "ENCODING") == 0)
    2871            0 :                         processEncodingEntry(AH, te);
    2872            0 :                 else if (strcmp(te->desc, "STDSTRINGS") == 0)
    2873            0 :                         processStdStringsEntry(AH, te);
    2874            0 :                 else if (strcmp(te->desc, "SEARCHPATH") == 0)
    2875            0 :                         processSearchPathEntry(AH, te);
    2876            0 :         }
    2877            0 : }
    2878              : 
    2879              : static void
    2880            0 : processEncodingEntry(ArchiveHandle *AH, TocEntry *te)
    2881              : {
    2882              :         /* te->defn should have the form SET client_encoding = 'foo'; */
    2883            0 :         char       *defn = pg_strdup(te->defn);
    2884            0 :         char       *ptr1;
    2885            0 :         char       *ptr2 = NULL;
    2886            0 :         int                     encoding;
    2887              : 
    2888            0 :         ptr1 = strchr(defn, '\'');
    2889            0 :         if (ptr1)
    2890            0 :                 ptr2 = strchr(++ptr1, '\'');
    2891            0 :         if (ptr2)
    2892              :         {
    2893            0 :                 *ptr2 = '\0';
    2894            0 :                 encoding = pg_char_to_encoding(ptr1);
    2895            0 :                 if (encoding < 0)
    2896            0 :                         pg_fatal("unrecognized encoding \"%s\"",
    2897              :                                          ptr1);
    2898            0 :                 AH->public.encoding = encoding;
    2899            0 :                 setFmtEncoding(encoding);
    2900            0 :         }
    2901              :         else
    2902            0 :                 pg_fatal("invalid ENCODING item: %s",
    2903              :                                  te->defn);
    2904              : 
    2905            0 :         free(defn);
    2906            0 : }
    2907              : 
    2908              : static void
    2909            0 : processStdStringsEntry(ArchiveHandle *AH, TocEntry *te)
    2910              : {
    2911              :         /* te->defn should have the form SET standard_conforming_strings = 'x'; */
    2912            0 :         char       *ptr1;
    2913              : 
    2914            0 :         ptr1 = strchr(te->defn, '\'');
    2915            0 :         if (ptr1 && strncmp(ptr1, "'on'", 4) == 0)
    2916            0 :                 AH->public.std_strings = true;
    2917            0 :         else if (ptr1 && strncmp(ptr1, "'off'", 5) == 0)
    2918            0 :                 AH->public.std_strings = false;
    2919              :         else
    2920            0 :                 pg_fatal("invalid STDSTRINGS item: %s",
    2921              :                                  te->defn);
    2922            0 : }
    2923              : 
    2924              : static void
    2925            0 : processSearchPathEntry(ArchiveHandle *AH, TocEntry *te)
    2926              : {
    2927              :         /*
    2928              :          * te->defn should contain a command to set search_path.  We just copy it
    2929              :          * verbatim for use later.
    2930              :          */
    2931            0 :         AH->public.searchpath = pg_strdup(te->defn);
    2932            0 : }
    2933              : 
    2934              : static void
    2935            0 : StrictNamesCheck(RestoreOptions *ropt)
    2936              : {
    2937            0 :         const char *missing_name;
    2938              : 
    2939            0 :         Assert(ropt->strict_names);
    2940              : 
    2941            0 :         if (ropt->schemaNames.head != NULL)
    2942              :         {
    2943            0 :                 missing_name = simple_string_list_not_touched(&ropt->schemaNames);
    2944            0 :                 if (missing_name != NULL)
    2945            0 :                         pg_fatal("schema \"%s\" not found", missing_name);
    2946            0 :         }
    2947              : 
    2948            0 :         if (ropt->tableNames.head != NULL)
    2949              :         {
    2950            0 :                 missing_name = simple_string_list_not_touched(&ropt->tableNames);
    2951            0 :                 if (missing_name != NULL)
    2952            0 :                         pg_fatal("table \"%s\" not found", missing_name);
    2953            0 :         }
    2954              : 
    2955            0 :         if (ropt->indexNames.head != NULL)
    2956              :         {
    2957            0 :                 missing_name = simple_string_list_not_touched(&ropt->indexNames);
    2958            0 :                 if (missing_name != NULL)
    2959            0 :                         pg_fatal("index \"%s\" not found", missing_name);
    2960            0 :         }
    2961              : 
    2962            0 :         if (ropt->functionNames.head != NULL)
    2963              :         {
    2964            0 :                 missing_name = simple_string_list_not_touched(&ropt->functionNames);
    2965            0 :                 if (missing_name != NULL)
    2966            0 :                         pg_fatal("function \"%s\" not found", missing_name);
    2967            0 :         }
    2968              : 
    2969            0 :         if (ropt->triggerNames.head != NULL)
    2970              :         {
    2971            0 :                 missing_name = simple_string_list_not_touched(&ropt->triggerNames);
    2972            0 :                 if (missing_name != NULL)
    2973            0 :                         pg_fatal("trigger \"%s\" not found", missing_name);
    2974            0 :         }
    2975            0 : }
    2976              : 
    2977              : /*
    2978              :  * Determine whether we want to restore this TOC entry.
    2979              :  *
    2980              :  * Returns 0 if entry should be skipped, or some combination of the
    2981              :  * REQ_SCHEMA, REQ_DATA, and REQ_STATS bits if we want to restore schema, data
    2982              :  * and/or statistics portions of this TOC entry, or REQ_SPECIAL if it's a
    2983              :  * special entry.
    2984              :  */
    2985              : static int
    2986            0 : _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH)
    2987              : {
    2988            0 :         int                     res = REQ_SCHEMA | REQ_DATA;
    2989            0 :         RestoreOptions *ropt = AH->public.ropt;
    2990              : 
    2991              :         /*
    2992              :          * For binary upgrade mode, dump pg_largeobject_metadata and the
    2993              :          * associated pg_shdepend rows. This is faster to restore than the
    2994              :          * equivalent set of large object commands.  We can only do this for
    2995              :          * upgrades from v12 and newer; in older versions, pg_largeobject_metadata
    2996              :          * was created WITH OIDS, so the OID column is hidden and won't be dumped.
    2997              :          */
    2998            0 :         if (ropt->binary_upgrade && AH->public.remoteVersion >= 120000 &&
    2999            0 :                 strcmp(te->desc, "TABLE DATA") == 0 &&
    3000            0 :                 (te->catalogId.oid == LargeObjectMetadataRelationId ||
    3001            0 :                  te->catalogId.oid == SharedDependRelationId))
    3002            0 :                 return REQ_DATA;
    3003              : 
    3004              :         /* These items are treated specially */
    3005            0 :         if (strcmp(te->desc, "ENCODING") == 0 ||
    3006            0 :                 strcmp(te->desc, "STDSTRINGS") == 0 ||
    3007            0 :                 strcmp(te->desc, "SEARCHPATH") == 0)
    3008            0 :                 return REQ_SPECIAL;
    3009              : 
    3010            0 :         if (strcmp(te->desc, "STATISTICS DATA") == 0)
    3011              :         {
    3012            0 :                 if (!ropt->dumpStatistics)
    3013            0 :                         return 0;
    3014              : 
    3015            0 :                 res = REQ_STATS;
    3016            0 :         }
    3017              : 
    3018              :         /*
    3019              :          * DATABASE and DATABASE PROPERTIES also have a special rule: they are
    3020              :          * restored in createDB mode, and not restored otherwise, independently of
    3021              :          * all else.
    3022              :          */
    3023            0 :         if (strcmp(te->desc, "DATABASE") == 0 ||
    3024            0 :                 strcmp(te->desc, "DATABASE PROPERTIES") == 0)
    3025              :         {
    3026            0 :                 if (ropt->createDB)
    3027            0 :                         return REQ_SCHEMA;
    3028              :                 else
    3029            0 :                         return 0;
    3030              :         }
    3031              : 
    3032              :         /*
    3033              :          * Process exclusions that affect certain classes of TOC entries.
    3034              :          */
    3035              : 
    3036              :         /* If it's an ACL, maybe ignore it */
    3037            0 :         if (ropt->aclsSkip && _tocEntryIsACL(te))
    3038            0 :                 return 0;
    3039              : 
    3040              :         /* If it's a comment, maybe ignore it */
    3041            0 :         if (ropt->no_comments && strcmp(te->desc, "COMMENT") == 0)
    3042            0 :                 return 0;
    3043              : 
    3044              :         /* If it's a policy, maybe ignore it */
    3045            0 :         if (ropt->no_policies &&
    3046            0 :                 (strcmp(te->desc, "POLICY") == 0 ||
    3047            0 :                  strcmp(te->desc, "ROW SECURITY") == 0))
    3048            0 :                 return 0;
    3049              : 
    3050              :         /*
    3051              :          * If it's a comment on a policy, a publication, or a subscription, maybe
    3052              :          * ignore it.
    3053              :          */
    3054            0 :         if (strcmp(te->desc, "COMMENT") == 0)
    3055              :         {
    3056            0 :                 if (ropt->no_policies &&
    3057            0 :                         strncmp(te->tag, "POLICY", strlen("POLICY")) == 0)
    3058            0 :                         return 0;
    3059              : 
    3060            0 :                 if (ropt->no_publications &&
    3061            0 :                         strncmp(te->tag, "PUBLICATION", strlen("PUBLICATION")) == 0)
    3062            0 :                         return 0;
    3063              : 
    3064            0 :                 if (ropt->no_subscriptions &&
    3065            0 :                         strncmp(te->tag, "SUBSCRIPTION", strlen("SUBSCRIPTION")) == 0)
    3066            0 :                         return 0;
    3067            0 :         }
    3068              : 
    3069              :         /*
    3070              :          * If it's a publication or a table part of a publication, maybe ignore
    3071              :          * it.
    3072              :          */
    3073            0 :         if (ropt->no_publications &&
    3074            0 :                 (strcmp(te->desc, "PUBLICATION") == 0 ||
    3075            0 :                  strcmp(te->desc, "PUBLICATION TABLE") == 0 ||
    3076            0 :                  strcmp(te->desc, "PUBLICATION TABLES IN SCHEMA") == 0))
    3077            0 :                 return 0;
    3078              : 
    3079              :         /* If it's a security label, maybe ignore it */
    3080            0 :         if (ropt->no_security_labels && strcmp(te->desc, "SECURITY LABEL") == 0)
    3081            0 :                 return 0;
    3082              : 
    3083              :         /*
    3084              :          * If it's a security label on a publication or a subscription, maybe
    3085              :          * ignore it.
    3086              :          */
    3087            0 :         if (strcmp(te->desc, "SECURITY LABEL") == 0)
    3088              :         {
    3089            0 :                 if (ropt->no_publications &&
    3090            0 :                         strncmp(te->tag, "PUBLICATION", strlen("PUBLICATION")) == 0)
    3091            0 :                         return 0;
    3092              : 
    3093            0 :                 if (ropt->no_subscriptions &&
    3094            0 :                         strncmp(te->tag, "SUBSCRIPTION", strlen("SUBSCRIPTION")) == 0)
    3095            0 :                         return 0;
    3096            0 :         }
    3097              : 
    3098              :         /* If it's a subscription, maybe ignore it */
    3099            0 :         if (ropt->no_subscriptions && strcmp(te->desc, "SUBSCRIPTION") == 0)
    3100            0 :                 return 0;
    3101              : 
    3102              :         /* Ignore it if section is not to be dumped/restored */
    3103            0 :         switch (curSection)
    3104              :         {
    3105              :                 case SECTION_PRE_DATA:
    3106            0 :                         if (!(ropt->dumpSections & DUMP_PRE_DATA))
    3107            0 :                                 return 0;
    3108            0 :                         break;
    3109              :                 case SECTION_DATA:
    3110            0 :                         if (!(ropt->dumpSections & DUMP_DATA))
    3111            0 :                                 return 0;
    3112            0 :                         break;
    3113              :                 case SECTION_POST_DATA:
    3114            0 :                         if (!(ropt->dumpSections & DUMP_POST_DATA))
    3115            0 :                                 return 0;
    3116            0 :                         break;
    3117              :                 default:
    3118              :                         /* shouldn't get here, really, but ignore it */
    3119            0 :                         return 0;
    3120              :         }
    3121              : 
    3122              :         /* Ignore it if rejected by idWanted[] (cf. SortTocFromFile) */
    3123            0 :         if (ropt->idWanted && !ropt->idWanted[te->dumpId - 1])
    3124            0 :                 return 0;
    3125              : 
    3126              :         /*
    3127              :          * Check options for selective dump/restore.
    3128              :          */
    3129            0 :         if (strcmp(te->desc, "ACL") == 0 ||
    3130            0 :                 strcmp(te->desc, "COMMENT") == 0 ||
    3131            0 :                 strcmp(te->desc, "STATISTICS DATA") == 0 ||
    3132            0 :                 strcmp(te->desc, "SECURITY LABEL") == 0)
    3133              :         {
    3134              :                 /* Database properties react to createDB, not selectivity options. */
    3135            0 :                 if (strncmp(te->tag, "DATABASE ", 9) == 0)
    3136              :                 {
    3137            0 :                         if (!ropt->createDB)
    3138            0 :                                 return 0;
    3139            0 :                 }
    3140            0 :                 else if (ropt->schemaNames.head != NULL ||
    3141            0 :                                  ropt->schemaExcludeNames.head != NULL ||
    3142            0 :                                  ropt->selTypes)
    3143              :                 {
    3144              :                         /*
    3145              :                          * In a selective dump/restore, we want to restore these dependent
    3146              :                          * TOC entry types only if their parent object is being restored.
    3147              :                          * Without selectivity options, we let through everything in the
    3148              :                          * archive.  Note there may be such entries with no parent, eg
    3149              :                          * non-default ACLs for built-in objects.  Also, we make
    3150              :                          * per-column ACLs additionally depend on the table's ACL if any
    3151              :                          * to ensure correct restore order, so those dependencies should
    3152              :                          * be ignored in this check.
    3153              :                          *
    3154              :                          * This code depends on the parent having been marked already,
    3155              :                          * which should be the case; if it isn't, perhaps due to
    3156              :                          * SortTocFromFile rearrangement, skipping the dependent entry
    3157              :                          * seems prudent anyway.
    3158              :                          *
    3159              :                          * Ideally we'd handle, eg, table CHECK constraints this way too.
    3160              :                          * But it's hard to tell which of their dependencies is the one to
    3161              :                          * consult.
    3162              :                          */
    3163            0 :                         bool            dumpthis = false;
    3164              : 
    3165            0 :                         for (int i = 0; i < te->nDeps; i++)
    3166              :                         {
    3167            0 :                                 TocEntry   *pte = getTocEntryByDumpId(AH, te->dependencies[i]);
    3168              : 
    3169            0 :                                 if (!pte)
    3170            0 :                                         continue;       /* probably shouldn't happen */
    3171            0 :                                 if (strcmp(pte->desc, "ACL") == 0)
    3172            0 :                                         continue;       /* ignore dependency on another ACL */
    3173            0 :                                 if (pte->reqs == 0)
    3174            0 :                                         continue;       /* this object isn't marked, so ignore it */
    3175              :                                 /* Found a parent to be dumped, so we want to dump this too */
    3176            0 :                                 dumpthis = true;
    3177            0 :                                 break;
    3178            0 :                         }
    3179            0 :                         if (!dumpthis)
    3180            0 :                                 return 0;
    3181            0 :                 }
    3182            0 :         }
    3183              :         else
    3184              :         {
    3185              :                 /* Apply selective-restore rules for standalone TOC entries. */
    3186            0 :                 if (ropt->schemaNames.head != NULL)
    3187              :                 {
    3188              :                         /* If no namespace is specified, it means all. */
    3189            0 :                         if (!te->namespace)
    3190            0 :                                 return 0;
    3191            0 :                         if (!simple_string_list_member(&ropt->schemaNames, te->namespace))
    3192            0 :                                 return 0;
    3193            0 :                 }
    3194              : 
    3195            0 :                 if (ropt->schemaExcludeNames.head != NULL &&
    3196            0 :                         te->namespace &&
    3197            0 :                         simple_string_list_member(&ropt->schemaExcludeNames, te->namespace))
    3198            0 :                         return 0;
    3199              : 
    3200            0 :                 if (ropt->selTypes)
    3201              :                 {
    3202            0 :                         if (strcmp(te->desc, "TABLE") == 0 ||
    3203            0 :                                 strcmp(te->desc, "TABLE DATA") == 0 ||
    3204            0 :                                 strcmp(te->desc, "VIEW") == 0 ||
    3205            0 :                                 strcmp(te->desc, "FOREIGN TABLE") == 0 ||
    3206            0 :                                 strcmp(te->desc, "MATERIALIZED VIEW") == 0 ||
    3207            0 :                                 strcmp(te->desc, "MATERIALIZED VIEW DATA") == 0 ||
    3208            0 :                                 strcmp(te->desc, "SEQUENCE") == 0 ||
    3209            0 :                                 strcmp(te->desc, "SEQUENCE SET") == 0)
    3210              :                         {
    3211            0 :                                 if (!ropt->selTable)
    3212            0 :                                         return 0;
    3213            0 :                                 if (ropt->tableNames.head != NULL &&
    3214            0 :                                         !simple_string_list_member(&ropt->tableNames, te->tag))
    3215            0 :                                         return 0;
    3216            0 :                         }
    3217            0 :                         else if (strcmp(te->desc, "INDEX") == 0)
    3218              :                         {
    3219            0 :                                 if (!ropt->selIndex)
    3220            0 :                                         return 0;
    3221            0 :                                 if (ropt->indexNames.head != NULL &&
    3222            0 :                                         !simple_string_list_member(&ropt->indexNames, te->tag))
    3223            0 :                                         return 0;
    3224            0 :                         }
    3225            0 :                         else if (strcmp(te->desc, "FUNCTION") == 0 ||
    3226            0 :                                          strcmp(te->desc, "AGGREGATE") == 0 ||
    3227            0 :                                          strcmp(te->desc, "PROCEDURE") == 0)
    3228              :                         {
    3229            0 :                                 if (!ropt->selFunction)
    3230            0 :                                         return 0;
    3231            0 :                                 if (ropt->functionNames.head != NULL &&
    3232            0 :                                         !simple_string_list_member(&ropt->functionNames, te->tag))
    3233            0 :                                         return 0;
    3234            0 :                         }
    3235            0 :                         else if (strcmp(te->desc, "TRIGGER") == 0)
    3236              :                         {
    3237            0 :                                 if (!ropt->selTrigger)
    3238            0 :                                         return 0;
    3239            0 :                                 if (ropt->triggerNames.head != NULL &&
    3240            0 :                                         !simple_string_list_member(&ropt->triggerNames, te->tag))
    3241            0 :                                         return 0;
    3242            0 :                         }
    3243              :                         else
    3244            0 :                                 return 0;
    3245            0 :                 }
    3246              :         }
    3247              : 
    3248              : 
    3249              :         /*
    3250              :          * Determine whether the TOC entry contains schema and/or data components,
    3251              :          * and mask off inapplicable REQ bits.  If it had a dataDumper, assume
    3252              :          * it's both schema and data.  Otherwise it's probably schema-only, but
    3253              :          * there are exceptions.
    3254              :          */
    3255            0 :         if (!te->hadDumper)
    3256              :         {
    3257              :                 /*
    3258              :                  * Special Case: If 'SEQUENCE SET' or anything to do with LOs, then it
    3259              :                  * is considered a data entry.  We don't need to check for BLOBS or
    3260              :                  * old-style BLOB COMMENTS entries, because they will have hadDumper =
    3261              :                  * true ... but we do need to check new-style BLOB ACLs, comments,
    3262              :                  * etc.
    3263              :                  */
    3264            0 :                 if (strcmp(te->desc, "SEQUENCE SET") == 0 ||
    3265            0 :                         strcmp(te->desc, "BLOB") == 0 ||
    3266            0 :                         strcmp(te->desc, "BLOB METADATA") == 0 ||
    3267            0 :                         (strcmp(te->desc, "ACL") == 0 &&
    3268            0 :                          strncmp(te->tag, "LARGE OBJECT", 12) == 0) ||
    3269            0 :                         (strcmp(te->desc, "COMMENT") == 0 &&
    3270            0 :                          strncmp(te->tag, "LARGE OBJECT", 12) == 0) ||
    3271            0 :                         (strcmp(te->desc, "SECURITY LABEL") == 0 &&
    3272            0 :                          strncmp(te->tag, "LARGE OBJECT", 12) == 0))
    3273            0 :                         res = res & REQ_DATA;
    3274              :                 else
    3275            0 :                         res = res & ~REQ_DATA;
    3276            0 :         }
    3277              : 
    3278              :         /*
    3279              :          * If there's no definition command, there's no schema component.  Treat
    3280              :          * "load via partition root" comments as not schema.
    3281              :          */
    3282            0 :         if (!te->defn || !te->defn[0] ||
    3283            0 :                 strncmp(te->defn, "-- load via partition root ", 27) == 0)
    3284            0 :                 res = res & ~REQ_SCHEMA;
    3285              : 
    3286              :         /*
    3287              :          * Special case: <Init> type with <Max OID> tag; this is obsolete and we
    3288              :          * always ignore it.
    3289              :          */
    3290            0 :         if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
    3291            0 :                 return 0;
    3292              : 
    3293              :         /* Mask it if we don't want data */
    3294            0 :         if (!ropt->dumpData)
    3295              :         {
    3296              :                 /*
    3297              :                  * The sequence_data option overrides dumpData for SEQUENCE SET.
    3298              :                  *
    3299              :                  * In binary-upgrade mode, even with dumpData unset, we do not mask
    3300              :                  * out large objects.  (Only large object definitions, comments and
    3301              :                  * other metadata should be generated in binary-upgrade mode, not the
    3302              :                  * actual data, but that need not concern us here.)
    3303              :                  */
    3304            0 :                 if (!(ropt->sequence_data && strcmp(te->desc, "SEQUENCE SET") == 0) &&
    3305            0 :                         !(ropt->binary_upgrade &&
    3306            0 :                           (strcmp(te->desc, "BLOB") == 0 ||
    3307            0 :                            strcmp(te->desc, "BLOB METADATA") == 0 ||
    3308            0 :                            (strcmp(te->desc, "ACL") == 0 &&
    3309            0 :                                 strncmp(te->tag, "LARGE OBJECT", 12) == 0) ||
    3310            0 :                            (strcmp(te->desc, "COMMENT") == 0 &&
    3311            0 :                                 strncmp(te->tag, "LARGE OBJECT", 12) == 0) ||
    3312            0 :                            (strcmp(te->desc, "SECURITY LABEL") == 0 &&
    3313            0 :                                 strncmp(te->tag, "LARGE OBJECT", 12) == 0))))
    3314            0 :                         res = res & (REQ_SCHEMA | REQ_STATS);
    3315            0 :         }
    3316              : 
    3317              :         /* Mask it if we don't want schema */
    3318            0 :         if (!ropt->dumpSchema)
    3319            0 :                 res = res & (REQ_DATA | REQ_STATS);
    3320              : 
    3321            0 :         return res;
    3322            0 : }
    3323              : 
    3324              : /*
    3325              :  * Identify which pass we should restore this TOC entry in.
    3326              :  *
    3327              :  * See notes with the RestorePass typedef in pg_backup_archiver.h.
    3328              :  */
    3329              : static RestorePass
    3330            0 : _tocEntryRestorePass(TocEntry *te)
    3331              : {
    3332              :         /* "ACL LANGUAGE" was a crock emitted only in PG 7.4 */
    3333            0 :         if (strcmp(te->desc, "ACL") == 0 ||
    3334            0 :                 strcmp(te->desc, "ACL LANGUAGE") == 0 ||
    3335            0 :                 strcmp(te->desc, "DEFAULT ACL") == 0)
    3336            0 :                 return RESTORE_PASS_ACL;
    3337            0 :         if (strcmp(te->desc, "EVENT TRIGGER") == 0 ||
    3338            0 :                 strcmp(te->desc, "MATERIALIZED VIEW DATA") == 0)
    3339            0 :                 return RESTORE_PASS_POST_ACL;
    3340              : 
    3341              :         /*
    3342              :          * Comments and security labels need to be emitted in the same pass as
    3343              :          * their parent objects. ACLs haven't got comments and security labels,
    3344              :          * and neither do matview data objects, but event triggers do.
    3345              :          * (Fortunately, event triggers haven't got ACLs, or we'd need yet another
    3346              :          * weird special case.)
    3347              :          */
    3348            0 :         if ((strcmp(te->desc, "COMMENT") == 0 ||
    3349            0 :                  strcmp(te->desc, "SECURITY LABEL") == 0) &&
    3350            0 :                 strncmp(te->tag, "EVENT TRIGGER ", 14) == 0)
    3351            0 :                 return RESTORE_PASS_POST_ACL;
    3352              : 
    3353              :         /*
    3354              :          * If statistics data is dependent on materialized view data, it must be
    3355              :          * deferred to RESTORE_PASS_POST_ACL.  Those entries are already marked as
    3356              :          * SECTION_POST_DATA, and some other stats entries (e.g., index stats)
    3357              :          * will also be marked as SECTION_POST_DATA.  Additionally, our lookahead
    3358              :          * code in fetchAttributeStats() assumes that we dump all statistics data
    3359              :          * entries in TOC order.  To ensure this assumption holds, we move all
    3360              :          * statistics data entries in SECTION_POST_DATA to RESTORE_PASS_POST_ACL.
    3361              :          */
    3362            0 :         if (strcmp(te->desc, "STATISTICS DATA") == 0 &&
    3363            0 :                 te->section == SECTION_POST_DATA)
    3364            0 :                 return RESTORE_PASS_POST_ACL;
    3365              : 
    3366              :         /* All else can be handled in the main pass. */
    3367            0 :         return RESTORE_PASS_MAIN;
    3368            0 : }
    3369              : 
    3370              : /*
    3371              :  * Identify TOC entries that are ACLs.
    3372              :  *
    3373              :  * Note: it seems worth duplicating some code here to avoid a hard-wired
    3374              :  * assumption that these are exactly the same entries that we restore during
    3375              :  * the RESTORE_PASS_ACL phase.
    3376              :  */
    3377              : static bool
    3378            0 : _tocEntryIsACL(TocEntry *te)
    3379              : {
    3380              :         /* "ACL LANGUAGE" was a crock emitted only in PG 7.4 */
    3381            0 :         if (strcmp(te->desc, "ACL") == 0 ||
    3382            0 :                 strcmp(te->desc, "ACL LANGUAGE") == 0 ||
    3383            0 :                 strcmp(te->desc, "DEFAULT ACL") == 0)
    3384            0 :                 return true;
    3385            0 :         return false;
    3386            0 : }
    3387              : 
    3388              : /*
    3389              :  * Issue SET commands for parameters that we want to have set the same way
    3390              :  * at all times during execution of a restore script.
    3391              :  */
    3392              : static void
    3393            0 : _doSetFixedOutputState(ArchiveHandle *AH)
    3394              : {
    3395            0 :         RestoreOptions *ropt = AH->public.ropt;
    3396              : 
    3397              :         /*
    3398              :          * Disable timeouts to allow for slow commands, idle parallel workers, etc
    3399              :          */
    3400            0 :         ahprintf(AH, "SET statement_timeout = 0;\n");
    3401            0 :         ahprintf(AH, "SET lock_timeout = 0;\n");
    3402            0 :         ahprintf(AH, "SET idle_in_transaction_session_timeout = 0;\n");
    3403            0 :         ahprintf(AH, "SET transaction_timeout = 0;\n");
    3404              : 
    3405              :         /* Select the correct character set encoding */
    3406            0 :         ahprintf(AH, "SET client_encoding = '%s';\n",
    3407            0 :                          pg_encoding_to_char(AH->public.encoding));
    3408              : 
    3409              :         /* Select the correct string literal syntax */
    3410            0 :         ahprintf(AH, "SET standard_conforming_strings = %s;\n",
    3411            0 :                          AH->public.std_strings ? "on" : "off");
    3412              : 
    3413              :         /* Select the role to be used during restore */
    3414            0 :         if (ropt && ropt->use_role)
    3415            0 :                 ahprintf(AH, "SET ROLE %s;\n", fmtId(ropt->use_role));
    3416              : 
    3417              :         /* Select the dump-time search_path */
    3418            0 :         if (AH->public.searchpath)
    3419            0 :                 ahprintf(AH, "%s", AH->public.searchpath);
    3420              : 
    3421              :         /* Make sure function checking is disabled */
    3422            0 :         ahprintf(AH, "SET check_function_bodies = false;\n");
    3423              : 
    3424              :         /* Ensure that all valid XML data will be accepted */
    3425            0 :         ahprintf(AH, "SET xmloption = content;\n");
    3426              : 
    3427              :         /* Avoid annoying notices etc */
    3428            0 :         ahprintf(AH, "SET client_min_messages = warning;\n");
    3429              : 
    3430              :         /* Adjust row-security state */
    3431            0 :         if (ropt && ropt->enable_row_security)
    3432            0 :                 ahprintf(AH, "SET row_security = on;\n");
    3433              :         else
    3434            0 :                 ahprintf(AH, "SET row_security = off;\n");
    3435              : 
    3436              :         /*
    3437              :          * In --transaction-size mode, we should always be in a transaction when
    3438              :          * we begin to restore objects.
    3439              :          */
    3440            0 :         if (ropt && ropt->txn_size > 0)
    3441              :         {
    3442            0 :                 if (AH->connection)
    3443            0 :                         StartTransaction(&AH->public);
    3444              :                 else
    3445            0 :                         ahprintf(AH, "\nBEGIN;\n");
    3446            0 :                 AH->txnCount = 0;
    3447            0 :         }
    3448              : 
    3449            0 :         ahprintf(AH, "\n");
    3450            0 : }
    3451              : 
    3452              : /*
    3453              :  * Issue a SET SESSION AUTHORIZATION command.  Caller is responsible
    3454              :  * for updating state if appropriate.  If user is NULL or an empty string,
    3455              :  * the specification DEFAULT will be used.
    3456              :  */
    3457              : static void
    3458            0 : _doSetSessionAuth(ArchiveHandle *AH, const char *user)
    3459              : {
    3460            0 :         PQExpBuffer cmd = createPQExpBuffer();
    3461              : 
    3462            0 :         appendPQExpBufferStr(cmd, "SET SESSION AUTHORIZATION ");
    3463              : 
    3464              :         /*
    3465              :          * SQL requires a string literal here.  Might as well be correct.
    3466              :          */
    3467            0 :         if (user && *user)
    3468            0 :                 appendStringLiteralAHX(cmd, user, AH);
    3469              :         else
    3470            0 :                 appendPQExpBufferStr(cmd, "DEFAULT");
    3471            0 :         appendPQExpBufferChar(cmd, ';');
    3472              : 
    3473            0 :         if (RestoringToDB(AH))
    3474              :         {
    3475            0 :                 PGresult   *res;
    3476              : 
    3477            0 :                 res = PQexec(AH->connection, cmd->data);
    3478              : 
    3479            0 :                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    3480              :                         /* NOT warn_or_exit_horribly... use -O instead to skip this. */
    3481            0 :                         pg_fatal("could not set session user to \"%s\": %s",
    3482              :                                          user, PQerrorMessage(AH->connection));
    3483              : 
    3484            0 :                 PQclear(res);
    3485            0 :         }
    3486              :         else
    3487            0 :                 ahprintf(AH, "%s\n\n", cmd->data);
    3488              : 
    3489            0 :         destroyPQExpBuffer(cmd);
    3490            0 : }
    3491              : 
    3492              : 
    3493              : /*
    3494              :  * Issue the commands to connect to the specified database.
    3495              :  *
    3496              :  * If we're currently restoring right into a database, this will
    3497              :  * actually establish a connection. Otherwise it puts a \connect into
    3498              :  * the script output.
    3499              :  */
    3500              : static void
    3501            0 : _reconnectToDB(ArchiveHandle *AH, const char *dbname)
    3502              : {
    3503            0 :         if (RestoringToDB(AH))
    3504            0 :                 ReconnectToServer(AH, dbname);
    3505              :         else
    3506              :         {
    3507            0 :                 PQExpBufferData connectbuf;
    3508            0 :                 RestoreOptions *ropt = AH->public.ropt;
    3509              : 
    3510              :                 /*
    3511              :                  * We must temporarily exit restricted mode for \connect, etc.
    3512              :                  * Anything added between this line and the following \restrict must
    3513              :                  * be careful to avoid any possible meta-command injection vectors.
    3514              :                  */
    3515            0 :                 ahprintf(AH, "\\unrestrict %s\n", ropt->restrict_key);
    3516              : 
    3517            0 :                 initPQExpBuffer(&connectbuf);
    3518            0 :                 appendPsqlMetaConnect(&connectbuf, dbname);
    3519            0 :                 ahprintf(AH, "%s", connectbuf.data);
    3520            0 :                 termPQExpBuffer(&connectbuf);
    3521              : 
    3522            0 :                 ahprintf(AH, "\\restrict %s\n\n", ropt->restrict_key);
    3523            0 :         }
    3524              : 
    3525              :         /*
    3526              :          * NOTE: currUser keeps track of what the imaginary session user in our
    3527              :          * script is.  It's now effectively reset to the original userID.
    3528              :          */
    3529            0 :         free(AH->currUser);
    3530            0 :         AH->currUser = NULL;
    3531              : 
    3532              :         /* don't assume we still know the output schema, tablespace, etc either */
    3533            0 :         free(AH->currSchema);
    3534            0 :         AH->currSchema = NULL;
    3535              : 
    3536            0 :         free(AH->currTableAm);
    3537            0 :         AH->currTableAm = NULL;
    3538              : 
    3539            0 :         free(AH->currTablespace);
    3540            0 :         AH->currTablespace = NULL;
    3541              : 
    3542              :         /* re-establish fixed state */
    3543            0 :         _doSetFixedOutputState(AH);
    3544            0 : }
    3545              : 
    3546              : /*
    3547              :  * Become the specified user, and update state to avoid redundant commands
    3548              :  *
    3549              :  * NULL or empty argument is taken to mean restoring the session default
    3550              :  */
    3551              : static void
    3552            0 : _becomeUser(ArchiveHandle *AH, const char *user)
    3553              : {
    3554            0 :         if (!user)
    3555            0 :                 user = "";                            /* avoid null pointers */
    3556              : 
    3557            0 :         if (AH->currUser && strcmp(AH->currUser, user) == 0)
    3558            0 :                 return;                                 /* no need to do anything */
    3559              : 
    3560            0 :         _doSetSessionAuth(AH, user);
    3561              : 
    3562              :         /*
    3563              :          * NOTE: currUser keeps track of what the imaginary session user in our
    3564              :          * script is
    3565              :          */
    3566            0 :         free(AH->currUser);
    3567            0 :         AH->currUser = pg_strdup(user);
    3568            0 : }
    3569              : 
    3570              : /*
    3571              :  * Become the owner of the given TOC entry object.  If
    3572              :  * changes in ownership are not allowed, this doesn't do anything.
    3573              :  */
    3574              : static void
    3575            0 : _becomeOwner(ArchiveHandle *AH, TocEntry *te)
    3576              : {
    3577            0 :         RestoreOptions *ropt = AH->public.ropt;
    3578              : 
    3579            0 :         if (ropt && (ropt->noOwner || !ropt->use_setsessauth))
    3580            0 :                 return;
    3581              : 
    3582            0 :         _becomeUser(AH, te->owner);
    3583            0 : }
    3584              : 
    3585              : 
    3586              : /*
    3587              :  * Issue the commands to select the specified schema as the current schema
    3588              :  * in the target database.
    3589              :  */
    3590              : static void
    3591            0 : _selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
    3592              : {
    3593            0 :         PQExpBuffer qry;
    3594              : 
    3595              :         /*
    3596              :          * If there was a SEARCHPATH TOC entry, we're supposed to just stay with
    3597              :          * that search_path rather than switching to entry-specific paths.
    3598              :          * Otherwise, it's an old archive that will not restore correctly unless
    3599              :          * we set the search_path as it's expecting.
    3600              :          */
    3601            0 :         if (AH->public.searchpath)
    3602            0 :                 return;
    3603              : 
    3604            0 :         if (!schemaName || *schemaName == '\0' ||
    3605            0 :                 (AH->currSchema && strcmp(AH->currSchema, schemaName) == 0))
    3606            0 :                 return;                                 /* no need to do anything */
    3607              : 
    3608            0 :         qry = createPQExpBuffer();
    3609              : 
    3610            0 :         appendPQExpBuffer(qry, "SET search_path = %s",
    3611            0 :                                           fmtId(schemaName));
    3612            0 :         if (strcmp(schemaName, "pg_catalog") != 0)
    3613            0 :                 appendPQExpBufferStr(qry, ", pg_catalog");
    3614              : 
    3615            0 :         if (RestoringToDB(AH))
    3616              :         {
    3617            0 :                 PGresult   *res;
    3618              : 
    3619            0 :                 res = PQexec(AH->connection, qry->data);
    3620              : 
    3621            0 :                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    3622            0 :                         warn_or_exit_horribly(AH,
    3623              :                                                                   "could not set \"search_path\" to \"%s\": %s",
    3624            0 :                                                                   schemaName, PQerrorMessage(AH->connection));
    3625              : 
    3626            0 :                 PQclear(res);
    3627            0 :         }
    3628              :         else
    3629            0 :                 ahprintf(AH, "%s;\n\n", qry->data);
    3630              : 
    3631            0 :         free(AH->currSchema);
    3632            0 :         AH->currSchema = pg_strdup(schemaName);
    3633              : 
    3634            0 :         destroyPQExpBuffer(qry);
    3635            0 : }
    3636              : 
    3637              : /*
    3638              :  * Issue the commands to select the specified tablespace as the current one
    3639              :  * in the target database.
    3640              :  */
    3641              : static void
    3642            0 : _selectTablespace(ArchiveHandle *AH, const char *tablespace)
    3643              : {
    3644            0 :         RestoreOptions *ropt = AH->public.ropt;
    3645            0 :         PQExpBuffer qry;
    3646            0 :         const char *want,
    3647              :                            *have;
    3648              : 
    3649              :         /* do nothing in --no-tablespaces mode */
    3650            0 :         if (ropt->noTablespace)
    3651            0 :                 return;
    3652              : 
    3653            0 :         have = AH->currTablespace;
    3654            0 :         want = tablespace;
    3655              : 
    3656              :         /* no need to do anything for non-tablespace object */
    3657            0 :         if (!want)
    3658            0 :                 return;
    3659              : 
    3660            0 :         if (have && strcmp(want, have) == 0)
    3661            0 :                 return;                                 /* no need to do anything */
    3662              : 
    3663            0 :         qry = createPQExpBuffer();
    3664              : 
    3665            0 :         if (strcmp(want, "") == 0)
    3666              :         {
    3667              :                 /* We want the tablespace to be the database's default */
    3668            0 :                 appendPQExpBufferStr(qry, "SET default_tablespace = ''");
    3669            0 :         }
    3670              :         else
    3671              :         {
    3672              :                 /* We want an explicit tablespace */
    3673            0 :                 appendPQExpBuffer(qry, "SET default_tablespace = %s", fmtId(want));
    3674              :         }
    3675              : 
    3676            0 :         if (RestoringToDB(AH))
    3677              :         {
    3678            0 :                 PGresult   *res;
    3679              : 
    3680            0 :                 res = PQexec(AH->connection, qry->data);
    3681              : 
    3682            0 :                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    3683            0 :                         warn_or_exit_horribly(AH,
    3684              :                                                                   "could not set \"default_tablespace\" to %s: %s",
    3685            0 :                                                                   fmtId(want), PQerrorMessage(AH->connection));
    3686              : 
    3687            0 :                 PQclear(res);
    3688            0 :         }
    3689              :         else
    3690            0 :                 ahprintf(AH, "%s;\n\n", qry->data);
    3691              : 
    3692            0 :         free(AH->currTablespace);
    3693            0 :         AH->currTablespace = pg_strdup(want);
    3694              : 
    3695            0 :         destroyPQExpBuffer(qry);
    3696            0 : }
    3697              : 
    3698              : /*
    3699              :  * Set the proper default_table_access_method value for the table.
    3700              :  */
    3701              : static void
    3702            0 : _selectTableAccessMethod(ArchiveHandle *AH, const char *tableam)
    3703              : {
    3704            0 :         RestoreOptions *ropt = AH->public.ropt;
    3705            0 :         PQExpBuffer cmd;
    3706            0 :         const char *want,
    3707              :                            *have;
    3708              : 
    3709              :         /* do nothing in --no-table-access-method mode */
    3710            0 :         if (ropt->noTableAm)
    3711            0 :                 return;
    3712              : 
    3713            0 :         have = AH->currTableAm;
    3714            0 :         want = tableam;
    3715              : 
    3716            0 :         if (!want)
    3717            0 :                 return;
    3718              : 
    3719            0 :         if (have && strcmp(want, have) == 0)
    3720            0 :                 return;
    3721              : 
    3722            0 :         cmd = createPQExpBuffer();
    3723            0 :         appendPQExpBuffer(cmd, "SET default_table_access_method = %s;", fmtId(want));
    3724              : 
    3725            0 :         if (RestoringToDB(AH))
    3726              :         {
    3727            0 :                 PGresult   *res;
    3728              : 
    3729            0 :                 res = PQexec(AH->connection, cmd->data);
    3730              : 
    3731            0 :                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    3732            0 :                         warn_or_exit_horribly(AH,
    3733              :                                                                   "could not set \"default_table_access_method\": %s",
    3734            0 :                                                                   PQerrorMessage(AH->connection));
    3735              : 
    3736            0 :                 PQclear(res);
    3737            0 :         }
    3738              :         else
    3739            0 :                 ahprintf(AH, "%s\n\n", cmd->data);
    3740              : 
    3741            0 :         destroyPQExpBuffer(cmd);
    3742              : 
    3743            0 :         free(AH->currTableAm);
    3744            0 :         AH->currTableAm = pg_strdup(want);
    3745            0 : }
    3746              : 
    3747              : /*
    3748              :  * Set the proper default table access method for a table without storage.
    3749              :  * Currently, this is required only for partitioned tables with a table AM.
    3750              :  */
    3751              : static void
    3752            0 : _printTableAccessMethodNoStorage(ArchiveHandle *AH, TocEntry *te)
    3753              : {
    3754            0 :         RestoreOptions *ropt = AH->public.ropt;
    3755            0 :         const char *tableam = te->tableam;
    3756            0 :         PQExpBuffer cmd;
    3757              : 
    3758              :         /* do nothing in --no-table-access-method mode */
    3759            0 :         if (ropt->noTableAm)
    3760            0 :                 return;
    3761              : 
    3762            0 :         if (!tableam)
    3763            0 :                 return;
    3764              : 
    3765            0 :         Assert(te->relkind == RELKIND_PARTITIONED_TABLE);
    3766              : 
    3767            0 :         cmd = createPQExpBuffer();
    3768              : 
    3769            0 :         appendPQExpBufferStr(cmd, "ALTER TABLE ");
    3770            0 :         appendPQExpBuffer(cmd, "%s ", fmtQualifiedId(te->namespace, te->tag));
    3771            0 :         appendPQExpBuffer(cmd, "SET ACCESS METHOD %s;",
    3772            0 :                                           fmtId(tableam));
    3773              : 
    3774            0 :         if (RestoringToDB(AH))
    3775              :         {
    3776            0 :                 PGresult   *res;
    3777              : 
    3778            0 :                 res = PQexec(AH->connection, cmd->data);
    3779              : 
    3780            0 :                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
    3781            0 :                         warn_or_exit_horribly(AH,
    3782              :                                                                   "could not alter table access method: %s",
    3783            0 :                                                                   PQerrorMessage(AH->connection));
    3784            0 :                 PQclear(res);
    3785            0 :         }
    3786              :         else
    3787            0 :                 ahprintf(AH, "%s\n\n", cmd->data);
    3788              : 
    3789            0 :         destroyPQExpBuffer(cmd);
    3790            0 : }
    3791              : 
    3792              : /*
    3793              :  * Extract an object description for a TOC entry, and append it to buf.
    3794              :  *
    3795              :  * This is used for ALTER ... OWNER TO.
    3796              :  *
    3797              :  * If the object type has no owner, do nothing.
    3798              :  */
    3799              : static void
    3800            0 : _getObjectDescription(PQExpBuffer buf, const TocEntry *te)
    3801              : {
    3802            0 :         const char *type = te->desc;
    3803              : 
    3804              :         /* objects that don't require special decoration */
    3805            0 :         if (strcmp(type, "COLLATION") == 0 ||
    3806            0 :                 strcmp(type, "CONVERSION") == 0 ||
    3807            0 :                 strcmp(type, "DOMAIN") == 0 ||
    3808            0 :                 strcmp(type, "FOREIGN TABLE") == 0 ||
    3809            0 :                 strcmp(type, "MATERIALIZED VIEW") == 0 ||
    3810            0 :                 strcmp(type, "SEQUENCE") == 0 ||
    3811            0 :                 strcmp(type, "STATISTICS") == 0 ||
    3812            0 :                 strcmp(type, "TABLE") == 0 ||
    3813            0 :                 strcmp(type, "TEXT SEARCH DICTIONARY") == 0 ||
    3814            0 :                 strcmp(type, "TEXT SEARCH CONFIGURATION") == 0 ||
    3815            0 :                 strcmp(type, "TYPE") == 0 ||
    3816            0 :                 strcmp(type, "VIEW") == 0 ||
    3817              :         /* non-schema-specified objects */
    3818            0 :                 strcmp(type, "DATABASE") == 0 ||
    3819            0 :                 strcmp(type, "PROCEDURAL LANGUAGE") == 0 ||
    3820            0 :                 strcmp(type, "SCHEMA") == 0 ||
    3821            0 :                 strcmp(type, "EVENT TRIGGER") == 0 ||
    3822            0 :                 strcmp(type, "FOREIGN DATA WRAPPER") == 0 ||
    3823            0 :                 strcmp(type, "SERVER") == 0 ||
    3824            0 :                 strcmp(type, "PUBLICATION") == 0 ||
    3825            0 :                 strcmp(type, "SUBSCRIPTION") == 0)
    3826              :         {
    3827            0 :                 appendPQExpBuffer(buf, "%s ", type);
    3828            0 :                 if (te->namespace && *te->namespace)
    3829            0 :                         appendPQExpBuffer(buf, "%s.", fmtId(te->namespace));
    3830            0 :                 appendPQExpBufferStr(buf, fmtId(te->tag));
    3831            0 :         }
    3832              :         /* LOs just have a name, but it's numeric so must not use fmtId */
    3833            0 :         else if (strcmp(type, "BLOB") == 0)
    3834              :         {
    3835            0 :                 appendPQExpBuffer(buf, "LARGE OBJECT %s", te->tag);
    3836            0 :         }
    3837              : 
    3838              :         /*
    3839              :          * These object types require additional decoration.  Fortunately, the
    3840              :          * information needed is exactly what's in the DROP command.
    3841              :          */
    3842            0 :         else if (strcmp(type, "AGGREGATE") == 0 ||
    3843            0 :                          strcmp(type, "FUNCTION") == 0 ||
    3844            0 :                          strcmp(type, "OPERATOR") == 0 ||
    3845            0 :                          strcmp(type, "OPERATOR CLASS") == 0 ||
    3846            0 :                          strcmp(type, "OPERATOR FAMILY") == 0 ||
    3847            0 :                          strcmp(type, "PROCEDURE") == 0)
    3848              :         {
    3849              :                 /* Chop "DROP " off the front and make a modifiable copy */
    3850            0 :                 char       *first = pg_strdup(te->dropStmt + 5);
    3851            0 :                 char       *last;
    3852              : 
    3853              :                 /* point to last character in string */
    3854            0 :                 last = first + strlen(first) - 1;
    3855              : 
    3856              :                 /* Strip off any ';' or '\n' at the end */
    3857            0 :                 while (last >= first && (*last == '\n' || *last == ';'))
    3858            0 :                         last--;
    3859            0 :                 *(last + 1) = '\0';
    3860              : 
    3861            0 :                 appendPQExpBufferStr(buf, first);
    3862              : 
    3863            0 :                 free(first);
    3864              :                 return;
    3865            0 :         }
    3866              :         /* these object types don't have separate owners */
    3867            0 :         else if (strcmp(type, "CAST") == 0 ||
    3868            0 :                          strcmp(type, "CHECK CONSTRAINT") == 0 ||
    3869            0 :                          strcmp(type, "CONSTRAINT") == 0 ||
    3870            0 :                          strcmp(type, "DATABASE PROPERTIES") == 0 ||
    3871            0 :                          strcmp(type, "DEFAULT") == 0 ||
    3872            0 :                          strcmp(type, "FK CONSTRAINT") == 0 ||
    3873            0 :                          strcmp(type, "INDEX") == 0 ||
    3874            0 :                          strcmp(type, "RULE") == 0 ||
    3875            0 :                          strcmp(type, "TRIGGER") == 0 ||
    3876            0 :                          strcmp(type, "ROW SECURITY") == 0 ||
    3877            0 :                          strcmp(type, "POLICY") == 0 ||
    3878            0 :                          strcmp(type, "USER MAPPING") == 0)
    3879              :         {
    3880              :                 /* do nothing */
    3881            0 :         }
    3882              :         else
    3883            0 :                 pg_fatal("don't know how to set owner for object type \"%s\"", type);
    3884            0 : }
    3885              : 
    3886              : /*
    3887              :  * Emit the SQL commands to create the object represented by a TOC entry
    3888              :  *
    3889              :  * This now also includes issuing an ALTER OWNER command to restore the
    3890              :  * object's ownership, if wanted.  But note that the object's permissions
    3891              :  * will remain at default, until the matching ACL TOC entry is restored.
    3892              :  */
    3893              : static void
    3894            0 : _printTocEntry(ArchiveHandle *AH, TocEntry *te, const char *pfx)
    3895              : {
    3896            0 :         RestoreOptions *ropt = AH->public.ropt;
    3897              : 
    3898              :         /*
    3899              :          * Select owner, schema, tablespace and default AM as necessary. The
    3900              :          * default access method for partitioned tables is handled after
    3901              :          * generating the object definition, as it requires an ALTER command
    3902              :          * rather than SET.
    3903              :          */
    3904            0 :         _becomeOwner(AH, te);
    3905            0 :         _selectOutputSchema(AH, te->namespace);
    3906            0 :         _selectTablespace(AH, te->tablespace);
    3907            0 :         if (te->relkind != RELKIND_PARTITIONED_TABLE)
    3908            0 :                 _selectTableAccessMethod(AH, te->tableam);
    3909              : 
    3910              :         /* Emit header comment for item */
    3911            0 :         if (!AH->noTocComments)
    3912              :         {
    3913            0 :                 char       *sanitized_name;
    3914            0 :                 char       *sanitized_schema;
    3915            0 :                 char       *sanitized_owner;
    3916              : 
    3917            0 :                 ahprintf(AH, "--\n");
    3918            0 :                 if (AH->public.verbose)
    3919              :                 {
    3920            0 :                         ahprintf(AH, "-- TOC entry %d (class %u OID %u)\n",
    3921            0 :                                          te->dumpId, te->catalogId.tableoid, te->catalogId.oid);
    3922            0 :                         if (te->nDeps > 0)
    3923              :                         {
    3924            0 :                                 int                     i;
    3925              : 
    3926            0 :                                 ahprintf(AH, "-- Dependencies:");
    3927            0 :                                 for (i = 0; i < te->nDeps; i++)
    3928            0 :                                         ahprintf(AH, " %d", te->dependencies[i]);
    3929            0 :                                 ahprintf(AH, "\n");
    3930            0 :                         }
    3931            0 :                 }
    3932              : 
    3933            0 :                 sanitized_name = sanitize_line(te->tag, false);
    3934            0 :                 sanitized_schema = sanitize_line(te->namespace, true);
    3935            0 :                 sanitized_owner = sanitize_line(ropt->noOwner ? NULL : te->owner, true);
    3936              : 
    3937            0 :                 ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s",
    3938            0 :                                  pfx, sanitized_name, te->desc, sanitized_schema,
    3939            0 :                                  sanitized_owner);
    3940              : 
    3941            0 :                 free(sanitized_name);
    3942            0 :                 free(sanitized_schema);
    3943            0 :                 free(sanitized_owner);
    3944              : 
    3945            0 :                 if (te->tablespace && strlen(te->tablespace) > 0 && !ropt->noTablespace)
    3946              :                 {
    3947            0 :                         char       *sanitized_tablespace;
    3948              : 
    3949            0 :                         sanitized_tablespace = sanitize_line(te->tablespace, false);
    3950            0 :                         ahprintf(AH, "; Tablespace: %s", sanitized_tablespace);
    3951            0 :                         free(sanitized_tablespace);
    3952            0 :                 }
    3953            0 :                 ahprintf(AH, "\n");
    3954              : 
    3955            0 :                 if (AH->PrintExtraTocPtr != NULL)
    3956            0 :                         AH->PrintExtraTocPtr(AH, te);
    3957            0 :                 ahprintf(AH, "--\n\n");
    3958            0 :         }
    3959              : 
    3960              :         /*
    3961              :          * Actually print the definition.  Normally we can just print the defn
    3962              :          * string if any, but we have four special cases:
    3963              :          *
    3964              :          * 1. A crude hack for suppressing AUTHORIZATION clause that old pg_dump
    3965              :          * versions put into CREATE SCHEMA.  Don't mutate the variant for schema
    3966              :          * "public" that is a comment.  We have to do this when --no-owner mode is
    3967              :          * selected.  This is ugly, but I see no other good way ...
    3968              :          *
    3969              :          * 2. BLOB METADATA entries need special processing since their defn
    3970              :          * strings are just lists of OIDs, not complete SQL commands.
    3971              :          *
    3972              :          * 3. ACL LARGE OBJECTS entries need special processing because they
    3973              :          * contain only one copy of the ACL GRANT/REVOKE commands, which we must
    3974              :          * apply to each large object listed in the associated BLOB METADATA.
    3975              :          *
    3976              :          * 4. Entries with a defnDumper need to call it to generate the
    3977              :          * definition.  This is primarily intended to provide a way to save memory
    3978              :          * for objects that would otherwise need a lot of it (e.g., statistics
    3979              :          * data).
    3980              :          */
    3981            0 :         if (ropt->noOwner &&
    3982            0 :                 strcmp(te->desc, "SCHEMA") == 0 && strncmp(te->defn, "--", 2) != 0)
    3983              :         {
    3984            0 :                 ahprintf(AH, "CREATE SCHEMA %s;\n\n\n", fmtId(te->tag));
    3985            0 :         }
    3986            0 :         else if (strcmp(te->desc, "BLOB METADATA") == 0)
    3987              :         {
    3988            0 :                 IssueCommandPerBlob(AH, te, "SELECT pg_catalog.lo_create('", "')");
    3989            0 :         }
    3990            0 :         else if (strcmp(te->desc, "ACL") == 0 &&
    3991            0 :                          strncmp(te->tag, "LARGE OBJECTS", 13) == 0)
    3992              :         {
    3993            0 :                 IssueACLPerBlob(AH, te);
    3994            0 :         }
    3995            0 :         else if (te->defnLen && AH->format != archTar)
    3996              :         {
    3997              :                 /*
    3998              :                  * If defnLen is set, the defnDumper has already been called for this
    3999              :                  * TOC entry.  We don't normally expect a defnDumper to be called for
    4000              :                  * a TOC entry a second time in _printTocEntry(), but there's an
    4001              :                  * exception.  The tar format first calls WriteToc(), which scans the
    4002              :                  * entire TOC, and then it later calls RestoreArchive() to generate
    4003              :                  * restore.sql, which scans the TOC again.  There doesn't appear to be
    4004              :                  * a good way to prevent a second defnDumper call in this case without
    4005              :                  * storing the definition in memory, which defeats the purpose.  This
    4006              :                  * second defnDumper invocation should generate the same output as the
    4007              :                  * first, but even if it doesn't, the worst-case scenario is that
    4008              :                  * restore.sql might have different statistics data than the archive.
    4009              :                  *
    4010              :                  * In all other cases, encountering a TOC entry a second time in
    4011              :                  * _printTocEntry() is unexpected, so we fail because one of our
    4012              :                  * assumptions must no longer hold true.
    4013              :                  *
    4014              :                  * XXX This is a layering violation, but the alternative is an awkward
    4015              :                  * and complicated callback infrastructure for this special case. This
    4016              :                  * might be worth revisiting in the future.
    4017              :                  */
    4018            0 :                 pg_fatal("unexpected TOC entry in _printTocEntry(): %d %s %s",
    4019              :                                  te->dumpId, te->desc, te->tag);
    4020            0 :         }
    4021            0 :         else if (te->defnDumper)
    4022              :         {
    4023            0 :                 char       *defn = te->defnDumper((Archive *) AH, te->defnDumperArg, te);
    4024              : 
    4025            0 :                 te->defnLen = ahprintf(AH, "%s\n\n", defn);
    4026            0 :                 pg_free(defn);
    4027            0 :         }
    4028            0 :         else if (te->defn && strlen(te->defn) > 0)
    4029              :         {
    4030            0 :                 ahprintf(AH, "%s\n\n", te->defn);
    4031              : 
    4032              :                 /*
    4033              :                  * If the defn string contains multiple SQL commands, txn_size mode
    4034              :                  * should count it as N actions not one.  But rather than build a full
    4035              :                  * SQL parser, approximate this by counting semicolons.  One case
    4036              :                  * where that tends to be badly fooled is function definitions, so
    4037              :                  * ignore them.  (restore_toc_entry will count one action anyway.)
    4038              :                  */
    4039            0 :                 if (ropt->txn_size > 0 &&
    4040            0 :                         strcmp(te->desc, "FUNCTION") != 0 &&
    4041            0 :                         strcmp(te->desc, "PROCEDURE") != 0)
    4042              :                 {
    4043            0 :                         const char *p = te->defn;
    4044            0 :                         int                     nsemis = 0;
    4045              : 
    4046            0 :                         while ((p = strchr(p, ';')) != NULL)
    4047              :                         {
    4048            0 :                                 nsemis++;
    4049            0 :                                 p++;
    4050              :                         }
    4051            0 :                         if (nsemis > 1)
    4052            0 :                                 AH->txnCount += nsemis - 1;
    4053            0 :                 }
    4054            0 :         }
    4055              : 
    4056              :         /*
    4057              :          * If we aren't using SET SESSION AUTH to determine ownership, we must
    4058              :          * instead issue an ALTER OWNER command.  Schema "public" is special; when
    4059              :          * a dump emits a comment in lieu of creating it, we use ALTER OWNER even
    4060              :          * when using SET SESSION for all other objects.  We assume that anything
    4061              :          * without a DROP command is not a separately ownable object.
    4062              :          */
    4063            0 :         if (!ropt->noOwner &&
    4064            0 :                 (!ropt->use_setsessauth ||
    4065            0 :                  (strcmp(te->desc, "SCHEMA") == 0 &&
    4066            0 :                   strncmp(te->defn, "--", 2) == 0)) &&
    4067            0 :                 te->owner && strlen(te->owner) > 0 &&
    4068            0 :                 te->dropStmt && strlen(te->dropStmt) > 0)
    4069              :         {
    4070            0 :                 if (strcmp(te->desc, "BLOB METADATA") == 0)
    4071              :                 {
    4072              :                         /* BLOB METADATA needs special code to handle multiple LOs */
    4073            0 :                         char       *cmdEnd = psprintf(" OWNER TO %s", fmtId(te->owner));
    4074              : 
    4075            0 :                         IssueCommandPerBlob(AH, te, "ALTER LARGE OBJECT ", cmdEnd);
    4076            0 :                         pg_free(cmdEnd);
    4077            0 :                 }
    4078              :                 else
    4079              :                 {
    4080              :                         /* For all other cases, we can use _getObjectDescription */
    4081            0 :                         PQExpBufferData temp;
    4082              : 
    4083            0 :                         initPQExpBuffer(&temp);
    4084            0 :                         _getObjectDescription(&temp, te);
    4085              : 
    4086              :                         /*
    4087              :                          * If _getObjectDescription() didn't fill the buffer, then there
    4088              :                          * is no owner.
    4089              :                          */
    4090            0 :                         if (temp.data[0])
    4091            0 :                                 ahprintf(AH, "ALTER %s OWNER TO %s;\n\n",
    4092            0 :                                                  temp.data, fmtId(te->owner));
    4093            0 :                         termPQExpBuffer(&temp);
    4094            0 :                 }
    4095            0 :         }
    4096              : 
    4097              :         /*
    4098              :          * Select a partitioned table's default AM, once the table definition has
    4099              :          * been generated.
    4100              :          */
    4101            0 :         if (te->relkind == RELKIND_PARTITIONED_TABLE)
    4102            0 :                 _printTableAccessMethodNoStorage(AH, te);
    4103              : 
    4104              :         /*
    4105              :          * If it's an ACL entry, it might contain SET SESSION AUTHORIZATION
    4106              :          * commands, so we can no longer assume we know the current auth setting.
    4107              :          */
    4108            0 :         if (_tocEntryIsACL(te))
    4109              :         {
    4110            0 :                 free(AH->currUser);
    4111            0 :                 AH->currUser = NULL;
    4112            0 :         }
    4113            0 : }
    4114              : 
    4115              : /*
    4116              :  * Write the file header for a custom-format archive
    4117              :  */
    4118              : void
    4119            0 : WriteHead(ArchiveHandle *AH)
    4120              : {
    4121            0 :         struct tm       crtm;
    4122              : 
    4123            0 :         AH->WriteBufPtr(AH, "PGDMP", 5);   /* Magic code */
    4124            0 :         AH->WriteBytePtr(AH, ARCHIVE_MAJOR(AH->version));
    4125            0 :         AH->WriteBytePtr(AH, ARCHIVE_MINOR(AH->version));
    4126            0 :         AH->WriteBytePtr(AH, ARCHIVE_REV(AH->version));
    4127            0 :         AH->WriteBytePtr(AH, AH->intSize);
    4128            0 :         AH->WriteBytePtr(AH, AH->offSize);
    4129            0 :         AH->WriteBytePtr(AH, AH->format);
    4130            0 :         AH->WriteBytePtr(AH, AH->compression_spec.algorithm);
    4131            0 :         crtm = *localtime(&AH->createDate);
    4132            0 :         WriteInt(AH, crtm.tm_sec);
    4133            0 :         WriteInt(AH, crtm.tm_min);
    4134            0 :         WriteInt(AH, crtm.tm_hour);
    4135            0 :         WriteInt(AH, crtm.tm_mday);
    4136            0 :         WriteInt(AH, crtm.tm_mon);
    4137            0 :         WriteInt(AH, crtm.tm_year);
    4138            0 :         WriteInt(AH, crtm.tm_isdst);
    4139            0 :         WriteStr(AH, PQdb(AH->connection));
    4140            0 :         WriteStr(AH, AH->public.remoteVersionStr);
    4141            0 :         WriteStr(AH, PG_VERSION);
    4142            0 : }
    4143              : 
    4144              : void
    4145            0 : ReadHead(ArchiveHandle *AH)
    4146              : {
    4147            0 :         char       *errmsg;
    4148            0 :         char            vmaj,
    4149              :                                 vmin,
    4150              :                                 vrev;
    4151            0 :         int                     fmt;
    4152              : 
    4153              :         /*
    4154              :          * If we haven't already read the header, do so.
    4155              :          *
    4156              :          * NB: this code must agree with _discoverArchiveFormat().  Maybe find a
    4157              :          * way to unify the cases?
    4158              :          */
    4159            0 :         if (!AH->readHeader)
    4160              :         {
    4161            0 :                 char            tmpMag[7];
    4162              : 
    4163            0 :                 AH->ReadBufPtr(AH, tmpMag, 5);
    4164              : 
    4165            0 :                 if (strncmp(tmpMag, "PGDMP", 5) != 0)
    4166            0 :                         pg_fatal("did not find magic string in file header");
    4167            0 :         }
    4168              : 
    4169            0 :         vmaj = AH->ReadBytePtr(AH);
    4170            0 :         vmin = AH->ReadBytePtr(AH);
    4171              : 
    4172            0 :         if (vmaj > 1 || (vmaj == 1 && vmin > 0))  /* Version > 1.0 */
    4173            0 :                 vrev = AH->ReadBytePtr(AH);
    4174              :         else
    4175            0 :                 vrev = 0;
    4176              : 
    4177            0 :         AH->version = MAKE_ARCHIVE_VERSION(vmaj, vmin, vrev);
    4178              : 
    4179            0 :         if (AH->version < K_VERS_1_0 || AH->version > K_VERS_MAX)
    4180            0 :                 pg_fatal("unsupported version (%d.%d) in file header",
    4181              :                                  vmaj, vmin);
    4182              : 
    4183            0 :         AH->intSize = AH->ReadBytePtr(AH);
    4184            0 :         if (AH->intSize > 32)
    4185            0 :                 pg_fatal("sanity check on integer size (%zu) failed", AH->intSize);
    4186              : 
    4187            0 :         if (AH->intSize > sizeof(int))
    4188            0 :                 pg_log_warning("archive was made on a machine with larger integers, some operations might fail");
    4189              : 
    4190            0 :         if (AH->version >= K_VERS_1_7)
    4191            0 :                 AH->offSize = AH->ReadBytePtr(AH);
    4192              :         else
    4193            0 :                 AH->offSize = AH->intSize;
    4194              : 
    4195            0 :         fmt = AH->ReadBytePtr(AH);
    4196              : 
    4197            0 :         if (AH->format != fmt)
    4198            0 :                 pg_fatal("expected format (%d) differs from format found in file (%d)",
    4199              :                                  AH->format, fmt);
    4200              : 
    4201            0 :         if (AH->version >= K_VERS_1_15)
    4202            0 :                 AH->compression_spec.algorithm = AH->ReadBytePtr(AH);
    4203            0 :         else if (AH->version >= K_VERS_1_2)
    4204              :         {
    4205              :                 /* Guess the compression method based on the level */
    4206            0 :                 if (AH->version < K_VERS_1_4)
    4207            0 :                         AH->compression_spec.level = AH->ReadBytePtr(AH);
    4208              :                 else
    4209            0 :                         AH->compression_spec.level = ReadInt(AH);
    4210              : 
    4211            0 :                 if (AH->compression_spec.level != 0)
    4212            0 :                         AH->compression_spec.algorithm = PG_COMPRESSION_GZIP;
    4213            0 :         }
    4214              :         else
    4215            0 :                 AH->compression_spec.algorithm = PG_COMPRESSION_GZIP;
    4216              : 
    4217            0 :         errmsg = supports_compression(AH->compression_spec);
    4218            0 :         if (errmsg)
    4219              :         {
    4220            0 :                 pg_log_warning("archive is compressed, but this installation does not support compression (%s) -- no data will be available",
    4221              :                                            errmsg);
    4222            0 :                 pg_free(errmsg);
    4223            0 :         }
    4224              : 
    4225            0 :         if (AH->version >= K_VERS_1_4)
    4226              :         {
    4227            0 :                 struct tm       crtm;
    4228              : 
    4229            0 :                 crtm.tm_sec = ReadInt(AH);
    4230            0 :                 crtm.tm_min = ReadInt(AH);
    4231            0 :                 crtm.tm_hour = ReadInt(AH);
    4232            0 :                 crtm.tm_mday = ReadInt(AH);
    4233            0 :                 crtm.tm_mon = ReadInt(AH);
    4234            0 :                 crtm.tm_year = ReadInt(AH);
    4235            0 :                 crtm.tm_isdst = ReadInt(AH);
    4236              : 
    4237              :                 /*
    4238              :                  * Newer versions of glibc have mktime() report failure if tm_isdst is
    4239              :                  * inconsistent with the prevailing timezone, e.g. tm_isdst = 1 when
    4240              :                  * TZ=UTC.  This is problematic when restoring an archive under a
    4241              :                  * different timezone setting.  If we get a failure, try again with
    4242              :                  * tm_isdst set to -1 ("don't know").
    4243              :                  *
    4244              :                  * XXX with or without this hack, we reconstruct createDate
    4245              :                  * incorrectly when the prevailing timezone is different from
    4246              :                  * pg_dump's.  Next time we bump the archive version, we should flush
    4247              :                  * this representation and store a plain seconds-since-the-Epoch
    4248              :                  * timestamp instead.
    4249              :                  */
    4250            0 :                 AH->createDate = mktime(&crtm);
    4251            0 :                 if (AH->createDate == (time_t) -1)
    4252              :                 {
    4253            0 :                         crtm.tm_isdst = -1;
    4254            0 :                         AH->createDate = mktime(&crtm);
    4255            0 :                         if (AH->createDate == (time_t) -1)
    4256            0 :                                 pg_log_warning("invalid creation date in header");
    4257            0 :                 }
    4258            0 :         }
    4259              : 
    4260            0 :         if (AH->version >= K_VERS_1_4)
    4261              :         {
    4262            0 :                 AH->archdbname = ReadStr(AH);
    4263            0 :         }
    4264              : 
    4265            0 :         if (AH->version >= K_VERS_1_10)
    4266              :         {
    4267            0 :                 AH->archiveRemoteVersion = ReadStr(AH);
    4268            0 :                 AH->archiveDumpVersion = ReadStr(AH);
    4269            0 :         }
    4270            0 : }
    4271              : 
    4272              : 
    4273              : /*
    4274              :  * checkSeek
    4275              :  *        check to see if ftell/fseek can be performed.
    4276              :  */
    4277              : bool
    4278            0 : checkSeek(FILE *fp)
    4279              : {
    4280            0 :         pgoff_t         tpos;
    4281              : 
    4282              :         /* Check that ftello works on this file */
    4283            0 :         tpos = ftello(fp);
    4284            0 :         if (tpos < 0)
    4285            0 :                 return false;
    4286              : 
    4287              :         /*
    4288              :          * Check that fseeko(SEEK_SET) works, too.  NB: we used to try to test
    4289              :          * this with fseeko(fp, 0, SEEK_CUR).  But some platforms treat that as a
    4290              :          * successful no-op even on files that are otherwise unseekable.
    4291              :          */
    4292            0 :         if (fseeko(fp, tpos, SEEK_SET) != 0)
    4293            0 :                 return false;
    4294              : 
    4295            0 :         return true;
    4296            0 : }
    4297              : 
    4298              : 
    4299              : /*
    4300              :  * dumpTimestamp
    4301              :  */
    4302              : static void
    4303            0 : dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim)
    4304              : {
    4305            0 :         char            buf[64];
    4306              : 
    4307            0 :         if (strftime(buf, sizeof(buf), PGDUMP_STRFTIME_FMT, localtime(&tim)) != 0)
    4308            0 :                 ahprintf(AH, "-- %s %s\n\n", msg, buf);
    4309            0 : }
    4310              : 
    4311              : /*
    4312              :  * Main engine for parallel restore.
    4313              :  *
    4314              :  * Parallel restore is done in three phases.  In this first phase,
    4315              :  * we'll process all SECTION_PRE_DATA TOC entries that are allowed to be
    4316              :  * processed in the RESTORE_PASS_MAIN pass.  (In practice, that's all
    4317              :  * PRE_DATA items other than ACLs.)  Entries we can't process now are
    4318              :  * added to the pending_list for later phases to deal with.
    4319              :  */
    4320              : static void
    4321            0 : restore_toc_entries_prefork(ArchiveHandle *AH, TocEntry *pending_list)
    4322              : {
    4323            0 :         bool            skipped_some;
    4324            0 :         TocEntry   *next_work_item;
    4325              : 
    4326            0 :         pg_log_debug("entering restore_toc_entries_prefork");
    4327              : 
    4328              :         /* Adjust dependency information */
    4329            0 :         fix_dependencies(AH);
    4330              : 
    4331              :         /*
    4332              :          * Do all the early stuff in a single connection in the parent. There's no
    4333              :          * great point in running it in parallel, in fact it will actually run
    4334              :          * faster in a single connection because we avoid all the connection and
    4335              :          * setup overhead.  Also, pre-9.2 pg_dump versions were not very good
    4336              :          * about showing all the dependencies of SECTION_PRE_DATA items, so we do
    4337              :          * not risk trying to process them out-of-order.
    4338              :          *
    4339              :          * Stuff that we can't do immediately gets added to the pending_list.
    4340              :          * Note: we don't yet filter out entries that aren't going to be restored.
    4341              :          * They might participate in dependency chains connecting entries that
    4342              :          * should be restored, so we treat them as live until we actually process
    4343              :          * them.
    4344              :          *
    4345              :          * Note: as of 9.2, it should be guaranteed that all PRE_DATA items appear
    4346              :          * before DATA items, and all DATA items before POST_DATA items.  That is
    4347              :          * not certain to be true in older archives, though, and in any case use
    4348              :          * of a list file would destroy that ordering (cf. SortTocFromFile).  So
    4349              :          * this loop cannot assume that it holds.
    4350              :          */
    4351            0 :         AH->restorePass = RESTORE_PASS_MAIN;
    4352            0 :         skipped_some = false;
    4353            0 :         for (next_work_item = AH->toc->next; next_work_item != AH->toc; next_work_item = next_work_item->next)
    4354              :         {
    4355            0 :                 bool            do_now = true;
    4356              : 
    4357            0 :                 if (next_work_item->section != SECTION_PRE_DATA)
    4358              :                 {
    4359              :                         /* DATA and POST_DATA items are just ignored for now */
    4360            0 :                         if (next_work_item->section == SECTION_DATA ||
    4361            0 :                                 next_work_item->section == SECTION_POST_DATA)
    4362              :                         {
    4363            0 :                                 do_now = false;
    4364            0 :                                 skipped_some = true;
    4365            0 :                         }
    4366              :                         else
    4367              :                         {
    4368              :                                 /*
    4369              :                                  * SECTION_NONE items, such as comments, can be processed now
    4370              :                                  * if we are still in the PRE_DATA part of the archive.  Once
    4371              :                                  * we've skipped any items, we have to consider whether the
    4372              :                                  * comment's dependencies are satisfied, so skip it for now.
    4373              :                                  */
    4374            0 :                                 if (skipped_some)
    4375            0 :                                         do_now = false;
    4376              :                         }
    4377            0 :                 }
    4378              : 
    4379              :                 /*
    4380              :                  * Also skip items that need to be forced into later passes.  We need
    4381              :                  * not set skipped_some in this case, since by assumption no main-pass
    4382              :                  * items could depend on these.
    4383              :                  */
    4384            0 :                 if (_tocEntryRestorePass(next_work_item) != RESTORE_PASS_MAIN)
    4385            0 :                         do_now = false;
    4386              : 
    4387            0 :                 if (do_now)
    4388              :                 {
    4389              :                         /* OK, restore the item and update its dependencies */
    4390            0 :                         pg_log_info("processing item %d %s %s",
    4391              :                                                 next_work_item->dumpId,
    4392              :                                                 next_work_item->desc, next_work_item->tag);
    4393              : 
    4394            0 :                         (void) restore_toc_entry(AH, next_work_item, false);
    4395              : 
    4396              :                         /* Reduce dependencies, but don't move anything to ready_heap */
    4397            0 :                         reduce_dependencies(AH, next_work_item, NULL);
    4398            0 :                 }
    4399              :                 else
    4400              :                 {
    4401              :                         /* Nope, so add it to pending_list */
    4402            0 :                         pending_list_append(pending_list, next_work_item);
    4403              :                 }
    4404            0 :         }
    4405              : 
    4406              :         /*
    4407              :          * In --transaction-size mode, we must commit the open transaction before
    4408              :          * dropping the database connection.  This also ensures that child workers
    4409              :          * can see the objects we've created so far.
    4410              :          */
    4411            0 :         if (AH->public.ropt->txn_size > 0)
    4412            0 :                 CommitTransaction(&AH->public);
    4413              : 
    4414              :         /*
    4415              :          * Now close parent connection in prep for parallel steps.  We do this
    4416              :          * mainly to ensure that we don't exceed the specified number of parallel
    4417              :          * connections.
    4418              :          */
    4419            0 :         DisconnectDatabase(&AH->public);
    4420              : 
    4421              :         /* blow away any transient state from the old connection */
    4422            0 :         free(AH->currUser);
    4423            0 :         AH->currUser = NULL;
    4424            0 :         free(AH->currSchema);
    4425            0 :         AH->currSchema = NULL;
    4426            0 :         free(AH->currTablespace);
    4427            0 :         AH->currTablespace = NULL;
    4428            0 :         free(AH->currTableAm);
    4429            0 :         AH->currTableAm = NULL;
    4430            0 : }
    4431              : 
    4432              : /*
    4433              :  * Main engine for parallel restore.
    4434              :  *
    4435              :  * Parallel restore is done in three phases.  In this second phase,
    4436              :  * we process entries by dispatching them to parallel worker children
    4437              :  * (processes on Unix, threads on Windows), each of which connects
    4438              :  * separately to the database.  Inter-entry dependencies are respected,
    4439              :  * and so is the RestorePass multi-pass structure.  When we can no longer
    4440              :  * make any entries ready to process, we exit.  Normally, there will be
    4441              :  * nothing left to do; but if there is, the third phase will mop up.
    4442              :  */
    4443              : static void
    4444            0 : restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
    4445              :                                                          TocEntry *pending_list)
    4446              : {
    4447            0 :         binaryheap *ready_heap;
    4448            0 :         TocEntry   *next_work_item;
    4449              : 
    4450            0 :         pg_log_debug("entering restore_toc_entries_parallel");
    4451              : 
    4452              :         /* Set up ready_heap with enough room for all known TocEntrys */
    4453            0 :         ready_heap = binaryheap_allocate(AH->tocCount,
    4454              :                                                                          TocEntrySizeCompareBinaryheap,
    4455              :                                                                          NULL);
    4456              : 
    4457              :         /*
    4458              :          * The pending_list contains all items that we need to restore.  Move all
    4459              :          * items that are available to process immediately into the ready_heap.
    4460              :          * After this setup, the pending list is everything that needs to be done
    4461              :          * but is blocked by one or more dependencies, while the ready heap
    4462              :          * contains items that have no remaining dependencies and are OK to
    4463              :          * process in the current restore pass.
    4464              :          */
    4465            0 :         AH->restorePass = RESTORE_PASS_MAIN;
    4466            0 :         move_to_ready_heap(pending_list, ready_heap, AH->restorePass);
    4467              : 
    4468              :         /*
    4469              :          * main parent loop
    4470              :          *
    4471              :          * Keep going until there is no worker still running AND there is no work
    4472              :          * left to be done.  Note invariant: at top of loop, there should always
    4473              :          * be at least one worker available to dispatch a job to.
    4474              :          */
    4475            0 :         pg_log_info("entering main parallel loop");
    4476              : 
    4477            0 :         for (;;)
    4478              :         {
    4479              :                 /* Look for an item ready to be dispatched to a worker */
    4480            0 :                 next_work_item = pop_next_work_item(ready_heap, pstate);
    4481            0 :                 if (next_work_item != NULL)
    4482              :                 {
    4483              :                         /* If not to be restored, don't waste time launching a worker */
    4484            0 :                         if ((next_work_item->reqs & (REQ_SCHEMA | REQ_DATA | REQ_STATS)) == 0)
    4485              :                         {
    4486            0 :                                 pg_log_info("skipping item %d %s %s",
    4487              :                                                         next_work_item->dumpId,
    4488              :                                                         next_work_item->desc, next_work_item->tag);
    4489              :                                 /* Update its dependencies as though we'd completed it */
    4490            0 :                                 reduce_dependencies(AH, next_work_item, ready_heap);
    4491              :                                 /* Loop around to see if anything else can be dispatched */
    4492            0 :                                 continue;
    4493              :                         }
    4494              : 
    4495            0 :                         pg_log_info("launching item %d %s %s",
    4496              :                                                 next_work_item->dumpId,
    4497              :                                                 next_work_item->desc, next_work_item->tag);
    4498              : 
    4499              :                         /* Dispatch to some worker */
    4500            0 :                         DispatchJobForTocEntry(AH, pstate, next_work_item, ACT_RESTORE,
    4501            0 :                                                                    mark_restore_job_done, ready_heap);
    4502            0 :                 }
    4503            0 :                 else if (IsEveryWorkerIdle(pstate))
    4504              :                 {
    4505              :                         /*
    4506              :                          * Nothing is ready and no worker is running, so we're done with
    4507              :                          * the current pass or maybe with the whole process.
    4508              :                          */
    4509            0 :                         if (AH->restorePass == RESTORE_PASS_LAST)
    4510            0 :                                 break;                  /* No more parallel processing is possible */
    4511              : 
    4512              :                         /* Advance to next restore pass */
    4513            0 :                         AH->restorePass++;
    4514              :                         /* That probably allows some stuff to be made ready */
    4515            0 :                         move_to_ready_heap(pending_list, ready_heap, AH->restorePass);
    4516              :                         /* Loop around to see if anything's now ready */
    4517            0 :                         continue;
    4518              :                 }
    4519              :                 else
    4520              :                 {
    4521              :                         /*
    4522              :                          * We have nothing ready, but at least one child is working, so
    4523              :                          * wait for some subjob to finish.
    4524              :                          */
    4525              :                 }
    4526              : 
    4527              :                 /*
    4528              :                  * Before dispatching another job, check to see if anything has
    4529              :                  * finished.  We should check every time through the loop so as to
    4530              :                  * reduce dependencies as soon as possible.  If we were unable to
    4531              :                  * dispatch any job this time through, wait until some worker finishes
    4532              :                  * (and, hopefully, unblocks some pending item).  If we did dispatch
    4533              :                  * something, continue as soon as there's at least one idle worker.
    4534              :                  * Note that in either case, there's guaranteed to be at least one
    4535              :                  * idle worker when we return to the top of the loop.  This ensures we
    4536              :                  * won't block inside DispatchJobForTocEntry, which would be
    4537              :                  * undesirable: we'd rather postpone dispatching until we see what's
    4538              :                  * been unblocked by finished jobs.
    4539              :                  */
    4540            0 :                 WaitForWorkers(AH, pstate,
    4541            0 :                                            next_work_item ? WFW_ONE_IDLE : WFW_GOT_STATUS);
    4542              :         }
    4543              : 
    4544              :         /* There should now be nothing in ready_heap. */
    4545            0 :         Assert(binaryheap_empty(ready_heap));
    4546              : 
    4547            0 :         binaryheap_free(ready_heap);
    4548              : 
    4549            0 :         pg_log_info("finished main parallel loop");
    4550            0 : }
    4551              : 
    4552              : /*
    4553              :  * Main engine for parallel restore.
    4554              :  *
    4555              :  * Parallel restore is done in three phases.  In this third phase,
    4556              :  * we mop up any remaining TOC entries by processing them serially.
    4557              :  * This phase normally should have nothing to do, but if we've somehow
    4558              :  * gotten stuck due to circular dependencies or some such, this provides
    4559              :  * at least some chance of completing the restore successfully.
    4560              :  */
    4561              : static void
    4562            0 : restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
    4563              : {
    4564            0 :         RestoreOptions *ropt = AH->public.ropt;
    4565            0 :         TocEntry   *te;
    4566              : 
    4567            0 :         pg_log_debug("entering restore_toc_entries_postfork");
    4568              : 
    4569              :         /*
    4570              :          * Now reconnect the single parent connection.
    4571              :          */
    4572            0 :         ConnectDatabaseAhx((Archive *) AH, &ropt->cparams, true);
    4573              : 
    4574              :         /* re-establish fixed state */
    4575            0 :         _doSetFixedOutputState(AH);
    4576              : 
    4577              :         /*
    4578              :          * Make sure there is no work left due to, say, circular dependencies, or
    4579              :          * some other pathological condition.  If so, do it in the single parent
    4580              :          * connection.  We don't sweat about RestorePass ordering; it's likely we
    4581              :          * already violated that.
    4582              :          */
    4583            0 :         for (te = pending_list->pending_next; te != pending_list; te = te->pending_next)
    4584              :         {
    4585            0 :                 pg_log_info("processing missed item %d %s %s",
    4586              :                                         te->dumpId, te->desc, te->tag);
    4587            0 :                 (void) restore_toc_entry(AH, te, false);
    4588            0 :         }
    4589            0 : }
    4590              : 
    4591              : /*
    4592              :  * Check if te1 has an exclusive lock requirement for an item that te2 also
    4593              :  * requires, whether or not te2's requirement is for an exclusive lock.
    4594              :  */
    4595              : static bool
    4596            0 : has_lock_conflicts(TocEntry *te1, TocEntry *te2)
    4597              : {
    4598            0 :         int                     j,
    4599              :                                 k;
    4600              : 
    4601            0 :         for (j = 0; j < te1->nLockDeps; j++)
    4602              :         {
    4603            0 :                 for (k = 0; k < te2->nDeps; k++)
    4604              :                 {
    4605            0 :                         if (te1->lockDeps[j] == te2->dependencies[k])
    4606            0 :                                 return true;
    4607            0 :                 }
    4608            0 :         }
    4609            0 :         return false;
    4610            0 : }
    4611              : 
    4612              : 
    4613              : /*
    4614              :  * Initialize the header of the pending-items list.
    4615              :  *
    4616              :  * This is a circular list with a dummy TocEntry as header, just like the
    4617              :  * main TOC list; but we use separate list links so that an entry can be in
    4618              :  * the main TOC list as well as in the pending list.
    4619              :  */
    4620              : static void
    4621            0 : pending_list_header_init(TocEntry *l)
    4622              : {
    4623            0 :         l->pending_prev = l->pending_next = l;
    4624            0 : }
    4625              : 
    4626              : /* Append te to the end of the pending-list headed by l */
    4627              : static void
    4628            0 : pending_list_append(TocEntry *l, TocEntry *te)
    4629              : {
    4630            0 :         te->pending_prev = l->pending_prev;
    4631            0 :         l->pending_prev->pending_next = te;
    4632            0 :         l->pending_prev = te;
    4633            0 :         te->pending_next = l;
    4634            0 : }
    4635              : 
    4636              : /* Remove te from the pending-list */
    4637              : static void
    4638            0 : pending_list_remove(TocEntry *te)
    4639              : {
    4640            0 :         te->pending_prev->pending_next = te->pending_next;
    4641            0 :         te->pending_next->pending_prev = te->pending_prev;
    4642            0 :         te->pending_prev = NULL;
    4643            0 :         te->pending_next = NULL;
    4644            0 : }
    4645              : 
    4646              : 
    4647              : /* qsort comparator for sorting TocEntries by dataLength */
    4648              : static int
    4649            0 : TocEntrySizeCompareQsort(const void *p1, const void *p2)
    4650              : {
    4651            0 :         const TocEntry *te1 = *(const TocEntry *const *) p1;
    4652            0 :         const TocEntry *te2 = *(const TocEntry *const *) p2;
    4653              : 
    4654              :         /* Sort by decreasing dataLength */
    4655            0 :         if (te1->dataLength > te2->dataLength)
    4656            0 :                 return -1;
    4657            0 :         if (te1->dataLength < te2->dataLength)
    4658            0 :                 return 1;
    4659              : 
    4660              :         /* For equal dataLengths, sort by dumpId, just to be stable */
    4661            0 :         if (te1->dumpId < te2->dumpId)
    4662            0 :                 return -1;
    4663            0 :         if (te1->dumpId > te2->dumpId)
    4664            0 :                 return 1;
    4665              : 
    4666            0 :         return 0;
    4667            0 : }
    4668              : 
    4669              : /* binaryheap comparator for sorting TocEntries by dataLength */
    4670              : static int
    4671            0 : TocEntrySizeCompareBinaryheap(void *p1, void *p2, void *arg)
    4672              : {
    4673              :         /* return opposite of qsort comparator for max-heap */
    4674            0 :         return -TocEntrySizeCompareQsort(&p1, &p2);
    4675              : }
    4676              : 
    4677              : 
    4678              : /*
    4679              :  * Move all immediately-ready items from pending_list to ready_heap.
    4680              :  *
    4681              :  * Items are considered ready if they have no remaining dependencies and
    4682              :  * they belong in the current restore pass.  (See also reduce_dependencies,
    4683              :  * which applies the same logic one-at-a-time.)
    4684              :  */
    4685              : static void
    4686            0 : move_to_ready_heap(TocEntry *pending_list,
    4687              :                                    binaryheap *ready_heap,
    4688              :                                    RestorePass pass)
    4689              : {
    4690            0 :         TocEntry   *te;
    4691            0 :         TocEntry   *next_te;
    4692              : 
    4693            0 :         for (te = pending_list->pending_next; te != pending_list; te = next_te)
    4694              :         {
    4695              :                 /* must save list link before possibly removing te from list */
    4696            0 :                 next_te = te->pending_next;
    4697              : 
    4698            0 :                 if (te->depCount == 0 &&
    4699            0 :                         _tocEntryRestorePass(te) == pass)
    4700              :                 {
    4701              :                         /* Remove it from pending_list ... */
    4702            0 :                         pending_list_remove(te);
    4703              :                         /* ... and add to ready_heap */
    4704            0 :                         binaryheap_add(ready_heap, te);
    4705            0 :                 }
    4706            0 :         }
    4707            0 : }
    4708              : 
    4709              : /*
    4710              :  * Find the next work item (if any) that is capable of being run now,
    4711              :  * and remove it from the ready_heap.
    4712              :  *
    4713              :  * Returns the item, or NULL if nothing is runnable.
    4714              :  *
    4715              :  * To qualify, the item must have no remaining dependencies
    4716              :  * and no requirements for locks that are incompatible with
    4717              :  * items currently running.  Items in the ready_heap are known to have
    4718              :  * no remaining dependencies, but we have to check for lock conflicts.
    4719              :  */
    4720              : static TocEntry *
    4721            0 : pop_next_work_item(binaryheap *ready_heap,
    4722              :                                    ParallelState *pstate)
    4723              : {
    4724              :         /*
    4725              :          * Search the ready_heap until we find a suitable item.  Note that we do a
    4726              :          * sequential scan through the heap nodes, so even though we will first
    4727              :          * try to choose the highest-priority item, we might end up picking
    4728              :          * something with a much lower priority.  However, we expect that we will
    4729              :          * typically be able to pick one of the first few items, which should
    4730              :          * usually have a relatively high priority.
    4731              :          */
    4732            0 :         for (int i = 0; i < binaryheap_size(ready_heap); i++)
    4733              :         {
    4734            0 :                 TocEntry   *te = (TocEntry *) binaryheap_get_node(ready_heap, i);
    4735            0 :                 bool            conflicts = false;
    4736              : 
    4737              :                 /*
    4738              :                  * Check to see if the item would need exclusive lock on something
    4739              :                  * that a currently running item also needs lock on, or vice versa. If
    4740              :                  * so, we don't want to schedule them together.
    4741              :                  */
    4742            0 :                 for (int k = 0; k < pstate->numWorkers; k++)
    4743              :                 {
    4744            0 :                         TocEntry   *running_te = pstate->te[k];
    4745              : 
    4746            0 :                         if (running_te == NULL)
    4747            0 :                                 continue;
    4748            0 :                         if (has_lock_conflicts(te, running_te) ||
    4749            0 :                                 has_lock_conflicts(running_te, te))
    4750              :                         {
    4751            0 :                                 conflicts = true;
    4752            0 :                                 break;
    4753              :                         }
    4754            0 :                 }
    4755              : 
    4756            0 :                 if (conflicts)
    4757            0 :                         continue;
    4758              : 
    4759              :                 /* passed all tests, so this item can run */
    4760            0 :                 binaryheap_remove_node(ready_heap, i);
    4761            0 :                 return te;
    4762            0 :         }
    4763              : 
    4764            0 :         pg_log_debug("no item ready");
    4765            0 :         return NULL;
    4766            0 : }
    4767              : 
    4768              : 
    4769              : /*
    4770              :  * Restore a single TOC item in parallel with others
    4771              :  *
    4772              :  * this is run in the worker, i.e. in a thread (Windows) or a separate process
    4773              :  * (everything else). A worker process executes several such work items during
    4774              :  * a parallel backup or restore. Once we terminate here and report back that
    4775              :  * our work is finished, the leader process will assign us a new work item.
    4776              :  */
    4777              : int
    4778            0 : parallel_restore(ArchiveHandle *AH, TocEntry *te)
    4779              : {
    4780            0 :         int                     status;
    4781              : 
    4782            0 :         Assert(AH->connection != NULL);
    4783              : 
    4784              :         /* Count only errors associated with this TOC entry */
    4785            0 :         AH->public.n_errors = 0;
    4786              : 
    4787              :         /* Restore the TOC item */
    4788            0 :         status = restore_toc_entry(AH, te, true);
    4789              : 
    4790            0 :         return status;
    4791            0 : }
    4792              : 
    4793              : 
    4794              : /*
    4795              :  * Callback function that's invoked in the leader process after a step has
    4796              :  * been parallel restored.
    4797              :  *
    4798              :  * Update status and reduce the dependency count of any dependent items.
    4799              :  */
    4800              : static void
    4801            0 : mark_restore_job_done(ArchiveHandle *AH,
    4802              :                                           TocEntry *te,
    4803              :                                           int status,
    4804              :                                           void *callback_data)
    4805              : {
    4806            0 :         binaryheap *ready_heap = (binaryheap *) callback_data;
    4807              : 
    4808            0 :         pg_log_info("finished item %d %s %s",
    4809              :                                 te->dumpId, te->desc, te->tag);
    4810              : 
    4811            0 :         if (status == WORKER_CREATE_DONE)
    4812            0 :                 mark_create_done(AH, te);
    4813            0 :         else if (status == WORKER_INHIBIT_DATA)
    4814              :         {
    4815            0 :                 inhibit_data_for_failed_table(AH, te);
    4816            0 :                 AH->public.n_errors++;
    4817            0 :         }
    4818            0 :         else if (status == WORKER_IGNORED_ERRORS)
    4819            0 :                 AH->public.n_errors++;
    4820            0 :         else if (status != 0)
    4821            0 :                 pg_fatal("worker process failed: exit code %d",
    4822              :                                  status);
    4823              : 
    4824            0 :         reduce_dependencies(AH, te, ready_heap);
    4825            0 : }
    4826              : 
    4827              : 
    4828              : /*
    4829              :  * Process the dependency information into a form useful for parallel restore.
    4830              :  *
    4831              :  * This function takes care of fixing up some missing or badly designed
    4832              :  * dependencies, and then prepares subsidiary data structures that will be
    4833              :  * used in the main parallel-restore logic, including:
    4834              :  * 1. We build the revDeps[] arrays of incoming dependency dumpIds.
    4835              :  * 2. We set up depCount fields that are the number of as-yet-unprocessed
    4836              :  * dependencies for each TOC entry.
    4837              :  *
    4838              :  * We also identify locking dependencies so that we can avoid trying to
    4839              :  * schedule conflicting items at the same time.
    4840              :  */
    4841              : static void
    4842            0 : fix_dependencies(ArchiveHandle *AH)
    4843              : {
    4844            0 :         TocEntry   *te;
    4845            0 :         int                     i;
    4846              : 
    4847              :         /*
    4848              :          * Initialize the depCount/revDeps/nRevDeps fields, and make sure the TOC
    4849              :          * items are marked as not being in any parallel-processing list.
    4850              :          */
    4851            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
    4852              :         {
    4853            0 :                 te->depCount = te->nDeps;
    4854            0 :                 te->revDeps = NULL;
    4855            0 :                 te->nRevDeps = 0;
    4856            0 :                 te->pending_prev = NULL;
    4857            0 :                 te->pending_next = NULL;
    4858            0 :         }
    4859              : 
    4860              :         /*
    4861              :          * POST_DATA items that are shown as depending on a table need to be
    4862              :          * re-pointed to depend on that table's data, instead.  This ensures they
    4863              :          * won't get scheduled until the data has been loaded.
    4864              :          */
    4865            0 :         repoint_table_dependencies(AH);
    4866              : 
    4867              :         /*
    4868              :          * Pre-8.4 versions of pg_dump neglected to set up a dependency from BLOB
    4869              :          * COMMENTS to BLOBS.  Cope.  (We assume there's only one BLOBS and only
    4870              :          * one BLOB COMMENTS in such files.)
    4871              :          */
    4872            0 :         if (AH->version < K_VERS_1_11)
    4873              :         {
    4874            0 :                 for (te = AH->toc->next; te != AH->toc; te = te->next)
    4875              :                 {
    4876            0 :                         if (strcmp(te->desc, "BLOB COMMENTS") == 0 && te->nDeps == 0)
    4877              :                         {
    4878            0 :                                 TocEntry   *te2;
    4879              : 
    4880            0 :                                 for (te2 = AH->toc->next; te2 != AH->toc; te2 = te2->next)
    4881              :                                 {
    4882            0 :                                         if (strcmp(te2->desc, "BLOBS") == 0)
    4883              :                                         {
    4884            0 :                                                 te->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    4885            0 :                                                 te->dependencies[0] = te2->dumpId;
    4886            0 :                                                 te->nDeps++;
    4887            0 :                                                 te->depCount++;
    4888            0 :                                                 break;
    4889              :                                         }
    4890            0 :                                 }
    4891              :                                 break;
    4892            0 :                         }
    4893            0 :                 }
    4894            0 :         }
    4895              : 
    4896              :         /*
    4897              :          * At this point we start to build the revDeps reverse-dependency arrays,
    4898              :          * so all changes of dependencies must be complete.
    4899              :          */
    4900              : 
    4901              :         /*
    4902              :          * Count the incoming dependencies for each item.  Also, it is possible
    4903              :          * that the dependencies list items that are not in the archive at all
    4904              :          * (that should not happen in 9.2 and later, but is highly likely in older
    4905              :          * archives).  Subtract such items from the depCounts.
    4906              :          */
    4907            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
    4908              :         {
    4909            0 :                 for (i = 0; i < te->nDeps; i++)
    4910              :                 {
    4911            0 :                         DumpId          depid = te->dependencies[i];
    4912              : 
    4913            0 :                         if (depid <= AH->maxDumpId && AH->tocsByDumpId[depid] != NULL)
    4914            0 :                                 AH->tocsByDumpId[depid]->nRevDeps++;
    4915              :                         else
    4916            0 :                                 te->depCount--;
    4917            0 :                 }
    4918            0 :         }
    4919              : 
    4920              :         /*
    4921              :          * Allocate space for revDeps[] arrays, and reset nRevDeps so we can use
    4922              :          * it as a counter below.
    4923              :          */
    4924            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
    4925              :         {
    4926            0 :                 if (te->nRevDeps > 0)
    4927            0 :                         te->revDeps = (DumpId *) pg_malloc(te->nRevDeps * sizeof(DumpId));
    4928            0 :                 te->nRevDeps = 0;
    4929            0 :         }
    4930              : 
    4931              :         /*
    4932              :          * Build the revDeps[] arrays of incoming-dependency dumpIds.  This had
    4933              :          * better agree with the loops above.
    4934              :          */
    4935            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
    4936              :         {
    4937            0 :                 for (i = 0; i < te->nDeps; i++)
    4938              :                 {
    4939            0 :                         DumpId          depid = te->dependencies[i];
    4940              : 
    4941            0 :                         if (depid <= AH->maxDumpId && AH->tocsByDumpId[depid] != NULL)
    4942              :                         {
    4943            0 :                                 TocEntry   *otherte = AH->tocsByDumpId[depid];
    4944              : 
    4945            0 :                                 otherte->revDeps[otherte->nRevDeps++] = te->dumpId;
    4946            0 :                         }
    4947            0 :                 }
    4948            0 :         }
    4949              : 
    4950              :         /*
    4951              :          * Lastly, work out the locking dependencies.
    4952              :          */
    4953            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
    4954              :         {
    4955            0 :                 te->lockDeps = NULL;
    4956            0 :                 te->nLockDeps = 0;
    4957            0 :                 identify_locking_dependencies(AH, te);
    4958            0 :         }
    4959            0 : }
    4960              : 
    4961              : /*
    4962              :  * Change dependencies on table items to depend on table data items instead,
    4963              :  * but only in POST_DATA items.
    4964              :  *
    4965              :  * Also, for any item having such dependency(s), set its dataLength to the
    4966              :  * largest dataLength of the table data items it depends on.  This ensures
    4967              :  * that parallel restore will prioritize larger jobs (index builds, FK
    4968              :  * constraint checks, etc) over smaller ones, avoiding situations where we
    4969              :  * end a restore with only one active job working on a large table.
    4970              :  */
    4971              : static void
    4972            0 : repoint_table_dependencies(ArchiveHandle *AH)
    4973              : {
    4974            0 :         TocEntry   *te;
    4975            0 :         int                     i;
    4976            0 :         DumpId          olddep;
    4977              : 
    4978            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
    4979              :         {
    4980            0 :                 if (te->section != SECTION_POST_DATA)
    4981            0 :                         continue;
    4982            0 :                 for (i = 0; i < te->nDeps; i++)
    4983              :                 {
    4984            0 :                         olddep = te->dependencies[i];
    4985            0 :                         if (olddep <= AH->maxDumpId &&
    4986            0 :                                 AH->tableDataId[olddep] != 0)
    4987              :                         {
    4988            0 :                                 DumpId          tabledataid = AH->tableDataId[olddep];
    4989            0 :                                 TocEntry   *tabledatate = AH->tocsByDumpId[tabledataid];
    4990              : 
    4991            0 :                                 te->dependencies[i] = tabledataid;
    4992            0 :                                 te->dataLength = Max(te->dataLength, tabledatate->dataLength);
    4993            0 :                                 pg_log_debug("transferring dependency %d -> %d to %d",
    4994              :                                                          te->dumpId, olddep, tabledataid);
    4995            0 :                         }
    4996            0 :                 }
    4997            0 :         }
    4998            0 : }
    4999              : 
    5000              : /*
    5001              :  * Identify which objects we'll need exclusive lock on in order to restore
    5002              :  * the given TOC entry (*other* than the one identified by the TOC entry
    5003              :  * itself).  Record their dump IDs in the entry's lockDeps[] array.
    5004              :  */
    5005              : static void
    5006            0 : identify_locking_dependencies(ArchiveHandle *AH, TocEntry *te)
    5007              : {
    5008            0 :         DumpId     *lockids;
    5009            0 :         int                     nlockids;
    5010            0 :         int                     i;
    5011              : 
    5012              :         /*
    5013              :          * We only care about this for POST_DATA items.  PRE_DATA items are not
    5014              :          * run in parallel, and DATA items are all independent by assumption.
    5015              :          */
    5016            0 :         if (te->section != SECTION_POST_DATA)
    5017            0 :                 return;
    5018              : 
    5019              :         /* Quick exit if no dependencies at all */
    5020            0 :         if (te->nDeps == 0)
    5021            0 :                 return;
    5022              : 
    5023              :         /*
    5024              :          * Most POST_DATA items are ALTER TABLEs or some moral equivalent of that,
    5025              :          * and hence require exclusive lock.  However, we know that CREATE INDEX
    5026              :          * does not.  (Maybe someday index-creating CONSTRAINTs will fall in that
    5027              :          * category too ... but today is not that day.)
    5028              :          */
    5029            0 :         if (strcmp(te->desc, "INDEX") == 0)
    5030            0 :                 return;
    5031              : 
    5032              :         /*
    5033              :          * We assume the entry requires exclusive lock on each TABLE or TABLE DATA
    5034              :          * item listed among its dependencies.  Originally all of these would have
    5035              :          * been TABLE items, but repoint_table_dependencies would have repointed
    5036              :          * them to the TABLE DATA items if those are present (which they might not
    5037              :          * be, eg in a schema-only dump).  Note that all of the entries we are
    5038              :          * processing here are POST_DATA; otherwise there might be a significant
    5039              :          * difference between a dependency on a table and a dependency on its
    5040              :          * data, so that closer analysis would be needed here.
    5041              :          */
    5042            0 :         lockids = (DumpId *) pg_malloc(te->nDeps * sizeof(DumpId));
    5043            0 :         nlockids = 0;
    5044            0 :         for (i = 0; i < te->nDeps; i++)
    5045              :         {
    5046            0 :                 DumpId          depid = te->dependencies[i];
    5047              : 
    5048            0 :                 if (depid <= AH->maxDumpId && AH->tocsByDumpId[depid] != NULL &&
    5049            0 :                         ((strcmp(AH->tocsByDumpId[depid]->desc, "TABLE DATA") == 0) ||
    5050            0 :                          strcmp(AH->tocsByDumpId[depid]->desc, "TABLE") == 0))
    5051            0 :                         lockids[nlockids++] = depid;
    5052            0 :         }
    5053              : 
    5054            0 :         if (nlockids == 0)
    5055              :         {
    5056            0 :                 free(lockids);
    5057            0 :                 return;
    5058              :         }
    5059              : 
    5060            0 :         te->lockDeps = pg_realloc(lockids, nlockids * sizeof(DumpId));
    5061            0 :         te->nLockDeps = nlockids;
    5062            0 : }
    5063              : 
    5064              : /*
    5065              :  * Remove the specified TOC entry from the depCounts of items that depend on
    5066              :  * it, thereby possibly making them ready-to-run.  Any pending item that
    5067              :  * becomes ready should be moved to the ready_heap, if that's provided.
    5068              :  */
    5069              : static void
    5070            0 : reduce_dependencies(ArchiveHandle *AH, TocEntry *te,
    5071              :                                         binaryheap *ready_heap)
    5072              : {
    5073            0 :         int                     i;
    5074              : 
    5075            0 :         pg_log_debug("reducing dependencies for %d", te->dumpId);
    5076              : 
    5077            0 :         for (i = 0; i < te->nRevDeps; i++)
    5078              :         {
    5079            0 :                 TocEntry   *otherte = AH->tocsByDumpId[te->revDeps[i]];
    5080              : 
    5081            0 :                 Assert(otherte->depCount > 0);
    5082            0 :                 otherte->depCount--;
    5083              : 
    5084              :                 /*
    5085              :                  * It's ready if it has no remaining dependencies, and it belongs in
    5086              :                  * the current restore pass, and it is currently a member of the
    5087              :                  * pending list (that check is needed to prevent double restore in
    5088              :                  * some cases where a list-file forces out-of-order restoring).
    5089              :                  * However, if ready_heap == NULL then caller doesn't want any list
    5090              :                  * memberships changed.
    5091              :                  */
    5092            0 :                 if (otherte->depCount == 0 &&
    5093            0 :                         _tocEntryRestorePass(otherte) == AH->restorePass &&
    5094            0 :                         otherte->pending_prev != NULL &&
    5095            0 :                         ready_heap != NULL)
    5096              :                 {
    5097              :                         /* Remove it from pending list ... */
    5098            0 :                         pending_list_remove(otherte);
    5099              :                         /* ... and add to ready_heap */
    5100            0 :                         binaryheap_add(ready_heap, otherte);
    5101            0 :                 }
    5102            0 :         }
    5103            0 : }
    5104              : 
    5105              : /*
    5106              :  * Set the created flag on the DATA member corresponding to the given
    5107              :  * TABLE member
    5108              :  */
    5109              : static void
    5110            0 : mark_create_done(ArchiveHandle *AH, TocEntry *te)
    5111              : {
    5112            0 :         if (AH->tableDataId[te->dumpId] != 0)
    5113              :         {
    5114            0 :                 TocEntry   *ted = AH->tocsByDumpId[AH->tableDataId[te->dumpId]];
    5115              : 
    5116            0 :                 ted->created = true;
    5117            0 :         }
    5118            0 : }
    5119              : 
    5120              : /*
    5121              :  * Mark the DATA member corresponding to the given TABLE member
    5122              :  * as not wanted
    5123              :  */
    5124              : static void
    5125            0 : inhibit_data_for_failed_table(ArchiveHandle *AH, TocEntry *te)
    5126              : {
    5127            0 :         pg_log_info("table \"%s\" could not be created, will not restore its data",
    5128              :                                 te->tag);
    5129              : 
    5130            0 :         if (AH->tableDataId[te->dumpId] != 0)
    5131              :         {
    5132            0 :                 TocEntry   *ted = AH->tocsByDumpId[AH->tableDataId[te->dumpId]];
    5133              : 
    5134            0 :                 ted->reqs = 0;
    5135            0 :         }
    5136            0 : }
    5137              : 
    5138              : /*
    5139              :  * Clone and de-clone routines used in parallel restoration.
    5140              :  *
    5141              :  * Enough of the structure is cloned to ensure that there is no
    5142              :  * conflict between different threads each with their own clone.
    5143              :  */
    5144              : ArchiveHandle *
    5145            0 : CloneArchive(ArchiveHandle *AH)
    5146              : {
    5147            0 :         ArchiveHandle *clone;
    5148              : 
    5149              :         /* Make a "flat" copy */
    5150            0 :         clone = (ArchiveHandle *) pg_malloc(sizeof(ArchiveHandle));
    5151            0 :         memcpy(clone, AH, sizeof(ArchiveHandle));
    5152              : 
    5153              :         /* Likewise flat-copy the RestoreOptions, so we can alter them locally */
    5154            0 :         clone->public.ropt = (RestoreOptions *) pg_malloc(sizeof(RestoreOptions));
    5155            0 :         memcpy(clone->public.ropt, AH->public.ropt, sizeof(RestoreOptions));
    5156              : 
    5157              :         /* Handle format-independent fields */
    5158            0 :         memset(&(clone->sqlparse), 0, sizeof(clone->sqlparse));
    5159              : 
    5160              :         /* The clone will have its own connection, so disregard connection state */
    5161            0 :         clone->connection = NULL;
    5162            0 :         clone->connCancel = NULL;
    5163            0 :         clone->currUser = NULL;
    5164            0 :         clone->currSchema = NULL;
    5165            0 :         clone->currTableAm = NULL;
    5166            0 :         clone->currTablespace = NULL;
    5167              : 
    5168              :         /* savedPassword must be local in case we change it while connecting */
    5169            0 :         if (clone->savedPassword)
    5170            0 :                 clone->savedPassword = pg_strdup(clone->savedPassword);
    5171              : 
    5172              :         /* clone has its own error count, too */
    5173            0 :         clone->public.n_errors = 0;
    5174              : 
    5175              :         /* clones should not share lo_buf */
    5176            0 :         clone->lo_buf = NULL;
    5177              : 
    5178              :         /*
    5179              :          * Clone connections disregard --transaction-size; they must commit after
    5180              :          * each command so that the results are immediately visible to other
    5181              :          * workers.
    5182              :          */
    5183            0 :         clone->public.ropt->txn_size = 0;
    5184              : 
    5185              :         /*
    5186              :          * Connect our new clone object to the database, using the same connection
    5187              :          * parameters used for the original connection.
    5188              :          */
    5189            0 :         ConnectDatabaseAhx((Archive *) clone, &clone->public.ropt->cparams, true);
    5190              : 
    5191              :         /* re-establish fixed state */
    5192            0 :         if (AH->mode == archModeRead)
    5193            0 :                 _doSetFixedOutputState(clone);
    5194              :         /* in write case, setupDumpWorker will fix up connection state */
    5195              : 
    5196              :         /* Let the format-specific code have a chance too */
    5197            0 :         clone->ClonePtr(clone);
    5198              : 
    5199            0 :         Assert(clone->connection != NULL);
    5200            0 :         return clone;
    5201            0 : }
    5202              : 
    5203              : /*
    5204              :  * Release clone-local storage.
    5205              :  *
    5206              :  * Note: we assume any clone-local connection was already closed.
    5207              :  */
    5208              : void
    5209            0 : DeCloneArchive(ArchiveHandle *AH)
    5210              : {
    5211              :         /* Should not have an open database connection */
    5212            0 :         Assert(AH->connection == NULL);
    5213              : 
    5214              :         /* Clear format-specific state */
    5215            0 :         AH->DeClonePtr(AH);
    5216              : 
    5217              :         /* Clear state allocated by CloneArchive */
    5218            0 :         if (AH->sqlparse.curCmd)
    5219            0 :                 destroyPQExpBuffer(AH->sqlparse.curCmd);
    5220              : 
    5221              :         /* Clear any connection-local state */
    5222            0 :         free(AH->currUser);
    5223            0 :         free(AH->currSchema);
    5224            0 :         free(AH->currTablespace);
    5225            0 :         free(AH->currTableAm);
    5226            0 :         free(AH->savedPassword);
    5227              : 
    5228            0 :         free(AH);
    5229            0 : }
        

Generated by: LCOV version 2.3.2-1