OSDN Git Service

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