]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_backup_archiver.c
Clean up pg_dump's handling of ownership for indexes (including
[postgresql] / src / bin / pg_dump / pg_backup_archiver.c
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  *              $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.101 2005/01/11 05:14:10 tgl Exp $
19  *
20  *-------------------------------------------------------------------------
21  */
22
23 #include "pg_backup.h"
24 #include "pg_dump.h"
25 #include "pg_backup_archiver.h"
26 #include "pg_backup_db.h"
27 #include "dumputils.h"
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <unistd.h>
32
33 #include "pqexpbuffer.h"
34 #include "libpq/libpq-fs.h"
35
36
37 typedef enum _teReqs_
38 {
39         REQ_SCHEMA = 1,
40         REQ_DATA = 2,
41         REQ_ALL = REQ_SCHEMA + REQ_DATA
42 } teReqs;
43
44 const char *progname;
45 static char *modulename = gettext_noop("archiver");
46
47
48 static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
49                  const int compression, ArchiveMode mode);
50 static void _getObjectDescription(PQExpBuffer buf, TocEntry *te);
51 static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass);
52
53
54 static void fixPriorBlobRefs(ArchiveHandle *AH, TocEntry *blobte,
55                                  RestoreOptions *ropt);
56 static void _doSetFixedOutputState(ArchiveHandle *AH);
57 static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
58 static void _doSetWithOids(ArchiveHandle *AH, const bool withOids);
59 static void _reconnectToDB(ArchiveHandle *AH, const char *dbname);
60 static void _becomeUser(ArchiveHandle *AH, const char *user);
61 static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
62 static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
63 static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
64
65 static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool acl_pass);
66 static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
67 static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
68 static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
69 static void _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te);
70 static int      _discoverArchiveFormat(ArchiveHandle *AH);
71
72 static void _write_msg(const char *modulename, const char *fmt, va_list ap);
73 static void _die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt, va_list ap);
74
75 static int      _canRestoreBlobs(ArchiveHandle *AH);
76 static int      _restoringToDB(ArchiveHandle *AH);
77
78
79 /*
80  *      Wrapper functions.
81  *
82  *      The objective it to make writing new formats and dumpers as simple
83  *      as possible, if necessary at the expense of extra function calls etc.
84  *
85  */
86
87
88 /* Create a new archive */
89 /* Public */
90 Archive *
91 CreateArchive(const char *FileSpec, const ArchiveFormat fmt,
92                           const int compression)
93
94 {
95         ArchiveHandle *AH = _allocAH(FileSpec, fmt, compression, archModeWrite);
96
97         return (Archive *) AH;
98 }
99
100 /* Open an existing archive */
101 /* Public */
102 Archive *
103 OpenArchive(const char *FileSpec, const ArchiveFormat fmt)
104 {
105         ArchiveHandle *AH = _allocAH(FileSpec, fmt, 0, archModeRead);
106
107         return (Archive *) AH;
108 }
109
110 /* Public */
111 void
112 CloseArchive(Archive *AHX)
113 {
114         int                     res = 0;
115         ArchiveHandle *AH = (ArchiveHandle *) AHX;
116
117         (*AH->ClosePtr) (AH);
118
119         /* Close the output */
120         if (AH->gzOut)
121                 res = GZCLOSE(AH->OF);
122         else if (AH->OF != stdout)
123                 res = fclose(AH->OF);
124
125         if (res != 0)
126                 die_horribly(AH, modulename, "could not close output archive file\n");
127 }
128
129 /* Public */
130 void
131 RestoreArchive(Archive *AHX, RestoreOptions *ropt)
132 {
133         ArchiveHandle *AH = (ArchiveHandle *) AHX;
134         TocEntry   *te = AH->toc->next;
135         teReqs          reqs;
136         OutputContext sav;
137         int                     impliedDataOnly;
138         bool            defnDumped;
139
140         AH->ropt = ropt;
141         AH->stage = STAGE_INITIALIZING;
142
143         /*
144          * Check for nonsensical option combinations.
145          *
146          * NB: create+dropSchema is useless because if you're creating the DB,
147          * there's no need to drop individual items in it.  Moreover, if we
148          * tried to do that then we'd issue the drops in the database
149          * initially connected to, not the one we will create, which is very
150          * bad...
151          */
152         if (ropt->create && ropt->dropSchema)
153                 die_horribly(AH, modulename, "-C and -c are incompatible options\n");
154
155         /*
156          * If we're using a DB connection, then connect it.
157          */
158         if (ropt->useDB)
159         {
160                 ahlog(AH, 1, "connecting to database for restore\n");
161                 if (AH->version < K_VERS_1_3)
162                         die_horribly(AH, modulename, "direct database connections are not supported in pre-1.3 archives\n");
163
164                 /* XXX Should get this from the archive */
165                 AHX->minRemoteVersion = 070100;
166                 AHX->maxRemoteVersion = 999999;
167
168                 ConnectDatabase(AHX, ropt->dbname,
169                                                 ropt->pghost, ropt->pgport, ropt->username,
170                                                 ropt->requirePassword, ropt->ignoreVersion);
171
172                 /*
173                  * If we're talking to the DB directly, don't send comments since
174                  * they obscure SQL when displaying errors
175                  */
176                 AH->noTocComments = 1;
177         }
178
179         /*
180          * Work out if we have an implied data-only restore. This can happen
181          * if the dump was data only or if the user has used a toc list to
182          * exclude all of the schema data. All we do is look for schema
183          * entries - if none are found then we set the dataOnly flag.
184          *
185          * We could scan for wanted TABLE entries, but that is not the same as
186          * dataOnly. At this stage, it seems unnecessary (6-Mar-2001).
187          */
188         if (!ropt->dataOnly)
189         {
190                 te = AH->toc->next;
191                 impliedDataOnly = 1;
192                 while (te != AH->toc)
193                 {
194                         reqs = _tocEntryRequired(te, ropt, false);
195                         if ((reqs & REQ_SCHEMA) != 0)
196                         {                                       /* It's schema, and it's wanted */
197                                 impliedDataOnly = 0;
198                                 break;
199                         }
200                         te = te->next;
201                 }
202                 if (impliedDataOnly)
203                 {
204                         ropt->dataOnly = impliedDataOnly;
205                         ahlog(AH, 1, "implied data-only restore\n");
206                 }
207         }
208
209         /*
210          * Setup the output file if necessary.
211          */
212         if (ropt->filename || ropt->compression)
213                 sav = SetOutput(AH, ropt->filename, ropt->compression);
214
215         ahprintf(AH, "--\n-- PostgreSQL database dump\n--\n\n");
216
217         /*
218          * Establish important parameter values right away.
219          */
220         _doSetFixedOutputState(AH);
221
222         AH->stage = STAGE_PROCESSING;
223
224         /*
225          * Drop the items at the start, in reverse order
226          */
227         if (ropt->dropSchema)
228         {
229                 te = AH->toc->prev;
230                 AH->currentTE = te;
231
232                 while (te != AH->toc)
233                 {
234                         reqs = _tocEntryRequired(te, ropt, false);
235                         if (((reqs & REQ_SCHEMA) != 0) && te->dropStmt)
236                         {
237                                 /* We want the schema */
238                                 ahlog(AH, 1, "dropping %s %s\n", te->desc, te->tag);
239                                 /* Select owner and schema as necessary */
240                                 _becomeOwner(AH, te);
241                                 _selectOutputSchema(AH, te->namespace);
242                                 /* Drop it */
243                                 ahprintf(AH, "%s", te->dropStmt);
244                         }
245                         te = te->prev;
246                 }
247         }
248
249         /*
250          * Now process each TOC entry
251          */
252         te = AH->toc->next;
253         while (te != AH->toc)
254         {
255                 AH->currentTE = te;
256
257                 /* Work out what, if anything, we want from this entry */
258                 reqs = _tocEntryRequired(te, ropt, false);
259
260                 /* Dump any relevant dump warnings to stderr */
261                 if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
262                 {
263                         if (!ropt->dataOnly && te->defn != NULL && strlen(te->defn) != 0)
264                                 write_msg(modulename, "warning from original dump file: %s\n", te->defn);
265                         else if (te->copyStmt != NULL && strlen(te->copyStmt) != 0)
266                                 write_msg(modulename, "warning from original dump file: %s\n", te->copyStmt);
267                 }
268
269                 defnDumped = false;
270
271                 if ((reqs & REQ_SCHEMA) != 0)   /* We want the schema */
272                 {
273                         ahlog(AH, 1, "creating %s %s\n", te->desc, te->tag);
274
275                         _printTocEntry(AH, te, ropt, false, false);
276                         defnDumped = true;
277
278                         /* If we created a DB, connect to it... */
279                         if (strcmp(te->desc, "DATABASE") == 0)
280                         {
281                                 ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag);
282                                 _reconnectToDB(AH, te->tag);
283                         }
284                 }
285
286                 /*
287                  * If we have a data component, then process it
288                  */
289                 if ((reqs & REQ_DATA) != 0)
290                 {
291                         /*
292                          * hadDumper will be set if there is genuine data component
293                          * for this node. Otherwise, we need to check the defn field
294                          * for statements that need to be executed in data-only
295                          * restores.
296                          */
297                         if (te->hadDumper)
298                         {
299                                 /*
300                                  * If we can output the data, then restore it.
301                                  */
302                                 if (AH->PrintTocDataPtr !=NULL && (reqs & REQ_DATA) != 0)
303                                 {
304 #ifndef HAVE_LIBZ
305                                         if (AH->compression != 0)
306                                                 die_horribly(AH, modulename, "cannot restore from compressed archive (not configured for compression support)\n");
307 #endif
308
309                                         _printTocEntry(AH, te, ropt, true, false);
310
311                                         /*
312                                          * Maybe we can't do BLOBS, so check if this node is
313                                          * for BLOBS
314                                          */
315                                         if ((strcmp(te->desc, "BLOBS") == 0) &&
316                                                 !_canRestoreBlobs(AH))
317                                         {
318                                                 ahprintf(AH, "--\n-- SKIPPED \n--\n\n");
319
320                                                 /*
321                                                  * This is a bit nasty - we assume, for the
322                                                  * moment, that if a custom output is used, then
323                                                  * we don't want warnings.
324                                                  */
325                                                 if (!AH->CustomOutPtr)
326                                                         write_msg(modulename, "WARNING: skipping large-object restoration\n");
327                                         }
328                                         else
329                                         {
330                                                 _disableTriggersIfNecessary(AH, te, ropt);
331
332                                                 /* Select owner and schema as necessary */
333                                                 _becomeOwner(AH, te);
334                                                 _selectOutputSchema(AH, te->namespace);
335
336                                                 ahlog(AH, 1, "restoring data for table \"%s\"\n", te->tag);
337
338                                                 /*
339                                                  * If we have a copy statement, use it. As of
340                                                  * V1.3, these are separate to allow easy import
341                                                  * from withing a database connection. Pre 1.3
342                                                  * archives can not use DB connections and are
343                                                  * sent to output only.
344                                                  *
345                                                  * For V1.3+, the table data MUST have a copy
346                                                  * statement so that we can go into appropriate
347                                                  * mode with libpq.
348                                                  */
349                                                 if (te->copyStmt && strlen(te->copyStmt) > 0)
350                                                         ahprintf(AH, te->copyStmt);
351
352                                                 (*AH->PrintTocDataPtr) (AH, te, ropt);
353
354                                                 /*
355                                                  * If we just restored blobs, fix references in
356                                                  * previously-loaded tables; otherwise, if we
357                                                  * previously restored blobs, fix references in
358                                                  * this table.  Note that in standard cases the
359                                                  * BLOBS entry comes after all TABLE DATA entries,
360                                                  * but we should cope with other orders in case
361                                                  * the user demands reordering.
362                                                  */
363                                                 if (strcmp(te->desc, "BLOBS") == 0)
364                                                         fixPriorBlobRefs(AH, te, ropt);
365                                                 else if (AH->createdBlobXref &&
366                                                                  strcmp(te->desc, "TABLE DATA") == 0)
367                                                 {
368                                                         ahlog(AH, 1, "fixing up large-object cross-reference for \"%s\"\n", te->tag);
369                                                         FixupBlobRefs(AH, te);
370                                                 }
371
372                                                 _enableTriggersIfNecessary(AH, te, ropt);
373                                         }
374                                 }
375                         }
376                         else if (!defnDumped)
377                         {
378                                 /* If we haven't already dumped the defn part, do so now */
379                                 ahlog(AH, 1, "executing %s %s\n", te->desc, te->tag);
380                                 _printTocEntry(AH, te, ropt, false, false);
381                         }
382                 }
383                 te = te->next;
384         }                                                       /* end loop over TOC entries */
385
386         /*
387          * Scan TOC again to output ownership commands and ACLs
388          */
389         te = AH->toc->next;
390         while (te != AH->toc)
391         {
392                 AH->currentTE = te;
393
394                 /* Work out what, if anything, we want from this entry */
395                 reqs = _tocEntryRequired(te, ropt, true);
396
397                 if ((reqs & REQ_SCHEMA) != 0)   /* We want the schema */
398                 {
399                         ahlog(AH, 1, "setting owner and privileges for %s %s\n",
400                                   te->desc, te->tag);
401                         _printTocEntry(AH, te, ropt, false, true);
402                 }
403
404                 te = te->next;
405         }
406
407         /*
408          * Clean up & we're done.
409          */
410         AH->stage = STAGE_FINALIZING;
411
412         if (ropt->filename || ropt->compression)
413                 ResetOutput(AH, sav);
414
415         if (ropt->useDB)
416         {
417                 PQfinish(AH->connection);
418                 AH->connection = NULL;
419
420                 if (AH->blobConnection)
421                 {
422                         PQfinish(AH->blobConnection);
423                         AH->blobConnection = NULL;
424                 }
425         }
426
427         ahprintf(AH, "--\n-- PostgreSQL database dump complete\n--\n\n");
428 }
429
430 /*
431  * After restoring BLOBS, fix all blob references in previously-restored
432  * tables.      (Normally, the BLOBS entry should appear after all TABLE DATA
433  * entries, so this will in fact handle all blob references.)
434  */
435 static void
436 fixPriorBlobRefs(ArchiveHandle *AH, TocEntry *blobte, RestoreOptions *ropt)
437 {
438         TocEntry   *te;
439         teReqs          reqs;
440
441         if (AH->createdBlobXref)
442         {
443                 /* NULL parameter means disable ALL user triggers */
444                 _disableTriggersIfNecessary(AH, NULL, ropt);
445
446                 for (te = AH->toc->next; te != blobte; te = te->next)
447                 {
448                         if (strcmp(te->desc, "TABLE DATA") == 0)
449                         {
450                                 reqs = _tocEntryRequired(te, ropt, false);
451
452                                 if ((reqs & REQ_DATA) != 0)             /* We loaded the data */
453                                 {
454                                         ahlog(AH, 1, "fixing up large-object cross-reference for \"%s\"\n", te->tag);
455                                         FixupBlobRefs(AH, te);
456                                 }
457                         }
458                 }
459
460                 /* NULL parameter means enable ALL user triggers */
461                 _enableTriggersIfNecessary(AH, NULL, ropt);
462         }
463 }
464
465 /*
466  * Allocate a new RestoreOptions block.
467  * This is mainly so we can initialize it, but also for future expansion,
468  */
469 RestoreOptions *
470 NewRestoreOptions(void)
471 {
472         RestoreOptions *opts;
473
474         opts = (RestoreOptions *) calloc(1, sizeof(RestoreOptions));
475
476         opts->format = archUnknown;
477         opts->suppressDumpWarnings = false;
478         opts->exit_on_error = false;
479
480         return opts;
481 }
482
483 /*
484  * Returns true if we're restoring directly to the database (and
485  * aren't just making a psql script that can do the restoration).
486  */
487 static int
488 _restoringToDB(ArchiveHandle *AH)
489 {
490         return (AH->ropt->useDB && AH->connection);
491 }
492
493 static int
494 _canRestoreBlobs(ArchiveHandle *AH)
495 {
496         return _restoringToDB(AH);
497 }
498
499 static void
500 _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
501 {
502         /* This hack is only needed in a data-only restore */
503         if (!ropt->dataOnly || !ropt->disable_triggers)
504                 return;
505
506         /* Don't do it for the BLOBS TocEntry, either */
507         if (te && strcmp(te->desc, "BLOBS") == 0)
508                 return;
509
510         /*
511          * Become superuser if possible, since they are the only ones who can
512          * update pg_class.  If -S was not given, assume the initial user
513          * identity is a superuser.
514          */
515         _becomeUser(AH, ropt->superuser);
516
517         ahlog(AH, 1, "disabling triggers\n");
518
519         /*
520          * Disable them. This is a hack. Needs to be done via an appropriate
521          * 'SET' command when one is available.
522          */
523         ahprintf(AH, "-- Disable triggers\n");
524
525         /*
526          * Just update the AFFECTED table, if known.  Otherwise update all
527          * non-system tables.
528          */
529         if (te && te->tag && strlen(te->tag) > 0)
530                 ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = 0 "
531                                  "WHERE oid = '%s'::pg_catalog.regclass;\n\n",
532                                  fmtId(te->tag));
533         else
534                 ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = 0 FROM pg_catalog.pg_namespace "
535                                  "WHERE relnamespace = pg_namespace.oid AND nspname !~ '^pg_';\n\n");
536 }
537
538 static void
539 _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
540 {
541         /* This hack is only needed in a data-only restore */
542         if (!ropt->dataOnly || !ropt->disable_triggers)
543                 return;
544
545         /* Don't do it for the BLOBS TocEntry, either */
546         if (te && strcmp(te->desc, "BLOBS") == 0)
547                 return;
548
549         /*
550          * Become superuser if possible, since they are the only ones who can
551          * update pg_class.  If -S was not given, assume the initial user
552          * identity is a superuser.
553          */
554         _becomeUser(AH, ropt->superuser);
555
556         ahlog(AH, 1, "enabling triggers\n");
557
558         /*
559          * Enable them. This is a hack. Needs to be done via an appropriate
560          * 'SET' command when one is available.
561          */
562         ahprintf(AH, "-- Enable triggers\n");
563
564         /*
565          * Just update the AFFECTED table, if known.  Otherwise update all
566          * non-system tables.
567          */
568         if (te && te->tag && strlen(te->tag) > 0)
569                 ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = "
570                                  "(SELECT pg_catalog.count(*) FROM pg_catalog.pg_trigger where pg_class.oid = tgrelid) "
571                                  "WHERE oid = '%s'::pg_catalog.regclass;\n\n",
572                                  fmtId(te->tag));
573         else
574                 ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = "
575                                  "(SELECT pg_catalog.count(*) FROM pg_catalog.pg_trigger where pg_class.oid = tgrelid) "
576                                  "FROM pg_catalog.pg_namespace "
577                                  "WHERE relnamespace = pg_namespace.oid AND nspname !~ '^pg_';\n\n");
578 }
579
580 /*
581  * This is a routine that is part of the dumper interface, hence the 'Archive*' parameter.
582  */
583
584 /* Public */
585 size_t
586 WriteData(Archive *AHX, const void *data, size_t dLen)
587 {
588         ArchiveHandle *AH = (ArchiveHandle *) AHX;
589
590         if (!AH->currToc)
591                 die_horribly(AH, modulename, "internal error -- WriteData cannot be called outside the context of a DataDumper routine\n");
592
593         return (*AH->WriteDataPtr) (AH, data, dLen);
594 }
595
596 /*
597  * Create a new TOC entry. The TOC was designed as a TOC, but is now the
598  * repository for all metadata. But the name has stuck.
599  */
600
601 /* Public */
602 void
603 ArchiveEntry(Archive *AHX,
604                          CatalogId catalogId, DumpId dumpId,
605                          const char *tag,
606                          const char *namespace,
607                          const char *tablespace, 
608                          const char *owner, bool withOids,
609                          const char *desc, const char *defn,
610                          const char *dropStmt, const char *copyStmt,
611                          const DumpId *deps, int nDeps,
612                          DataDumperPtr dumpFn, void *dumpArg)
613 {
614         ArchiveHandle *AH = (ArchiveHandle *) AHX;
615         TocEntry   *newToc;
616
617         newToc = (TocEntry *) calloc(1, sizeof(TocEntry));
618         if (!newToc)
619                 die_horribly(AH, modulename, "out of memory\n");
620
621         AH->tocCount++;
622         if (dumpId > AH->maxDumpId)
623                 AH->maxDumpId = dumpId;
624
625         newToc->prev = AH->toc->prev;
626         newToc->next = AH->toc;
627         AH->toc->prev->next = newToc;
628         AH->toc->prev = newToc;
629
630         newToc->catalogId = catalogId;
631         newToc->dumpId = dumpId;
632
633         newToc->tag = strdup(tag);
634         newToc->namespace = namespace ? strdup(namespace) : NULL;
635         newToc->tablespace = tablespace ? strdup(tablespace) : NULL;
636         newToc->owner = strdup(owner);
637         newToc->withOids = withOids;
638         newToc->desc = strdup(desc);
639         newToc->defn = strdup(defn);
640         newToc->dropStmt = strdup(dropStmt);
641         newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
642
643         if (nDeps > 0)
644         {
645                 newToc->dependencies = (DumpId *) malloc(nDeps * sizeof(DumpId));
646                 memcpy(newToc->dependencies, deps, nDeps * sizeof(DumpId));
647                 newToc->nDeps = nDeps;
648         }
649         else
650         {
651                 newToc->dependencies = NULL;
652                 newToc->nDeps = 0;
653         }
654
655         newToc->dataDumper = dumpFn;
656         newToc->dataDumperArg = dumpArg;
657         newToc->hadDumper = dumpFn ? true : false;
658
659         newToc->formatData = NULL;
660
661         if (AH->ArchiveEntryPtr !=NULL)
662                 (*AH->ArchiveEntryPtr) (AH, newToc);
663 }
664
665 /* Public */
666 void
667 PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
668 {
669         ArchiveHandle *AH = (ArchiveHandle *) AHX;
670         TocEntry   *te = AH->toc->next;
671         OutputContext sav;
672         char       *fmtName;
673
674         if (ropt->filename)
675                 sav = SetOutput(AH, ropt->filename, 0 /* no compression */ );
676
677         ahprintf(AH, ";\n; Archive created at %s", ctime(&AH->createDate));
678         ahprintf(AH, ";     dbname: %s\n;     TOC Entries: %d\n;     Compression: %d\n",
679                          AH->archdbname, AH->tocCount, AH->compression);
680
681         switch (AH->format)
682         {
683                 case archFiles:
684                         fmtName = "FILES";
685                         break;
686                 case archCustom:
687                         fmtName = "CUSTOM";
688                         break;
689                 case archTar:
690                         fmtName = "TAR";
691                         break;
692                 default:
693                         fmtName = "UNKNOWN";
694         }
695
696         ahprintf(AH, ";     Dump Version: %d.%d-%d\n", AH->vmaj, AH->vmin, AH->vrev);
697         ahprintf(AH, ";     Format: %s\n", fmtName);
698         ahprintf(AH, ";     Integer: %d bytes\n", (int) AH->intSize);
699         ahprintf(AH, ";     Offset: %d bytes\n", (int) AH->offSize);
700         if (AH->archiveRemoteVersion)
701                 ahprintf(AH, ";     Dumped from database version: %s\n",
702                                  AH->archiveRemoteVersion);
703         if (AH->archiveDumpVersion)
704                 ahprintf(AH, ";     Dumped by pg_dump version: %s\n",
705                                  AH->archiveDumpVersion);
706
707         ahprintf(AH, ";\n;\n; Selected TOC Entries:\n;\n");
708
709         while (te != AH->toc)
710         {
711                 if (_tocEntryRequired(te, ropt, false) != 0)
712                         ahprintf(AH, "%d; %u %u %s %s %s %s\n", te->dumpId,
713                                          te->catalogId.tableoid, te->catalogId.oid,
714                                          te->desc, te->namespace ? te->namespace : "-",
715                                          te->tag, te->owner);
716                 te = te->next;
717         }
718
719         if (ropt->filename)
720                 ResetOutput(AH, sav);
721 }
722
723 /***********
724  * BLOB Archival
725  ***********/
726
727 /* Called by a dumper to signal start of a BLOB */
728 int
729 StartBlob(Archive *AHX, Oid oid)
730 {
731         ArchiveHandle *AH = (ArchiveHandle *) AHX;
732
733         if (!AH->StartBlobPtr)
734                 die_horribly(AH, modulename, "large-object output not supported in chosen format\n");
735
736         (*AH->StartBlobPtr) (AH, AH->currToc, oid);
737
738         return 1;
739 }
740
741 /* Called by a dumper to signal end of a BLOB */
742 int
743 EndBlob(Archive *AHX, Oid oid)
744 {
745         ArchiveHandle *AH = (ArchiveHandle *) AHX;
746
747         if (AH->EndBlobPtr)
748                 (*AH->EndBlobPtr) (AH, AH->currToc, oid);
749
750         return 1;
751 }
752
753 /**********
754  * BLOB Restoration
755  **********/
756
757 /*
758  * Called by a format handler before any blobs are restored
759  */
760 void
761 StartRestoreBlobs(ArchiveHandle *AH)
762 {
763         AH->blobCount = 0;
764 }
765
766 /*
767  * Called by a format handler after all blobs are restored
768  */
769 void
770 EndRestoreBlobs(ArchiveHandle *AH)
771 {
772         if (AH->txActive)
773         {
774                 ahlog(AH, 2, "committing large-object transactions\n");
775                 CommitTransaction(AH);
776         }
777
778         if (AH->blobTxActive)
779                 CommitTransactionXref(AH);
780
781         if (AH->createdBlobXref)
782                 CreateBlobXrefIndex(AH);
783
784         ahlog(AH, 1, "restored %d large objects\n", AH->blobCount);
785 }
786
787
788 /*
789  * Called by a format handler to initiate restoration of a blob
790  */
791 void
792 StartRestoreBlob(ArchiveHandle *AH, Oid oid)
793 {
794         Oid                     loOid;
795
796         AH->blobCount++;
797
798         if (!AH->createdBlobXref)
799         {
800                 if (!AH->connection)
801                         die_horribly(AH, modulename, "cannot restore large objects without a database connection\n");
802
803                 CreateBlobXrefTable(AH);
804                 AH->createdBlobXref = 1;
805         }
806
807         /* Initialize the LO Buffer */
808         AH->lo_buf_used = 0;
809
810         /*
811          * Start long-running TXs if necessary
812          */
813         if (!AH->txActive)
814         {
815                 ahlog(AH, 2, "starting large-object transactions\n");
816                 StartTransaction(AH);
817         }
818         if (!AH->blobTxActive)
819                 StartTransactionXref(AH);
820
821         loOid = lo_creat(AH->connection, INV_READ | INV_WRITE);
822         if (loOid == 0)
823                 die_horribly(AH, modulename, "could not create large object\n");
824
825         ahlog(AH, 2, "restoring large object with OID %u as %u\n", oid, loOid);
826
827         InsertBlobXref(AH, oid, loOid);
828
829         AH->loFd = lo_open(AH->connection, loOid, INV_WRITE);
830         if (AH->loFd == -1)
831                 die_horribly(AH, modulename, "could not open large object\n");
832
833         AH->writingBlob = 1;
834 }
835
836 void
837 EndRestoreBlob(ArchiveHandle *AH, Oid oid)
838 {
839         if (AH->lo_buf_used > 0)
840         {
841                 /* Write remaining bytes from the LO buffer */
842                 size_t          res;
843
844                 res = lo_write(AH->connection, AH->loFd, (void *) AH->lo_buf, AH->lo_buf_used);
845
846                 ahlog(AH, 5, "wrote remaining %lu bytes of large-object data (result = %lu)\n",
847                           (unsigned long) AH->lo_buf_used, (unsigned long) res);
848                 if (res != AH->lo_buf_used)
849                         die_horribly(AH, modulename, "could not write to large object (result: %lu, expected: %lu)\n",
850                                    (unsigned long) res, (unsigned long) AH->lo_buf_used);
851                 AH->lo_buf_used = 0;
852         }
853
854         lo_close(AH->connection, AH->loFd);
855         AH->writingBlob = 0;
856
857         /*
858          * Commit every BLOB_BATCH_SIZE blobs...
859          */
860         if (((AH->blobCount / BLOB_BATCH_SIZE) * BLOB_BATCH_SIZE) == AH->blobCount)
861         {
862                 ahlog(AH, 2, "committing large-object transactions\n");
863                 CommitTransaction(AH);
864                 CommitTransactionXref(AH);
865         }
866 }
867
868 /***********
869  * Sorting and Reordering
870  ***********/
871
872 void
873 SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
874 {
875         ArchiveHandle *AH = (ArchiveHandle *) AHX;
876         FILE       *fh;
877         char            buf[1024];
878         char       *cmnt;
879         char       *endptr;
880         DumpId          id;
881         TocEntry   *te;
882         TocEntry   *tePrev;
883
884         /* Allocate space for the 'wanted' array, and init it */
885         ropt->idWanted = (bool *) malloc(sizeof(bool) * AH->maxDumpId);
886         memset(ropt->idWanted, 0, sizeof(bool) * AH->maxDumpId);
887         ropt->limitToList = true;
888
889         /* Set prev entry as head of list */
890         tePrev = AH->toc;
891
892         /* Setup the file */
893         fh = fopen(ropt->tocFile, PG_BINARY_R);
894         if (!fh)
895                 die_horribly(AH, modulename, "could not open TOC file\n");
896
897         while (fgets(buf, 1024, fh) != NULL)
898         {
899                 /* Find a comment */
900                 cmnt = strchr(buf, ';');
901                 if (cmnt == buf)
902                         continue;
903
904                 /* End string at comment */
905                 if (cmnt != NULL)
906                         cmnt[0] = '\0';
907
908                 /* Skip if all spaces */
909                 if (strspn(buf, " \t") == strlen(buf))
910                         continue;
911
912                 /* Get an ID */
913                 id = strtol(buf, &endptr, 10);
914                 if (endptr == buf || id <= 0 || id > AH->maxDumpId)
915                 {
916                         write_msg(modulename, "WARNING: line ignored: %s\n", buf);
917                         continue;
918                 }
919
920                 /* Find TOC entry */
921                 te = getTocEntryByDumpId(AH, id);
922                 if (!te)
923                         die_horribly(AH, modulename, "could not find entry for ID %d\n",
924                                                  id);
925
926                 ropt->idWanted[id - 1] = true;
927
928                 _moveAfter(AH, tePrev, te);
929                 tePrev = te;
930         }
931
932         if (fclose(fh) != 0)
933                 die_horribly(AH, modulename, "could not close TOC file: %s\n",
934                                          strerror(errno));
935 }
936
937 /**********************
938  * 'Convenience functions that look like standard IO functions
939  * for writing data when in dump mode.
940  **********************/
941
942 /* Public */
943 int
944 archputs(const char *s, Archive *AH)
945 {
946         return WriteData(AH, s, strlen(s));
947 }
948
949 /* Public */
950 int
951 archprintf(Archive *AH, const char *fmt,...)
952 {
953         char       *p = NULL;
954         va_list         ap;
955         int                     bSize = strlen(fmt) + 256;
956         int                     cnt = -1;
957
958         /*
959          * This is paranoid: deal with the possibility that vsnprintf is
960          * willing to ignore trailing null or returns > 0 even if string does
961          * not fit. It may be the case that it returns cnt = bufsize
962          */
963         while (cnt < 0 || cnt >= (bSize - 1))
964         {
965                 if (p != NULL)
966                         free(p);
967                 bSize *= 2;
968                 p = (char *) malloc(bSize);
969                 if (p == NULL)
970                         exit_horribly(AH, modulename, "out of memory\n");
971                 va_start(ap, fmt);
972                 cnt = vsnprintf(p, bSize, fmt, ap);
973                 va_end(ap);
974         }
975         WriteData(AH, p, cnt);
976         free(p);
977         return cnt;
978 }
979
980
981 /*******************************
982  * Stuff below here should be 'private' to the archiver routines
983  *******************************/
984
985 OutputContext
986 SetOutput(ArchiveHandle *AH, char *filename, int compression)
987 {
988         OutputContext sav;
989         int                     fn;
990
991         /* Replace the AH output file handle */
992         sav.OF = AH->OF;
993         sav.gzOut = AH->gzOut;
994
995         if (filename)
996                 fn = -1;
997         else if (AH->FH)
998                 fn = fileno(AH->FH);
999         else if (AH->fSpec)
1000         {
1001                 fn = -1;
1002                 filename = AH->fSpec;
1003         }
1004         else
1005                 fn = fileno(stdout);
1006
1007         /* If compression explicitly requested, use gzopen */
1008 #ifdef HAVE_LIBZ
1009         if (compression != 0)
1010         {
1011                 char            fmode[10];
1012
1013                 /* Don't use PG_BINARY_x since this is zlib */
1014                 sprintf(fmode, "wb%d", compression);
1015                 if (fn >= 0)
1016                         AH->OF = gzdopen(dup(fn), fmode);
1017                 else
1018                         AH->OF = gzopen(filename, fmode);
1019                 AH->gzOut = 1;
1020         }
1021         else
1022 #endif
1023         {                                                       /* Use fopen */
1024                 if (fn >= 0)
1025                         AH->OF = fdopen(dup(fn), PG_BINARY_W);
1026                 else
1027                         AH->OF = fopen(filename, PG_BINARY_W);
1028                 AH->gzOut = 0;
1029         }
1030
1031         if (!AH->OF)
1032                 die_horribly(AH, modulename, "could not open output file: %s\n", strerror(errno));
1033
1034         return sav;
1035 }
1036
1037 void
1038 ResetOutput(ArchiveHandle *AH, OutputContext sav)
1039 {
1040         int                     res;
1041
1042         if (AH->gzOut)
1043                 res = GZCLOSE(AH->OF);
1044         else
1045                 res = fclose(AH->OF);
1046
1047         if (res != 0)
1048                 die_horribly(AH, modulename, "could not close output file: %s\n",
1049                                          strerror(errno));
1050
1051         AH->gzOut = sav.gzOut;
1052         AH->OF = sav.OF;
1053 }
1054
1055
1056
1057 /*
1058  *      Print formatted text to the output file (usually stdout).
1059  */
1060 int
1061 ahprintf(ArchiveHandle *AH, const char *fmt,...)
1062 {
1063         char       *p = NULL;
1064         va_list         ap;
1065         int                     bSize = strlen(fmt) + 256;              /* Should be enough */
1066         int                     cnt = -1;
1067
1068         /*
1069          * This is paranoid: deal with the possibility that vsnprintf is
1070          * willing to ignore trailing null
1071          */
1072
1073         /*
1074          * or returns > 0 even if string does not fit. It may be the case that
1075          * it returns cnt = bufsize
1076          */
1077         while (cnt < 0 || cnt >= (bSize - 1))
1078         {
1079                 if (p != NULL)
1080                         free(p);
1081                 bSize *= 2;
1082                 p = (char *) malloc(bSize);
1083                 if (p == NULL)
1084                         die_horribly(AH, modulename, "out of memory\n");
1085                 va_start(ap, fmt);
1086                 cnt = vsnprintf(p, bSize, fmt, ap);
1087                 va_end(ap);
1088         }
1089         ahwrite(p, 1, cnt, AH);
1090         free(p);
1091         return cnt;
1092 }
1093
1094 void
1095 ahlog(ArchiveHandle *AH, int level, const char *fmt,...)
1096 {
1097         va_list         ap;
1098
1099         if (AH->debugLevel < level && (!AH->public.verbose || level > 1))
1100                 return;
1101
1102         va_start(ap, fmt);
1103         _write_msg(NULL, fmt, ap);
1104         va_end(ap);
1105 }
1106
1107 /*
1108  * Single place for logic which says 'We are restoring to a direct DB connection'.
1109  */
1110 int
1111 RestoringToDB(ArchiveHandle *AH)
1112 {
1113         return (AH->ropt && AH->ropt->useDB && AH->connection);
1114 }
1115
1116 /*
1117  *      Write buffer to the output file (usually stdout). This is user for
1118  *      outputting 'restore' scripts etc. It is even possible for an archive
1119  *      format to create a custom output routine to 'fake' a restore if it
1120  *      wants to generate a script (see TAR output).
1121  */
1122 int
1123 ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
1124 {
1125         size_t          res;
1126
1127         if (AH->writingBlob)
1128         {
1129                 if (AH->lo_buf_used + size * nmemb > AH->lo_buf_size)
1130                 {
1131                         /* Split LO buffer */
1132                         size_t          remaining = AH->lo_buf_size - AH->lo_buf_used;
1133                         size_t          slack = nmemb * size - remaining;
1134
1135                         memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining);
1136                         res = lo_write(AH->connection, AH->loFd, AH->lo_buf, AH->lo_buf_size);
1137                         ahlog(AH, 5, "wrote %lu bytes of large object data (result = %lu)\n",
1138                                   (unsigned long) AH->lo_buf_size, (unsigned long) res);
1139                         if (res != AH->lo_buf_size)
1140                                 die_horribly(AH, modulename,
1141                                                          "could not write to large object (result: %lu, expected: %lu)\n",
1142                                    (unsigned long) res, (unsigned long) AH->lo_buf_size);
1143                         memcpy(AH->lo_buf, (char *) ptr + remaining, slack);
1144                         AH->lo_buf_used = slack;
1145                 }
1146                 else
1147                 {
1148                         /* LO Buffer is still large enough, buffer it */
1149                         memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, size * nmemb);
1150                         AH->lo_buf_used += size * nmemb;
1151                 }
1152
1153                 return size * nmemb;
1154         }
1155         else if (AH->gzOut)
1156         {
1157                 res = GZWRITE((void *) ptr, size, nmemb, AH->OF);
1158                 if (res != (nmemb * size))
1159                         die_horribly(AH, modulename, "could not write to compressed archive\n");
1160                 return res;
1161         }
1162         else if (AH->CustomOutPtr)
1163         {
1164                 res = AH->CustomOutPtr (AH, ptr, size * nmemb);
1165
1166                 if (res != (nmemb * size))
1167                         die_horribly(AH, modulename, "could not write to custom output routine\n");
1168                 return res;
1169         }
1170         else
1171         {
1172                 /*
1173                  * If we're doing a restore, and it's direct to DB, and we're
1174                  * connected then send it to the DB.
1175                  */
1176                 if (RestoringToDB(AH))
1177                         return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb);            /* Always 1, currently */
1178                 else
1179                 {
1180                         res = fwrite((void *) ptr, size, nmemb, AH->OF);
1181                         if (res != nmemb)
1182                                 die_horribly(AH, modulename, "could not write to output file (%lu != %lu)\n",
1183                                                          (unsigned long) res, (unsigned long) nmemb);
1184                         return res;
1185                 }
1186         }
1187 }
1188
1189 /* Common exit code */
1190 static void
1191 _write_msg(const char *modulename, const char *fmt, va_list ap)
1192 {
1193         if (modulename)
1194                 fprintf(stderr, "%s: [%s] ", progname, gettext(modulename));
1195         else
1196                 fprintf(stderr, "%s: ", progname);
1197         vfprintf(stderr, gettext(fmt), ap);
1198 }
1199
1200 void
1201 write_msg(const char *modulename, const char *fmt,...)
1202 {
1203         va_list         ap;
1204
1205         va_start(ap, fmt);
1206         _write_msg(modulename, fmt, ap);
1207         va_end(ap);
1208 }
1209
1210
1211 static void
1212 _die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt, va_list ap)
1213 {
1214         _write_msg(modulename, fmt, ap);
1215
1216         if (AH)
1217         {
1218                 if (AH->public.verbose)
1219                         write_msg(NULL, "*** aborted because of error\n");
1220                 if (AH->connection)
1221                         PQfinish(AH->connection);
1222                 if (AH->blobConnection)
1223                         PQfinish(AH->blobConnection);
1224         }
1225
1226         exit(1);
1227 }
1228
1229 /* External use */
1230 void
1231 exit_horribly(Archive *AH, const char *modulename, const char *fmt,...)
1232 {
1233         va_list         ap;
1234
1235         va_start(ap, fmt);
1236         _die_horribly((ArchiveHandle *) AH, modulename, fmt, ap);
1237         va_end(ap);
1238 }
1239
1240 /* Archiver use (just different arg declaration) */
1241 void
1242 die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...)
1243 {
1244         va_list         ap;
1245
1246         va_start(ap, fmt);
1247         _die_horribly(AH, modulename, fmt, ap);
1248         va_end(ap);
1249 }
1250
1251 /* on some error, we may decide to go on... */
1252 void
1253 warn_or_die_horribly(ArchiveHandle *AH,
1254                                          const char *modulename, const char *fmt,...)
1255 {
1256         va_list         ap;
1257
1258         switch (AH->stage)
1259         {
1260
1261                 case STAGE_NONE:
1262                         /* Do nothing special */
1263                         break;
1264
1265                 case STAGE_INITIALIZING:
1266                         if (AH->stage != AH->lastErrorStage)
1267                                 write_msg(modulename, "Error while INITIALIZING:\n");
1268                         break;
1269
1270                 case STAGE_PROCESSING:
1271                         if (AH->stage != AH->lastErrorStage)
1272                                 write_msg(modulename, "Error while PROCESSING TOC:\n");
1273                         break;
1274
1275                 case STAGE_FINALIZING:
1276                         if (AH->stage != AH->lastErrorStage)
1277                                 write_msg(modulename, "Error while FINALIZING:\n");
1278                         break;
1279         }
1280         if (AH->currentTE != NULL && AH->currentTE != AH->lastErrorTE)
1281         {
1282                 write_msg(modulename, "Error from TOC entry %d; %u %u %s %s %s\n", AH->currentTE->dumpId,
1283                  AH->currentTE->catalogId.tableoid, AH->currentTE->catalogId.oid,
1284                   AH->currentTE->desc, AH->currentTE->tag, AH->currentTE->owner);
1285         }
1286         AH->lastErrorStage = AH->stage;
1287         AH->lastErrorTE = AH->currentTE;
1288
1289         va_start(ap, fmt);
1290         if (AH->public.exit_on_error)
1291                 _die_horribly(AH, modulename, fmt, ap);
1292         else
1293         {
1294                 _write_msg(modulename, fmt, ap);
1295                 AH->public.n_errors++;
1296         }
1297         va_end(ap);
1298 }
1299
1300 static void
1301 _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
1302 {
1303         te->prev->next = te->next;
1304         te->next->prev = te->prev;
1305
1306         te->prev = pos;
1307         te->next = pos->next;
1308
1309         pos->next->prev = te;
1310         pos->next = te;
1311 }
1312
1313 #ifdef NOT_USED
1314
1315 static void
1316 _moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
1317 {
1318         te->prev->next = te->next;
1319         te->next->prev = te->prev;
1320
1321         te->prev = pos->prev;
1322         te->next = pos;
1323         pos->prev->next = te;
1324         pos->prev = te;
1325 }
1326 #endif
1327
1328 static TocEntry *
1329 getTocEntryByDumpId(ArchiveHandle *AH, DumpId id)
1330 {
1331         TocEntry   *te;
1332
1333         te = AH->toc->next;
1334         while (te != AH->toc)
1335         {
1336                 if (te->dumpId == id)
1337                         return te;
1338                 te = te->next;
1339         }
1340         return NULL;
1341 }
1342
1343 int
1344 TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
1345 {
1346         TocEntry   *te = getTocEntryByDumpId(AH, id);
1347
1348         if (!te)
1349                 return 0;
1350
1351         return _tocEntryRequired(te, ropt, false);
1352 }
1353
1354 size_t
1355 WriteOffset(ArchiveHandle *AH, off_t o, int wasSet)
1356 {
1357         int                     off;
1358
1359         /* Save the flag */
1360         (*AH->WriteBytePtr) (AH, wasSet);
1361
1362         /* Write out off_t smallest byte first, prevents endian mismatch */
1363         for (off = 0; off < sizeof(off_t); off++)
1364         {
1365                 (*AH->WriteBytePtr) (AH, o & 0xFF);
1366                 o >>= 8;
1367         }
1368         return sizeof(off_t) + 1;
1369 }
1370
1371 int
1372 ReadOffset(ArchiveHandle *AH, off_t *o)
1373 {
1374         int                     i;
1375         int                     off;
1376         int                     offsetFlg;
1377
1378         /* Initialize to zero */
1379         *o = 0;
1380
1381         /* Check for old version */
1382         if (AH->version < K_VERS_1_7)
1383         {
1384                 /* Prior versions wrote offsets using WriteInt */
1385                 i = ReadInt(AH);
1386                 /* -1 means not set */
1387                 if (i < 0)
1388                         return K_OFFSET_POS_NOT_SET;
1389                 else if (i == 0)
1390                         return K_OFFSET_NO_DATA;
1391
1392                 /* Cast to off_t because it was written as an int. */
1393                 *o = (off_t) i;
1394                 return K_OFFSET_POS_SET;
1395         }
1396
1397         /*
1398          * Read the flag indicating the state of the data pointer. Check if
1399          * valid and die if not.
1400          *
1401          * This used to be handled by a negative or zero pointer, now we use an
1402          * extra byte specifically for the state.
1403          */
1404         offsetFlg = (*AH->ReadBytePtr) (AH) & 0xFF;
1405
1406         switch (offsetFlg)
1407         {
1408                 case K_OFFSET_POS_NOT_SET:
1409                 case K_OFFSET_NO_DATA:
1410                 case K_OFFSET_POS_SET:
1411
1412                         break;
1413
1414                 default:
1415                         die_horribly(AH, modulename, "Unexpected data offset flag %d\n", offsetFlg);
1416         }
1417
1418         /*
1419          * Read the bytes
1420          */
1421         for (off = 0; off < AH->offSize; off++)
1422         {
1423                 if (off < sizeof(off_t))
1424                         *o |= ((off_t) ((*AH->ReadBytePtr) (AH))) << (off * 8);
1425                 else
1426                 {
1427                         if ((*AH->ReadBytePtr) (AH) != 0)
1428                                 die_horribly(AH, modulename, "file offset in dump file is too large\n");
1429                 }
1430         }
1431
1432         return offsetFlg;
1433 }
1434
1435 size_t
1436 WriteInt(ArchiveHandle *AH, int i)
1437 {
1438         int                     b;
1439
1440         /*
1441          * This is a bit yucky, but I don't want to make the binary format
1442          * very dependent on representation, and not knowing much about it, I
1443          * write out a sign byte. If you change this, don't forget to change
1444          * the file version #, and modify readInt to read the new format AS
1445          * WELL AS the old formats.
1446          */
1447
1448         /* SIGN byte */
1449         if (i < 0)
1450         {
1451                 (*AH->WriteBytePtr) (AH, 1);
1452                 i = -i;
1453         }
1454         else
1455                 (*AH->WriteBytePtr) (AH, 0);
1456
1457         for (b = 0; b < AH->intSize; b++)
1458         {
1459                 (*AH->WriteBytePtr) (AH, i & 0xFF);
1460                 i >>= 8;
1461         }
1462
1463         return AH->intSize + 1;
1464 }
1465
1466 int
1467 ReadInt(ArchiveHandle *AH)
1468 {
1469         int                     res = 0;
1470         int                     bv,
1471                                 b;
1472         int                     sign = 0;               /* Default positive */
1473         int                     bitShift = 0;
1474
1475         if (AH->version > K_VERS_1_0)
1476                 /* Read a sign byte */
1477                 sign = (*AH->ReadBytePtr) (AH);
1478
1479         for (b = 0; b < AH->intSize; b++)
1480         {
1481                 bv = (*AH->ReadBytePtr) (AH) & 0xFF;
1482                 if (bv != 0)
1483                         res = res + (bv << bitShift);
1484                 bitShift += 8;
1485         }
1486
1487         if (sign)
1488                 res = -res;
1489
1490         return res;
1491 }
1492
1493 size_t
1494 WriteStr(ArchiveHandle *AH, const char *c)
1495 {
1496         size_t          res;
1497
1498         if (c)
1499         {
1500                 res = WriteInt(AH, strlen(c));
1501                 res += (*AH->WriteBufPtr) (AH, c, strlen(c));
1502         }
1503         else
1504                 res = WriteInt(AH, -1);
1505
1506         return res;
1507 }
1508
1509 char *
1510 ReadStr(ArchiveHandle *AH)
1511 {
1512         char       *buf;
1513         int                     l;
1514
1515         l = ReadInt(AH);
1516         if (l == -1)
1517                 buf = NULL;
1518         else
1519         {
1520                 buf = (char *) malloc(l + 1);
1521                 if (!buf)
1522                         die_horribly(AH, modulename, "out of memory\n");
1523
1524                 (*AH->ReadBufPtr) (AH, (void *) buf, l);
1525                 buf[l] = '\0';
1526         }
1527
1528         return buf;
1529 }
1530
1531 static int
1532 _discoverArchiveFormat(ArchiveHandle *AH)
1533 {
1534         FILE       *fh;
1535         char            sig[6];                 /* More than enough */
1536         size_t          cnt;
1537         int                     wantClose = 0;
1538
1539 #if 0
1540         write_msg(modulename, "attempting to ascertain archive format\n");
1541 #endif
1542
1543         if (AH->lookahead)
1544                 free(AH->lookahead);
1545
1546         AH->lookaheadSize = 512;
1547         AH->lookahead = calloc(1, 512);
1548         AH->lookaheadLen = 0;
1549         AH->lookaheadPos = 0;
1550
1551         if (AH->fSpec)
1552         {
1553                 wantClose = 1;
1554                 fh = fopen(AH->fSpec, PG_BINARY_R);
1555         }
1556         else
1557                 fh = stdin;
1558
1559         if (!fh)
1560                 die_horribly(AH, modulename, "could not open input file: %s\n", strerror(errno));
1561
1562         cnt = fread(sig, 1, 5, fh);
1563
1564         if (cnt != 5)
1565         {
1566                 if (ferror(fh))
1567                         die_horribly(AH, modulename, "could not read input file: %s\n", strerror(errno));
1568                 else
1569                         die_horribly(AH, modulename, "input file is too short (read %lu, expected 5)\n",
1570                                                  (unsigned long) cnt);
1571         }
1572
1573         /* Save it, just in case we need it later */
1574         strncpy(&AH->lookahead[0], sig, 5);
1575         AH->lookaheadLen = 5;
1576
1577         if (strncmp(sig, "PGDMP", 5) == 0)
1578         {
1579                 AH->vmaj = fgetc(fh);
1580                 AH->vmin = fgetc(fh);
1581
1582                 /* Save these too... */
1583                 AH->lookahead[AH->lookaheadLen++] = AH->vmaj;
1584                 AH->lookahead[AH->lookaheadLen++] = AH->vmin;
1585
1586                 /* Check header version; varies from V1.0 */
1587                 if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))                /* Version > 1.0 */
1588                 {
1589                         AH->vrev = fgetc(fh);
1590                         AH->lookahead[AH->lookaheadLen++] = AH->vrev;
1591                 }
1592                 else
1593                         AH->vrev = 0;
1594
1595                 /* Make a convenient integer <maj><min><rev>00 */
1596                 AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
1597
1598                 AH->intSize = fgetc(fh);
1599                 AH->lookahead[AH->lookaheadLen++] = AH->intSize;
1600
1601                 if (AH->version >= K_VERS_1_7)
1602                 {
1603                         AH->offSize = fgetc(fh);
1604                         AH->lookahead[AH->lookaheadLen++] = AH->offSize;
1605                 }
1606                 else
1607                         AH->offSize = AH->intSize;
1608
1609                 AH->format = fgetc(fh);
1610                 AH->lookahead[AH->lookaheadLen++] = AH->format;
1611         }
1612         else
1613         {
1614                 /*
1615                  * *Maybe* we have a tar archive format file... So, read first 512
1616                  * byte header...
1617                  */
1618                 cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh);
1619                 AH->lookaheadLen += cnt;
1620
1621                 if (AH->lookaheadLen != 512)
1622                         die_horribly(AH, modulename, "input file does not appear to be a valid archive (too short?)\n");
1623
1624                 if (!isValidTarHeader(AH->lookahead))
1625                         die_horribly(AH, modulename, "input file does not appear to be a valid archive\n");
1626
1627                 AH->format = archTar;
1628         }
1629
1630         /* If we can't seek, then mark the header as read */
1631         if (fseeko(fh, 0, SEEK_SET) != 0)
1632         {
1633                 /*
1634                  * NOTE: Formats that use the lookahead buffer can unset this in
1635                  * their Init routine.
1636                  */
1637                 AH->readHeader = 1;
1638         }
1639         else
1640                 AH->lookaheadLen = 0;   /* Don't bother since we've reset the file */
1641
1642 #if 0
1643         write_msg(modulename, "read %lu bytes into lookahead buffer\n",
1644                           (unsigned long) AH->lookaheadLen);
1645 #endif
1646
1647         /* Close the file */
1648         if (wantClose)
1649                 if (fclose(fh) != 0)
1650                         die_horribly(AH, modulename, "could not close the input file after reading header: %s\n",
1651                                                  strerror(errno));
1652
1653         return AH->format;
1654 }
1655
1656
1657 /*
1658  * Allocate an archive handle
1659  */
1660 static ArchiveHandle *
1661 _allocAH(const char *FileSpec, const ArchiveFormat fmt,
1662                  const int compression, ArchiveMode mode)
1663 {
1664         ArchiveHandle *AH;
1665
1666 #if 0
1667         write_msg(modulename, "allocating AH for %s, format %d\n", FileSpec, fmt);
1668 #endif
1669
1670         AH = (ArchiveHandle *) calloc(1, sizeof(ArchiveHandle));
1671         if (!AH)
1672                 die_horribly(AH, modulename, "out of memory\n");
1673
1674         /* AH->debugLevel = 100; */
1675
1676         AH->vmaj = K_VERS_MAJOR;
1677         AH->vmin = K_VERS_MINOR;
1678         AH->vrev = K_VERS_REV;
1679
1680         AH->createDate = time(NULL);
1681
1682         AH->intSize = sizeof(int);
1683         AH->offSize = sizeof(off_t);
1684         if (FileSpec)
1685         {
1686                 AH->fSpec = strdup(FileSpec);
1687
1688                 /*
1689                  * Not used; maybe later....
1690                  *
1691                  * AH->workDir = strdup(FileSpec); for(i=strlen(FileSpec) ; i > 0 ;
1692                  * i--) if (AH->workDir[i-1] == '/')
1693                  */
1694         }
1695         else
1696                 AH->fSpec = NULL;
1697
1698         AH->currUser = strdup("");      /* So it's valid, but we can free() it
1699                                                                  * later if necessary */
1700         AH->currSchema = strdup("");    /* ditto */
1701         AH->currWithOids = -1;          /* force SET */
1702
1703         AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry));
1704         if (!AH->toc)
1705                 die_horribly(AH, modulename, "out of memory\n");
1706
1707         AH->toc->next = AH->toc;
1708         AH->toc->prev = AH->toc;
1709
1710         AH->mode = mode;
1711         AH->compression = compression;
1712
1713         AH->pgCopyBuf = createPQExpBuffer();
1714         AH->sqlBuf = createPQExpBuffer();
1715
1716         /* Open stdout with no compression for AH output handle */
1717         AH->gzOut = 0;
1718         AH->OF = stdout;
1719
1720 #if 0
1721         write_msg(modulename, "archive format is %d\n", fmt);
1722 #endif
1723
1724         if (fmt == archUnknown)
1725                 AH->format = _discoverArchiveFormat(AH);
1726         else
1727                 AH->format = fmt;
1728
1729         switch (AH->format)
1730         {
1731
1732                 case archCustom:
1733                         InitArchiveFmt_Custom(AH);
1734                         break;
1735
1736                 case archFiles:
1737                         InitArchiveFmt_Files(AH);
1738                         break;
1739
1740                 case archNull:
1741                         InitArchiveFmt_Null(AH);
1742                         break;
1743
1744                 case archTar:
1745                         InitArchiveFmt_Tar(AH);
1746                         break;
1747
1748                 default:
1749                         die_horribly(AH, modulename, "unrecognized file format \"%d\"\n", fmt);
1750         }
1751
1752         /* sql error handling */
1753         AH->public.exit_on_error = true;
1754         AH->public.n_errors = 0;
1755
1756         return AH;
1757 }
1758
1759
1760 void
1761 WriteDataChunks(ArchiveHandle *AH)
1762 {
1763         TocEntry   *te = AH->toc->next;
1764         StartDataPtr startPtr;
1765         EndDataPtr      endPtr;
1766
1767         while (te != AH->toc)
1768         {
1769                 if (te->dataDumper != NULL)
1770                 {
1771                         AH->currToc = te;
1772                         /* printf("Writing data for %d (%x)\n", te->id, te); */
1773
1774                         if (strcmp(te->desc, "BLOBS") == 0)
1775                         {
1776                                 startPtr = AH->StartBlobsPtr;
1777                                 endPtr = AH->EndBlobsPtr;
1778                         }
1779                         else
1780                         {
1781                                 startPtr = AH->StartDataPtr;
1782                                 endPtr = AH->EndDataPtr;
1783                         }
1784
1785                         if (startPtr != NULL)
1786                                 (*startPtr) (AH, te);
1787
1788                         /*
1789                          * printf("Dumper arg for %d is %x\n", te->id,
1790                          * te->dataDumperArg);
1791                          */
1792
1793                         /*
1794                          * The user-provided DataDumper routine needs to call
1795                          * AH->WriteData
1796                          */
1797                         (*te->dataDumper) ((Archive *) AH, te->dataDumperArg);
1798
1799                         if (endPtr != NULL)
1800                                 (*endPtr) (AH, te);
1801                         AH->currToc = NULL;
1802                 }
1803                 te = te->next;
1804         }
1805 }
1806
1807 void
1808 WriteToc(ArchiveHandle *AH)
1809 {
1810         TocEntry   *te;
1811         char            workbuf[32];
1812         int                     i;
1813
1814         /* printf("%d TOC Entries to save\n", AH->tocCount); */
1815
1816         WriteInt(AH, AH->tocCount);
1817
1818         for (te = AH->toc->next; te != AH->toc; te = te->next)
1819         {
1820                 WriteInt(AH, te->dumpId);
1821                 WriteInt(AH, te->dataDumper ? 1 : 0);
1822
1823                 /* OID is recorded as a string for historical reasons */
1824                 sprintf(workbuf, "%u", te->catalogId.tableoid);
1825                 WriteStr(AH, workbuf);
1826                 sprintf(workbuf, "%u", te->catalogId.oid);
1827                 WriteStr(AH, workbuf);
1828
1829                 WriteStr(AH, te->tag);
1830                 WriteStr(AH, te->desc);
1831                 WriteStr(AH, te->defn);
1832                 WriteStr(AH, te->dropStmt);
1833                 WriteStr(AH, te->copyStmt);
1834                 WriteStr(AH, te->namespace);
1835                 WriteStr(AH, te->tablespace);
1836                 WriteStr(AH, te->owner);
1837                 WriteStr(AH, te->withOids ? "true" : "false");
1838
1839                 /* Dump list of dependencies */
1840                 for (i = 0; i < te->nDeps; i++)
1841                 {
1842                         sprintf(workbuf, "%d", te->dependencies[i]);
1843                         WriteStr(AH, workbuf);
1844                 }
1845                 WriteStr(AH, NULL);             /* Terminate List */
1846
1847                 if (AH->WriteExtraTocPtr)
1848                         (*AH->WriteExtraTocPtr) (AH, te);
1849         }
1850 }
1851
1852 void
1853 ReadToc(ArchiveHandle *AH)
1854 {
1855         int                     i;
1856         char       *tmp;
1857         DumpId     *deps;
1858         int                     depIdx;
1859         int                     depSize;
1860
1861         TocEntry   *te = AH->toc->next;
1862
1863         AH->tocCount = ReadInt(AH);
1864         AH->maxDumpId = 0;
1865
1866         for (i = 0; i < AH->tocCount; i++)
1867         {
1868                 te = (TocEntry *) calloc(1, sizeof(TocEntry));
1869                 te->dumpId = ReadInt(AH);
1870
1871                 if (te->dumpId > AH->maxDumpId)
1872                         AH->maxDumpId = te->dumpId;
1873
1874                 /* Sanity check */
1875                 if (te->dumpId <= 0)
1876                         die_horribly(AH, modulename,
1877                                    "entry ID %d out of range -- perhaps a corrupt TOC\n",
1878                                                  te->dumpId);
1879
1880                 te->hadDumper = ReadInt(AH);
1881
1882                 if (AH->version >= K_VERS_1_8)
1883                 {
1884                         tmp = ReadStr(AH);
1885                         sscanf(tmp, "%u", &te->catalogId.tableoid);
1886                         free(tmp);
1887                 }
1888                 else
1889                         te->catalogId.tableoid = InvalidOid;
1890                 tmp = ReadStr(AH);
1891                 sscanf(tmp, "%u", &te->catalogId.oid);
1892                 free(tmp);
1893
1894                 te->tag = ReadStr(AH);
1895                 te->desc = ReadStr(AH);
1896                 te->defn = ReadStr(AH);
1897                 te->dropStmt = ReadStr(AH);
1898
1899                 if (AH->version >= K_VERS_1_3)
1900                         te->copyStmt = ReadStr(AH);
1901
1902                 if (AH->version >= K_VERS_1_6)
1903                         te->namespace = ReadStr(AH);
1904
1905                 if (AH->version >= K_VERS_1_10)
1906                         te->tablespace = ReadStr(AH);
1907
1908                 te->owner = ReadStr(AH);
1909                 if (AH->version >= K_VERS_1_9)
1910                 {
1911                         if (strcmp(ReadStr(AH), "true") == 0)
1912                                 te->withOids = true;
1913                         else
1914                                 te->withOids = false;
1915                 }
1916                 else
1917                         te->withOids = true;
1918
1919                 /* Read TOC entry dependencies */
1920                 if (AH->version >= K_VERS_1_5)
1921                 {
1922                         depSize = 100;
1923                         deps = (DumpId *) malloc(sizeof(DumpId) * depSize);
1924                         depIdx = 0;
1925                         for (;;)
1926                         {
1927                                 tmp = ReadStr(AH);
1928                                 if (!tmp)
1929                                         break;          /* end of list */
1930                                 if (depIdx >= depSize)
1931                                 {
1932                                         depSize *= 2;
1933                                         deps = (DumpId *) realloc(deps, sizeof(DumpId) * depSize);
1934                                 }
1935                                 sscanf(tmp, "%d", &deps[depIdx]);
1936                                 free(tmp);
1937                                 depIdx++;
1938                         }
1939
1940                         if (depIdx > 0)         /* We have a non-null entry */
1941                         {
1942                                 deps = (DumpId *) realloc(deps, sizeof(DumpId) * depIdx);
1943                                 te->dependencies = deps;
1944                                 te->nDeps = depIdx;
1945                         }
1946                         else
1947                         {
1948                                 free(deps);
1949                                 te->dependencies = NULL;
1950                                 te->nDeps = 0;
1951                         }
1952                 }
1953                 else
1954                 {
1955                         te->dependencies = NULL;
1956                         te->nDeps = 0;
1957                 }
1958
1959                 if (AH->ReadExtraTocPtr)
1960                         (*AH->ReadExtraTocPtr) (AH, te);
1961
1962                 ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n",
1963                           i, te->dumpId, te->desc, te->tag);
1964
1965                 te->prev = AH->toc->prev;
1966                 AH->toc->prev->next = te;
1967                 AH->toc->prev = te;
1968                 te->next = AH->toc;
1969         }
1970 }
1971
1972 static teReqs
1973 _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool acl_pass)
1974 {
1975         teReqs          res = 3;                /* Schema = 1, Data = 2, Both = 3 */
1976
1977         /* ENCODING objects are dumped specially, so always reject here */
1978         if (strcmp(te->desc, "ENCODING") == 0)
1979                 return 0;
1980
1981         /* If it's an ACL, maybe ignore it */
1982         if ((!acl_pass || ropt->aclsSkip) && strcmp(te->desc, "ACL") == 0)
1983                 return 0;
1984
1985         if (!ropt->create && strcmp(te->desc, "DATABASE") == 0)
1986                 return 0;
1987
1988         /* Check if tablename only is wanted */
1989         if (ropt->selTypes)
1990         {
1991                 if ((strcmp(te->desc, "TABLE") == 0) || (strcmp(te->desc, "TABLE DATA") == 0))
1992                 {
1993                         if (!ropt->selTable)
1994                                 return 0;
1995                         if (ropt->tableNames && strcmp(ropt->tableNames, te->tag) != 0)
1996                                 return 0;
1997                 }
1998                 else if (strcmp(te->desc, "INDEX") == 0)
1999                 {
2000                         if (!ropt->selIndex)
2001                                 return 0;
2002                         if (ropt->indexNames && strcmp(ropt->indexNames, te->tag) != 0)
2003                                 return 0;
2004                 }
2005                 else if (strcmp(te->desc, "FUNCTION") == 0)
2006                 {
2007                         if (!ropt->selFunction)
2008                                 return 0;
2009                         if (ropt->functionNames && strcmp(ropt->functionNames, te->tag) != 0)
2010                                 return 0;
2011                 }
2012                 else if (strcmp(te->desc, "TRIGGER") == 0)
2013                 {
2014                         if (!ropt->selTrigger)
2015                                 return 0;
2016                         if (ropt->triggerNames && strcmp(ropt->triggerNames, te->tag) != 0)
2017                                 return 0;
2018                 }
2019                 else
2020                         return 0;
2021         }
2022
2023         /*
2024          * Check if we had a dataDumper. Indicates if the entry is schema or
2025          * data
2026          */
2027         if (!te->hadDumper)
2028         {
2029                 /*
2030                  * Special Case: If 'SEQUENCE SET' then it is considered a data
2031                  * entry
2032                  */
2033                 if (strcmp(te->desc, "SEQUENCE SET") == 0)
2034                         res = res & REQ_DATA;
2035                 else
2036                         res = res & ~REQ_DATA;
2037         }
2038
2039         /*
2040          * Special case: <Init> type with <Max OID> tag; this is part of a
2041          * DATA restore even though it has SQL.
2042          */
2043         if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
2044                 res = REQ_DATA;
2045
2046         /* Mask it if we only want schema */
2047         if (ropt->schemaOnly)
2048                 res = res & REQ_SCHEMA;
2049
2050         /* Mask it we only want data */
2051         if (ropt->dataOnly)
2052                 res = res & REQ_DATA;
2053
2054         /* Mask it if we don't have a schema contribution */
2055         if (!te->defn || strlen(te->defn) == 0)
2056                 res = res & ~REQ_SCHEMA;
2057
2058         /* Finally, if we used a list, limit based on that as well */
2059         if (ropt->limitToList && !ropt->idWanted[te->dumpId - 1])
2060                 return 0;
2061
2062         return res;
2063 }
2064
2065 /*
2066  * Issue SET commands for parameters that we want to have set the same way
2067  * at all times during execution of a restore script.
2068  */
2069 static void
2070 _doSetFixedOutputState(ArchiveHandle *AH)
2071 {
2072         TocEntry   *te;
2073
2074         /* If we have an encoding setting, emit that */
2075         te = AH->toc->next;
2076         while (te != AH->toc)
2077         {
2078                 if (strcmp(te->desc, "ENCODING") == 0)
2079                 {
2080                         ahprintf(AH, "%s", te->defn);
2081                         break;
2082                 }
2083                 te = te->next;
2084         }
2085
2086         /* Make sure function checking is disabled */
2087         ahprintf(AH, "SET check_function_bodies = false;\n");
2088
2089         /* Avoid annoying notices etc */
2090         ahprintf(AH, "SET client_min_messages = warning;\n");
2091
2092         ahprintf(AH, "\n");
2093 }
2094
2095 /*
2096  * Issue a SET SESSION AUTHORIZATION command.  Caller is responsible
2097  * for updating state if appropriate.  If user is NULL or an empty string,
2098  * the specification DEFAULT will be used.
2099  */
2100 static void
2101 _doSetSessionAuth(ArchiveHandle *AH, const char *user)
2102 {
2103         PQExpBuffer cmd = createPQExpBuffer();
2104
2105         appendPQExpBuffer(cmd, "SET SESSION AUTHORIZATION ");
2106
2107         /*
2108          * SQL requires a string literal here.  Might as well be correct.
2109          */
2110         if (user && *user)
2111                 appendStringLiteral(cmd, user, false);
2112         else
2113                 appendPQExpBuffer(cmd, "DEFAULT");
2114         appendPQExpBuffer(cmd, ";");
2115
2116         if (RestoringToDB(AH))
2117         {
2118                 PGresult   *res;
2119
2120                 res = PQexec(AH->connection, cmd->data);
2121
2122                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2123                         /* NOT warn_or_die_horribly... use -O instead to skip this. */
2124                         die_horribly(AH, modulename, "could not set session user to \"%s\": %s",
2125                                                  user, PQerrorMessage(AH->connection));
2126
2127                 PQclear(res);
2128         }
2129         else
2130                 ahprintf(AH, "%s\n\n", cmd->data);
2131
2132         destroyPQExpBuffer(cmd);
2133 }
2134
2135
2136 /*
2137  * Issue a SET default_with_oids command.  Caller is responsible
2138  * for updating state if appropriate.
2139  */
2140 static void
2141 _doSetWithOids(ArchiveHandle *AH, const bool withOids)
2142 {
2143         PQExpBuffer cmd = createPQExpBuffer();
2144
2145         appendPQExpBuffer(cmd, "SET default_with_oids = %s;", withOids ?
2146                                           "true" : "false");
2147
2148         if (RestoringToDB(AH))
2149         {
2150                 PGresult   *res;
2151
2152                 res = PQexec(AH->connection, cmd->data);
2153
2154                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2155                         warn_or_die_horribly(AH, modulename,
2156                                                                  "could not set default_with_oids: %s",
2157                                                                  PQerrorMessage(AH->connection));
2158
2159                 PQclear(res);
2160         }
2161         else
2162                 ahprintf(AH, "%s\n\n", cmd->data);
2163
2164         destroyPQExpBuffer(cmd);
2165 }
2166
2167
2168 /*
2169  * Issue the commands to connect to the specified database.
2170  *
2171  * If we're currently restoring right into a database, this will
2172  * actually establish a connection. Otherwise it puts a \connect into
2173  * the script output.
2174  *
2175  * NULL dbname implies reconnecting to the current DB (pretty useless).
2176  */
2177 static void
2178 _reconnectToDB(ArchiveHandle *AH, const char *dbname)
2179 {
2180         if (RestoringToDB(AH))
2181                 ReconnectToServer(AH, dbname, NULL);
2182         else
2183         {
2184                 PQExpBuffer qry = createPQExpBuffer();
2185
2186                 appendPQExpBuffer(qry, "\\connect %s\n\n",
2187                                                   dbname ? fmtId(dbname) : "-");
2188
2189                 ahprintf(AH, qry->data);
2190
2191                 destroyPQExpBuffer(qry);
2192         }
2193
2194         /*
2195          * NOTE: currUser keeps track of what the imaginary session user in
2196          * our script is.  It's now effectively reset to the original userID.
2197          */
2198         if (AH->currUser)
2199                 free(AH->currUser);
2200
2201         AH->currUser = strdup("");
2202
2203         /* don't assume we still know the output schema */
2204         if (AH->currSchema)
2205                 free(AH->currSchema);
2206         AH->currSchema = strdup("");
2207         AH->currWithOids = -1;
2208
2209         /* re-establish fixed state */
2210         _doSetFixedOutputState(AH);
2211 }
2212
2213 /*
2214  * Become the specified user, and update state to avoid redundant commands
2215  *
2216  * NULL or empty argument is taken to mean restoring the session default
2217  */
2218 static void
2219 _becomeUser(ArchiveHandle *AH, const char *user)
2220 {
2221         if (!user)
2222                 user = "";                              /* avoid null pointers */
2223
2224         if (AH->currUser && strcmp(AH->currUser, user) == 0)
2225                 return;                                 /* no need to do anything */
2226
2227         _doSetSessionAuth(AH, user);
2228
2229         /*
2230          * NOTE: currUser keeps track of what the imaginary session user in
2231          * our script is
2232          */
2233         if (AH->currUser)
2234                 free(AH->currUser);
2235
2236         AH->currUser = strdup(user);
2237 }
2238
2239 /*
2240  * Become the owner of the the given TOC entry object.  If
2241  * changes in ownership are not allowed, this doesn't do anything.
2242  */
2243 static void
2244 _becomeOwner(ArchiveHandle *AH, TocEntry *te)
2245 {
2246         if (AH->ropt && (AH->ropt->noOwner || !AH->ropt->use_setsessauth))
2247                 return;
2248
2249         _becomeUser(AH, te->owner);
2250 }
2251
2252
2253 /*
2254  * Set the proper default_with_oids value for the table.
2255  */
2256 static void
2257 _setWithOids(ArchiveHandle *AH, TocEntry *te)
2258 {
2259         if (AH->currWithOids != te->withOids)
2260         {
2261                 _doSetWithOids(AH, te->withOids);
2262                 AH->currWithOids = te->withOids;
2263         }
2264 }
2265
2266
2267 /*
2268  * Issue the commands to select the specified schema as the current schema
2269  * in the target database.
2270  */
2271 static void
2272 _selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
2273 {
2274         PQExpBuffer qry;
2275
2276         if (!schemaName || *schemaName == '\0' ||
2277                 strcmp(AH->currSchema, schemaName) == 0)
2278                 return;                                 /* no need to do anything */
2279
2280         qry = createPQExpBuffer();
2281
2282         appendPQExpBuffer(qry, "SET search_path = %s",
2283                                           fmtId(schemaName));
2284         if (strcmp(schemaName, "pg_catalog") != 0)
2285                 appendPQExpBuffer(qry, ", pg_catalog");
2286
2287         if (RestoringToDB(AH))
2288         {
2289                 PGresult   *res;
2290
2291                 res = PQexec(AH->connection, qry->data);
2292
2293                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2294                         warn_or_die_horribly(AH, modulename,
2295                                                            "could not set search_path to \"%s\": %s",
2296                                                          schemaName, PQerrorMessage(AH->connection));
2297
2298                 PQclear(res);
2299         }
2300         else
2301                 ahprintf(AH, "%s;\n\n", qry->data);
2302
2303         if (AH->currSchema)
2304                 free(AH->currSchema);
2305         AH->currSchema = strdup(schemaName);
2306
2307         destroyPQExpBuffer(qry);
2308 }
2309
2310 /*
2311  * Issue the commands to select the specified tablespace as the current one
2312  * in the target database.
2313  */
2314 static void
2315 _selectTablespace(ArchiveHandle *AH, const char *tablespace)
2316 {
2317         PQExpBuffer qry;
2318         const char      *want, *have;
2319
2320         have = AH->currTablespace;
2321         want = tablespace;
2322
2323         /* no need to do anything for non-tablespace object */
2324         if (!want)
2325                 return;
2326
2327         if (have && strcmp(want, have) == 0)
2328                 return;                                 /* no need to do anything */
2329
2330         qry = createPQExpBuffer();
2331
2332         if (strcmp(want, "") == 0)
2333         {
2334                 /* We want the tablespace to be the database's default */
2335                 appendPQExpBuffer(qry, "SET default_tablespace = ''");
2336         }
2337         else
2338         {
2339                 /* We want an explicit tablespace */
2340                 appendPQExpBuffer(qry, "SET default_tablespace = %s", fmtId(want));
2341         }
2342
2343         if (RestoringToDB(AH))
2344         {
2345                 PGresult   *res;
2346
2347                 res = PQexec(AH->connection, qry->data);
2348
2349                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2350                         warn_or_die_horribly(AH, modulename, 
2351                                                                  "could not set default_tablespace to %s: %s",
2352                                                                  fmtId(want), PQerrorMessage(AH->connection));
2353
2354                 PQclear(res);
2355         }
2356         else
2357                 ahprintf(AH, "%s;\n\n", qry->data);
2358
2359         if (AH->currTablespace)
2360                 free(AH->currTablespace);
2361         AH->currTablespace = strdup(want);
2362
2363         destroyPQExpBuffer(qry);
2364 }
2365
2366 /*
2367  * Extract an object description for a TOC entry, and append it to buf.
2368  *
2369  * This is not quite as general as it may seem, since it really only
2370  * handles constructing the right thing to put into ALTER ... OWNER TO.
2371  *
2372  * The whole thing is pretty grotty, but we are kind of stuck since the
2373  * information used is all that's available in older dump files.
2374  */
2375 static void
2376 _getObjectDescription(PQExpBuffer buf, TocEntry *te)
2377 {
2378         const char *type = te->desc;
2379
2380         /* Use ALTER TABLE for views and sequences */
2381         if (strcmp(type, "VIEW") == 0 ||
2382                 strcmp(type, "SEQUENCE") == 0)
2383                 type = "TABLE";
2384
2385         /* We assume CONSTRAINTs are always pkey/unique indexes */
2386         if (strcmp(type, "CONSTRAINT") == 0)
2387                 type = "INDEX";
2388
2389         /* objects named by a schema and name */
2390         if (strcmp(type, "CONVERSION") == 0 ||
2391                 strcmp(type, "DOMAIN") == 0 ||
2392                 strcmp(type, "INDEX") == 0 ||
2393                 strcmp(type, "TABLE") == 0 ||
2394                 strcmp(type, "TYPE") == 0)
2395         {
2396                 appendPQExpBuffer(buf, "%s %s", type, fmtId(te->namespace));
2397                 appendPQExpBuffer(buf, ".%s", fmtId(te->tag));
2398                 return;
2399         }
2400
2401         /* objects named by just a name */
2402         if (strcmp(type, "DATABASE") == 0 ||
2403                 strcmp(type, "SCHEMA") == 0)
2404         {
2405                 appendPQExpBuffer(buf, "%s %s", type, fmtId(te->tag));
2406                 return;
2407         }
2408
2409         /*
2410          * These object types require additional decoration.  Fortunately,
2411          * the information needed is exactly what's in the DROP command.
2412          */
2413         if (strcmp(type, "AGGREGATE") == 0 ||
2414                 strcmp(type, "FUNCTION") == 0 ||
2415                 strcmp(type, "OPERATOR") == 0 ||
2416                 strcmp(type, "OPERATOR CLASS") == 0)
2417         {
2418                 /* Chop "DROP " off the front and make a modifiable copy */
2419                 char       *first = strdup(te->dropStmt + 5);
2420                 char       *last;
2421
2422                 /* point to last character in string */
2423                 last = first + strlen(first) - 1;
2424
2425                 /* Strip off any ';' or '\n' at the end */
2426                 while (last >= first && (*last == '\n' || *last == ';'))
2427                         last--;
2428                 *(last + 1) = '\0';
2429
2430                 appendPQExpBufferStr(buf, first);
2431
2432                 free(first);
2433                 return;
2434         }
2435
2436         write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n",
2437                           type);
2438 }
2439
2440 static void
2441 _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass)
2442 {
2443         /* ACLs are dumped only during acl pass */
2444         if (acl_pass)
2445         {
2446                 if (strcmp(te->desc, "ACL") != 0)
2447                         return;
2448         }
2449         else
2450         {
2451                 if (strcmp(te->desc, "ACL") == 0)
2452                         return;
2453         }
2454
2455         /*
2456          * Avoid dumping the public schema, as it will already be created ...
2457          * unless we are using --clean mode, in which case it's been deleted
2458          * and we'd better recreate it.
2459          */
2460         if (!ropt->dropSchema &&
2461                 strcmp(te->desc, "SCHEMA") == 0 && strcmp(te->tag, "public") == 0)
2462                 return;
2463
2464         /* Select owner, schema, and tablespace as necessary */
2465         _becomeOwner(AH, te);
2466         _selectOutputSchema(AH, te->namespace);
2467         _selectTablespace(AH, te->tablespace);
2468
2469         /* Set up OID mode too */
2470         if (strcmp(te->desc, "TABLE") == 0)
2471                 _setWithOids(AH, te);
2472
2473         /* Emit header comment for item */
2474         if (!AH->noTocComments)
2475         {
2476                 const char *pfx;
2477
2478                 if (isData)
2479                         pfx = "Data for ";
2480                 else
2481                         pfx = "";
2482
2483                 ahprintf(AH, "--\n");
2484                 if (AH->public.verbose)
2485                 {
2486                         ahprintf(AH, "-- TOC entry %d (class %u OID %u)\n",
2487                                          te->dumpId, te->catalogId.tableoid, te->catalogId.oid);
2488                         if (te->nDeps > 0)
2489                         {
2490                                 int                     i;
2491
2492                                 ahprintf(AH, "-- Dependencies:");
2493                                 for (i = 0; i < te->nDeps; i++)
2494                                         ahprintf(AH, " %d", te->dependencies[i]);
2495                                 ahprintf(AH, "\n");
2496                         }
2497                 }
2498                 ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s",
2499                                  pfx, te->tag, te->desc,
2500                                  te->namespace ? te->namespace : "-",
2501                                  te->owner);
2502                 if (te->tablespace) 
2503                         ahprintf(AH, "; Tablespace: %s", te->tablespace);
2504                 ahprintf(AH, "\n");
2505
2506                 if (AH->PrintExtraTocPtr != NULL)
2507                         (*AH->PrintExtraTocPtr) (AH, te);
2508                 ahprintf(AH, "--\n\n");
2509         }
2510
2511         /*
2512          * Actually print the definition.
2513          *
2514          * Really crude hack for suppressing AUTHORIZATION clause that old
2515          * pg_dump versions put into CREATE SCHEMA.  We have to do this when
2516          * --no-owner mode is selected.  This is ugly, but I see
2517          * no other good way ...
2518          */
2519         if (ropt->noOwner && strcmp(te->desc, "SCHEMA") == 0)
2520         {
2521                 ahprintf(AH, "CREATE SCHEMA %s;\n\n\n", fmtId(te->tag));
2522         }
2523         else
2524         {
2525                 if (strlen(te->defn) > 0)
2526                         ahprintf(AH, "%s\n\n", te->defn);
2527         }
2528
2529         /*
2530          * If we aren't using SET SESSION AUTH to determine ownership, we must
2531          * instead issue an ALTER OWNER command.  We assume that anything without
2532          * a DROP command is not a separately ownable object.  All the categories
2533          * with DROP commands must appear in one list or the other.
2534          */
2535         if (!ropt->noOwner && !ropt->use_setsessauth &&
2536                 strlen(te->owner) > 0 && strlen(te->dropStmt) > 0)
2537         {
2538                 if (strcmp(te->desc, "AGGREGATE") == 0 ||
2539                         strcmp(te->desc, "CONSTRAINT") == 0 ||
2540                         strcmp(te->desc, "CONVERSION") == 0 ||
2541                         strcmp(te->desc, "DATABASE") == 0 ||
2542                         strcmp(te->desc, "DOMAIN") == 0 ||
2543                         strcmp(te->desc, "FUNCTION") == 0 ||
2544                         strcmp(te->desc, "INDEX") == 0 ||
2545                         strcmp(te->desc, "OPERATOR") == 0 ||
2546                         strcmp(te->desc, "OPERATOR CLASS") == 0 ||
2547                         strcmp(te->desc, "SCHEMA") == 0 ||
2548                         strcmp(te->desc, "TABLE") == 0 ||
2549                         strcmp(te->desc, "TYPE") == 0 ||
2550                         strcmp(te->desc, "VIEW") == 0 ||
2551                         strcmp(te->desc, "SEQUENCE") == 0)
2552                 {
2553                         PQExpBuffer temp = createPQExpBuffer();
2554
2555                         appendPQExpBuffer(temp, "ALTER ");
2556                         _getObjectDescription(temp, te);
2557                         appendPQExpBuffer(temp, " OWNER TO %s;", fmtId(te->owner));
2558                         ahprintf(AH, "%s\n\n", temp->data);
2559                         destroyPQExpBuffer(temp);
2560                 }
2561                 else if (strcmp(te->desc, "CAST") == 0 ||
2562                                  strcmp(te->desc, "CHECK CONSTRAINT") == 0 ||
2563                                  strcmp(te->desc, "DEFAULT") == 0 ||
2564                                  strcmp(te->desc, "FK CONSTRAINT") == 0 ||
2565                                  strcmp(te->desc, "PROCEDURAL LANGUAGE") == 0 ||
2566                                  strcmp(te->desc, "RULE") == 0 ||
2567                                  strcmp(te->desc, "TRIGGER") == 0)
2568                 {
2569                         /* these object types don't have separate owners */
2570                 }
2571                 else
2572                 {
2573                         write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n",
2574                                           te->desc);
2575                 }
2576         }
2577
2578         /*
2579          * If it's an ACL entry, it might contain SET SESSION AUTHORIZATION
2580          * commands, so we can no longer assume we know the current auth
2581          * setting.
2582          */
2583         if (strncmp(te->desc, "ACL", 3) == 0)
2584         {
2585                 if (AH->currUser)
2586                         free(AH->currUser);
2587                 AH->currUser = NULL;
2588         }
2589 }
2590
2591 void
2592 WriteHead(ArchiveHandle *AH)
2593 {
2594         struct tm       crtm;
2595
2596         (*AH->WriteBufPtr) (AH, "PGDMP", 5);            /* Magic code */
2597         (*AH->WriteBytePtr) (AH, AH->vmaj);
2598         (*AH->WriteBytePtr) (AH, AH->vmin);
2599         (*AH->WriteBytePtr) (AH, AH->vrev);
2600         (*AH->WriteBytePtr) (AH, AH->intSize);
2601         (*AH->WriteBytePtr) (AH, AH->offSize);
2602         (*AH->WriteBytePtr) (AH, AH->format);
2603
2604 #ifndef HAVE_LIBZ
2605         if (AH->compression != 0)
2606                 write_msg(modulename, "WARNING: requested compression not available in this "
2607                                   "installation -- archive will be uncompressed\n");
2608
2609         AH->compression = 0;
2610 #endif
2611
2612         WriteInt(AH, AH->compression);
2613
2614         crtm = *localtime(&AH->createDate);
2615         WriteInt(AH, crtm.tm_sec);
2616         WriteInt(AH, crtm.tm_min);
2617         WriteInt(AH, crtm.tm_hour);
2618         WriteInt(AH, crtm.tm_mday);
2619         WriteInt(AH, crtm.tm_mon);
2620         WriteInt(AH, crtm.tm_year);
2621         WriteInt(AH, crtm.tm_isdst);
2622         WriteStr(AH, PQdb(AH->connection));
2623         WriteStr(AH, AH->public.remoteVersionStr);
2624         WriteStr(AH, PG_VERSION);
2625 }
2626
2627 void
2628 ReadHead(ArchiveHandle *AH)
2629 {
2630         char            tmpMag[7];
2631         int                     fmt;
2632         struct tm       crtm;
2633
2634         /* If we haven't already read the header... */
2635         if (!AH->readHeader)
2636         {
2637
2638                 (*AH->ReadBufPtr) (AH, tmpMag, 5);
2639
2640                 if (strncmp(tmpMag, "PGDMP", 5) != 0)
2641                         die_horribly(AH, modulename, "did not find magic string in file header\n");
2642
2643                 AH->vmaj = (*AH->ReadBytePtr) (AH);
2644                 AH->vmin = (*AH->ReadBytePtr) (AH);
2645
2646                 if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))                /* Version > 1.0 */
2647                         AH->vrev = (*AH->ReadBytePtr) (AH);
2648                 else
2649                         AH->vrev = 0;
2650
2651                 AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
2652
2653
2654                 if (AH->version < K_VERS_1_0 || AH->version > K_VERS_MAX)
2655                         die_horribly(AH, modulename, "unsupported version (%d.%d) in file header\n",
2656                                                  AH->vmaj, AH->vmin);
2657
2658                 AH->intSize = (*AH->ReadBytePtr) (AH);
2659                 if (AH->intSize > 32)
2660                         die_horribly(AH, modulename, "sanity check on integer size (%lu) failed\n",
2661                                                  (unsigned long) AH->intSize);
2662
2663                 if (AH->intSize > sizeof(int))
2664                         write_msg(modulename, "WARNING: archive was made on a machine with larger integers, some operations may fail\n");
2665
2666                 if (AH->version >= K_VERS_1_7)
2667                         AH->offSize = (*AH->ReadBytePtr) (AH);
2668                 else
2669                         AH->offSize = AH->intSize;
2670
2671                 fmt = (*AH->ReadBytePtr) (AH);
2672
2673                 if (AH->format != fmt)
2674                         die_horribly(AH, modulename, "expected format (%d) differs from format found in file (%d)\n",
2675                                                  AH->format, fmt);
2676         }
2677
2678         if (AH->version >= K_VERS_1_2)
2679         {
2680                 if (AH->version < K_VERS_1_4)
2681                         AH->compression = (*AH->ReadBytePtr) (AH);
2682                 else
2683                         AH->compression = ReadInt(AH);
2684         }
2685         else
2686                 AH->compression = Z_DEFAULT_COMPRESSION;
2687
2688 #ifndef HAVE_LIBZ
2689         if (AH->compression != 0)
2690                 write_msg(modulename, "WARNING: archive is compressed, but this installation does not support compression -- no data will be available\n");
2691 #endif
2692
2693         if (AH->version >= K_VERS_1_4)
2694         {
2695                 crtm.tm_sec = ReadInt(AH);
2696                 crtm.tm_min = ReadInt(AH);
2697                 crtm.tm_hour = ReadInt(AH);
2698                 crtm.tm_mday = ReadInt(AH);
2699                 crtm.tm_mon = ReadInt(AH);
2700                 crtm.tm_year = ReadInt(AH);
2701                 crtm.tm_isdst = ReadInt(AH);
2702
2703                 AH->archdbname = ReadStr(AH);
2704
2705                 AH->createDate = mktime(&crtm);
2706
2707                 if (AH->createDate == (time_t) -1)
2708                         write_msg(modulename, "WARNING: invalid creation date in header\n");
2709         }
2710
2711         if (AH->version >= K_VERS_1_10)
2712         {
2713                 AH->archiveRemoteVersion = ReadStr(AH);
2714                 AH->archiveDumpVersion = ReadStr(AH);
2715         }
2716
2717 }
2718
2719
2720 /*
2721  * checkSeek
2722  *        check to see if fseek can be performed.
2723  */
2724
2725 bool
2726 checkSeek(FILE *fp)
2727 {
2728
2729         if (fseeko(fp, 0, SEEK_CUR) != 0)
2730                 return false;
2731         else if (sizeof(off_t) > sizeof(long))
2732
2733                 /*
2734                  * At this point, off_t is too large for long, so we return based
2735                  * on whether an off_t version of fseek is available.
2736                  */
2737 #ifdef HAVE_FSEEKO
2738                 return true;
2739 #else
2740                 return false;
2741 #endif
2742         else
2743                 return true;
2744 }