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