1 /*-------------------------------------------------------------------------
5 * Private implementation of the archiver routines.
7 * See the headers to pg_restore for more details.
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.
13 * The author is not responsible for loss or damages that may
14 * result from its use.
18 * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.56 2002/08/27 18:57:26 petere Exp $
20 *-------------------------------------------------------------------------
23 #include "pg_backup.h"
25 #include "pg_backup_archiver.h"
26 #include "pg_backup_db.h"
27 #include "dumputils.h"
33 #include "pqexpbuffer.h"
34 #include "libpq/libpq-fs.h"
41 REQ_ALL = REQ_SCHEMA + REQ_DATA
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);
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);
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)[]));
67 static char *modulename = gettext_noop("archiver");
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);
72 static int _canRestoreBlobs(ArchiveHandle *AH);
73 static int _restoringToDB(ArchiveHandle *AH);
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.
84 /* Create a new archive */
87 CreateArchive(const char *FileSpec, const ArchiveFormat fmt,
88 const int compression)
91 ArchiveHandle *AH = _allocAH(FileSpec, fmt, compression, archModeWrite);
93 return (Archive *) AH;
96 /* Open an existing archive */
99 OpenArchive(const char *FileSpec, const ArchiveFormat fmt)
101 ArchiveHandle *AH = _allocAH(FileSpec, fmt, 0, archModeRead);
103 return (Archive *) AH;
108 CloseArchive(Archive *AHX)
111 ArchiveHandle *AH = (ArchiveHandle *) AHX;
113 (*AH->ClosePtr) (AH);
115 /* Close the output */
117 res = GZCLOSE(AH->OF);
118 else if (AH->OF != stdout)
119 res = fclose(AH->OF);
122 die_horribly(AH, modulename, "could not close the output file in CloseArchive\n");
127 RestoreArchive(Archive *AHX, RestoreOptions *ropt)
129 ArchiveHandle *AH = (ArchiveHandle *) AHX;
130 TocEntry *te = AH->toc->next;
139 * Check for nonsensical option combinations.
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
148 if (ropt->create && ropt->noReconnect)
149 die_horribly(AH, modulename, "-C and -R are incompatible options\n");
151 if (ropt->create && ropt->dropSchema)
152 die_horribly(AH, modulename, "-C and -c are incompatible options\n");
155 * If we're using a DB connection, then connect it.
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");
163 /* XXX Should get this from the archive */
164 AHX->minRemoteVersion = 070100;
165 AHX->maxRemoteVersion = 999999;
167 ConnectDatabase(AHX, ropt->dbname,
168 ropt->pghost, ropt->pgport, ropt->username,
169 ropt->requirePassword, ropt->ignoreVersion);
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.
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).
185 while (te != AH->toc)
187 reqs = _tocEntryRequired(te, ropt);
188 if ((reqs & REQ_SCHEMA) != 0)
189 { /* It's schema, and it's wanted */
197 ropt->dataOnly = impliedDataOnly;
198 ahlog(AH, 1, "implied data-only restore\n");
203 * Setup the output file if necessary.
205 if (ropt->filename || ropt->compression)
206 sav = SetOutput(AH, ropt->filename, ropt->compression);
208 ahprintf(AH, "--\n-- PostgreSQL database dump\n--\n\n");
211 * Drop the items at the start, in reverse order
213 if (ropt->dropSchema)
216 while (te != AH->toc)
218 reqs = _tocEntryRequired(te, ropt);
219 if (((reqs & REQ_SCHEMA) != 0) && te->dropStmt)
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);
227 ahprintf(AH, "%s", te->dropStmt);
234 * Now process each TOC entry
237 while (te != AH->toc)
239 /* Work out what, if anything, we want from this entry */
240 reqs = _tocEntryRequired(te, ropt);
242 /* Dump any relevant dump warnings to stderr */
243 if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
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);
253 if ((reqs & REQ_SCHEMA) != 0) /* We want the schema */
255 ahlog(AH, 1, "creating %s %s\n", te->desc, te->tag);
256 _printTocEntry(AH, te, ropt, false);
259 /* If we created a DB, connect to it... */
260 if (strcmp(te->desc, "DATABASE") == 0)
262 ahlog(AH, 1, "connecting to new database %s as user %s\n", te->tag, te->owner);
263 _reconnectAsUser(AH, te->tag, te->owner);
268 * If we have a data component, then process it
270 if ((reqs & REQ_DATA) != 0)
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
281 * If we can output the data, then restore it.
283 if (AH->PrintTocDataPtr !=NULL && (reqs & REQ_DATA) != 0)
286 if (AH->compression != 0)
287 die_horribly(AH, modulename, "unable to restore from compressed archive (not configured for compression support)\n");
290 _printTocEntry(AH, te, ropt, true);
293 * Maybe we can't do BLOBS, so check if this node is
296 if ((strcmp(te->desc, "BLOBS") == 0) && !_canRestoreBlobs(AH))
298 ahprintf(AH, "--\n-- SKIPPED \n--\n\n");
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.
305 if (!AH->CustomOutPtr)
306 write_msg(modulename, "WARNING: skipping large object restoration\n");
312 _disableTriggersIfNecessary(AH, te, ropt);
315 * Reconnect if necessary (_disableTriggers may
318 _reconnectAsOwner(AH, NULL, te);
319 _selectOutputSchema(AH, te->namespace);
321 ahlog(AH, 1, "restoring data for table %s\n", te->tag);
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.
330 * For V1.3+, the table data MUST have a copy
331 * statement so that we can go into appropriate
334 if (te->copyStmt && strlen(te->copyStmt) > 0)
335 ahprintf(AH, te->copyStmt);
337 (*AH->PrintTocDataPtr) (AH, te, ropt);
339 _enableTriggersIfNecessary(AH, te, ropt);
343 else if (!defnDumped)
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);
354 * Now use blobs_xref (if used) to fixup any refs for tables that we
357 if (_canRestoreBlobs(AH) && AH->createdBlobXref)
359 /* NULL parameter means disable ALL user triggers */
360 _disableTriggersIfNecessary(AH, NULL, ropt);
363 while (te != AH->toc)
366 /* Is it table data? */
367 if (strcmp(te->desc, "TABLE DATA") == 0)
370 ahlog(AH, 2, "checking whether we loaded %s\n", te->tag);
372 reqs = _tocEntryRequired(te, ropt);
374 if ((reqs & REQ_DATA) != 0) /* We loaded the data */
376 ahlog(AH, 1, "fixing up large object cross-reference for %s\n", te->tag);
377 FixupBlobRefs(AH, te);
381 ahlog(AH, 2, "ignoring large object cross-references for %s %s\n", te->desc, te->tag);
386 /* NULL parameter means enable ALL user triggers */
387 _enableTriggersIfNecessary(AH, NULL, ropt);
391 * Clean up & we're done.
394 ResetOutput(AH, sav);
398 PQfinish(AH->connection);
399 AH->connection = NULL;
401 if (AH->blobConnection)
403 PQfinish(AH->blobConnection);
404 AH->blobConnection = NULL;
410 * Allocate a new RestoreOptions block.
411 * This is mainly so we can initialize it, but also for future expansion,
414 NewRestoreOptions(void)
416 RestoreOptions *opts;
418 opts = (RestoreOptions *) calloc(1, sizeof(RestoreOptions));
420 opts->format = archUnknown;
421 opts->suppressDumpWarnings = false;
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).
431 _restoringToDB(ArchiveHandle *AH)
433 return (AH->ropt->useDB && AH->connection);
437 _canRestoreBlobs(ArchiveHandle *AH)
439 return _restoringToDB(AH);
443 _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
448 /* This hack is only needed in a data-only restore */
449 if (!ropt->dataOnly || !ropt->disable_triggers)
452 oldUser = strdup(AH->currUser);
453 oldSchema = strdup(AH->currSchema);
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.
463 _reconnectAsUser(AH, NULL, ropt->superuser);
464 /* be careful to preserve schema setting */
465 _selectOutputSchema(AH, oldSchema);
467 else if (AH->ropt->use_setsessauth)
469 _doSetSessionAuth(AH, NULL);
472 ahlog(AH, 1, "disabling triggers\n");
475 * Disable them. This is a hack. Needs to be done via an appropriate
476 * 'SET' command when one is available.
478 ahprintf(AH, "-- Disable triggers\n");
481 * Just update the AFFECTED table, if known. Otherwise update all
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",
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");
493 * Restore original user and schema state.
497 _reconnectAsUser(AH, NULL, oldUser);
498 /* be careful to preserve schema setting */
499 _selectOutputSchema(AH, oldSchema);
501 else if (AH->ropt->use_setsessauth)
503 _doSetSessionAuth(AH, oldUser);
510 _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
515 /* This hack is only needed in a data-only restore */
516 if (!ropt->dataOnly || !ropt->disable_triggers)
519 oldUser = strdup(AH->currUser);
520 oldSchema = strdup(AH->currSchema);
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.
530 _reconnectAsUser(AH, NULL, ropt->superuser);
531 /* be careful to preserve schema setting */
532 _selectOutputSchema(AH, oldSchema);
534 else if (AH->ropt->use_setsessauth)
536 _doSetSessionAuth(AH, NULL);
539 ahlog(AH, 1, "enabling triggers\n");
542 * Enable them. This is a hack. Needs to be done via an appropriate
543 * 'SET' command when one is available.
545 ahprintf(AH, "-- Enable triggers\n");
548 * Just update the AFFECTED table, if known. Otherwise update all
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",
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");
563 * Restore original user and schema state.
567 _reconnectAsUser(AH, NULL, oldUser);
568 /* be careful to preserve schema setting */
569 _selectOutputSchema(AH, oldSchema);
571 else if (AH->ropt->use_setsessauth)
573 _doSetSessionAuth(AH, oldUser);
580 * This is a routine that is part of the dumper interface, hence the 'Archive*' parameter.
585 WriteData(Archive *AHX, const void *data, size_t dLen)
587 ArchiveHandle *AH = (ArchiveHandle *) AHX;
590 die_horribly(AH, modulename, "WriteData cannot be called outside the context of a DataDumper routine\n");
592 return (*AH->WriteDataPtr) (AH, data, dLen);
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.
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)
609 ArchiveHandle *AH = (ArchiveHandle *) AHX;
615 newToc = (TocEntry *) calloc(1, sizeof(TocEntry));
617 die_horribly(AH, modulename, "out of memory\n");
619 newToc->prev = AH->toc->prev;
620 newToc->next = AH->toc;
621 AH->toc->prev->next = newToc;
622 AH->toc->prev = newToc;
624 newToc->id = AH->lastID;
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;
634 newToc->oid = strdup(oid);
635 newToc->depOid = deps; /* NB: not copied */
636 _fixupOidInfo(newToc);
639 newToc->formatData = NULL;
640 newToc->dataDumper = dumpFn;
641 newToc->dataDumperArg = dumpArg;
643 newToc->hadDumper = dumpFn ? 1 : 0;
645 if (AH->ArchiveEntryPtr !=NULL)
646 (*AH->ArchiveEntryPtr) (AH, newToc);
649 * printf("New toc owned by '%s', oid %u\n", newToc->owner,
656 PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
658 ArchiveHandle *AH = (ArchiveHandle *) AHX;
659 TocEntry *te = AH->toc->next;
664 sav = SetOutput(AH, ropt->filename, ropt->compression);
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);
685 ahprintf(AH, "; Dump Version: %d.%d-%d\n", AH->vmaj, AH->vmin, AH->vrev);
686 ahprintf(AH, "; Format: %s\n;\n", fmtName);
688 ahprintf(AH, ";\n; Selected TOC Entries:\n;\n");
690 while (te != AH->toc)
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);
698 ResetOutput(AH, sav);
705 /* Called by a dumper to signal start of a BLOB */
707 StartBlob(Archive *AHX, Oid oid)
709 ArchiveHandle *AH = (ArchiveHandle *) AHX;
711 if (!AH->StartBlobPtr)
712 die_horribly(AH, modulename, "large object output not supported in chosen format\n");
714 (*AH->StartBlobPtr) (AH, AH->currToc, oid);
719 /* Called by a dumper to signal end of a BLOB */
721 EndBlob(Archive *AHX, Oid oid)
723 ArchiveHandle *AH = (ArchiveHandle *) AHX;
726 (*AH->EndBlobPtr) (AH, AH->currToc, oid);
736 * Called by a format handler before any blobs are restored
739 StartRestoreBlobs(ArchiveHandle *AH)
745 * Called by a format handler after all blobs are restored
748 EndRestoreBlobs(ArchiveHandle *AH)
752 ahlog(AH, 2, "committing large object transactions\n");
753 CommitTransaction(AH);
756 if (AH->blobTxActive)
757 CommitTransactionXref(AH);
759 ahlog(AH, 1, "restored %d large objects\n", AH->blobCount);
764 * Called by a format handler to initiate restoration of a blob
767 StartRestoreBlob(ArchiveHandle *AH, Oid oid)
773 if (!AH->createdBlobXref)
776 die_horribly(AH, modulename, "cannot restore large objects without a database connection\n");
778 CreateBlobXrefTable(AH);
779 AH->createdBlobXref = 1;
782 /* Initialize the LO Buffer */
786 * Start long-running TXs if necessary
790 ahlog(AH, 2, "starting large object transactions\n");
791 StartTransaction(AH);
793 if (!AH->blobTxActive)
794 StartTransactionXref(AH);
796 loOid = lo_creat(AH->connection, INV_READ | INV_WRITE);
798 die_horribly(AH, modulename, "could not create large object\n");
800 ahlog(AH, 2, "restoring large object with oid %u as %u\n", oid, loOid);
802 InsertBlobXref(AH, oid, loOid);
804 AH->loFd = lo_open(AH->connection, loOid, INV_WRITE);
806 die_horribly(AH, modulename, "could not open large object\n");
812 EndRestoreBlob(ArchiveHandle *AH, Oid oid)
814 if (AH->lo_buf_used > 0)
816 /* Write remaining bytes from the LO buffer */
819 res = lo_write(AH->connection, AH->loFd, (void *) AH->lo_buf, AH->lo_buf_used);
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);
829 lo_close(AH->connection, AH->loFd);
833 * Commit every BLOB_BATCH_SIZE blobs...
835 if (((AH->blobCount / BLOB_BATCH_SIZE) * BLOB_BATCH_SIZE) == AH->blobCount)
837 ahlog(AH, 2, "committing large object transactions\n");
838 CommitTransaction(AH);
839 CommitTransactionXref(AH);
844 * Sorting and Reordering
848 * Move TOC entries of the specified type to the START of the TOC.
853 MoveToStart(Archive *AHX, char *oType)
855 ArchiveHandle *AH = (ArchiveHandle *) AHX;
856 TocEntry *te = AH->toc->next;
859 while (te != AH->toc)
866 while (te != AH->toc && !te->_moved)
869 if (strcmp(te->desc, oType) == 0)
870 _moveAfter(AH, AH->toc, te);
877 * Move TOC entries of the specified type to the end of the TOC.
881 MoveToEnd(Archive *AHX, char *oType)
883 ArchiveHandle *AH = (ArchiveHandle *) AHX;
884 TocEntry *te = AH->toc->next;
887 while (te != AH->toc)
894 while (te != AH->toc && !te->_moved)
897 if (strcmp(te->desc, oType) == 0)
898 _moveBefore(AH, AH->toc, te);
908 SortTocByOID(Archive *AHX)
910 ArchiveHandle *AH = (ArchiveHandle *) AHX;
912 _SortToc(AH, _tocSortCompareByOIDNum);
920 SortTocByID(Archive *AHX)
922 ArchiveHandle *AH = (ArchiveHandle *) AHX;
924 _SortToc(AH, _tocSortCompareByIDNum);
928 SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
930 ArchiveHandle *AH = (ArchiveHandle *) AHX;
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;
945 ropt->limitToList = 1;
947 /* Mark all entries as 'not moved' */
949 while (te != AH->toc)
955 /* Set prev entry as head of list */
959 fh = fopen(ropt->tocFile, PG_BINARY_R);
961 die_horribly(AH, modulename, "could not open TOC file\n");
963 while (fgets(buf, 1024, fh) != NULL)
966 cmnt = strchr(buf, ';');
970 /* End string at comment */
974 /* Skip if all spaces */
975 if (strspn(buf, " \t") == strlen(buf))
979 id = strtol(buf, &endptr, 10);
982 write_msg(modulename, "WARNING: line ignored: %s\n", buf);
987 te = _getTocEntry(AH, id);
989 die_horribly(AH, modulename, "could not find entry for id %d\n", id);
991 ropt->idWanted[id - 1] = 1;
993 _moveAfter(AH, tePrev, te);
998 die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno));
1001 /**********************
1002 * 'Convenience functions that look like standard IO functions
1003 * for writing data when in dump mode.
1004 **********************/
1008 archputs(const char *s, Archive *AH)
1010 return WriteData(AH, s, strlen(s));
1015 archputc(const char c, Archive *AH)
1017 return WriteData(AH, &c, 1);
1022 archprintf(Archive *AH, const char *fmt,...)
1026 int bSize = strlen(fmt) + 256;
1030 * This is paranoid: deal with the possibility that vsnprintf is
1031 * willing to ignore trailing null
1035 * or returns > 0 even if string does not fit. It may be the case that
1036 * it returns cnt = bufsize
1038 while (cnt < 0 || cnt >= (bSize - 1))
1043 p = (char *) malloc(bSize);
1045 exit_horribly(AH, modulename, "out of memory\n");
1047 cnt = vsnprintf(p, bSize, fmt, ap);
1050 WriteData(AH, p, cnt);
1056 /*******************************
1057 * Stuff below here should be 'private' to the archiver routines
1058 *******************************/
1061 SetOutput(ArchiveHandle *AH, char *filename, int compression)
1070 /* Replace the AH output file handle */
1072 sav.gzOut = AH->gzOut;
1077 fn = fileno(AH->FH);
1081 filename = AH->fSpec;
1084 fn = fileno(stdout);
1086 /* If compression explicitly requested, use gzopen */
1088 if (compression != 0)
1090 sprintf(fmode, "wb%d", compression);
1093 AH->OF = gzdopen(dup(fn), fmode); /* Don't use PG_BINARY_x
1094 * since this is zlib */
1097 AH->OF = gzopen(filename, fmode);
1104 AH->OF = fdopen(dup(fn), PG_BINARY_W);
1106 AH->OF = fopen(filename, PG_BINARY_W);
1113 die_horribly(AH, modulename, "could not open output file: %s\n", strerror(errno));
1119 ResetOutput(ArchiveHandle *AH, OutputContext sav)
1124 res = GZCLOSE(AH->OF);
1126 res = fclose(AH->OF);
1129 die_horribly(AH, modulename, "could not close output file: %s\n", strerror(errno));
1131 AH->gzOut = sav.gzOut;
1138 * Print formatted text to the output file (usually stdout).
1141 ahprintf(ArchiveHandle *AH, const char *fmt,...)
1145 int bSize = strlen(fmt) + 256; /* Should be enough */
1149 * This is paranoid: deal with the possibility that vsnprintf is
1150 * willing to ignore trailing null
1154 * or returns > 0 even if string does not fit. It may be the case that
1155 * it returns cnt = bufsize
1157 while (cnt < 0 || cnt >= (bSize - 1))
1162 p = (char *) malloc(bSize);
1164 die_horribly(AH, modulename, "out of memory\n");
1166 cnt = vsnprintf(p, bSize, fmt, ap);
1169 ahwrite(p, 1, cnt, AH);
1175 ahlog(ArchiveHandle *AH, int level, const char *fmt,...)
1179 if (AH->debugLevel < level && (!AH->public.verbose || level > 1))
1183 _write_msg(NULL, fmt, ap);
1188 * Single place for logic which says 'We are restoring to a direct DB connection'.
1191 RestoringToDB(ArchiveHandle *AH)
1193 return (AH->ropt && AH->ropt->useDB && AH->connection);
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).
1203 ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
1207 if (AH->writingBlob)
1209 if (AH->lo_buf_used + size * nmemb > AH->lo_buf_size)
1211 /* Split LO buffer */
1212 size_t remaining = AH->lo_buf_size - AH->lo_buf_used;
1213 size_t slack = nmemb * size - remaining;
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;
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;
1233 return size * nmemb;
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");
1242 else if (AH->CustomOutPtr)
1244 res = AH->CustomOutPtr (AH, ptr, size * nmemb);
1246 if (res != (nmemb * size))
1247 die_horribly(AH, modulename, "could not write to custom output routine\n");
1253 * If we're doing a restore, and it's direct to DB, and we're
1254 * connected then send it to the DB.
1256 if (RestoringToDB(AH))
1257 return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb); /* Always 1, currently */
1260 res = fwrite((void *) ptr, size, nmemb, AH->OF);
1262 die_horribly(AH, modulename, "could not write to output file (%lu != %lu)\n",
1263 (unsigned long) res, (unsigned long) nmemb);
1269 /* Common exit code */
1271 _write_msg(const char *modulename, const char *fmt, va_list ap)
1274 fprintf(stderr, "%s: [%s] ", progname, gettext(modulename));
1276 fprintf(stderr, "%s: ", progname);
1277 vfprintf(stderr, gettext(fmt), ap);
1281 write_msg(const char *modulename, const char *fmt,...)
1286 _write_msg(modulename, fmt, ap);
1292 _die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt, va_list ap)
1294 _write_msg(modulename, fmt, ap);
1295 if (AH->public.verbose)
1296 write_msg(NULL, "*** aborted because of error\n");
1300 PQfinish(AH->connection);
1301 if (AH->blobConnection)
1302 PQfinish(AH->blobConnection);
1309 exit_horribly(Archive *AH, const char *modulename, const char *fmt,...)
1314 _die_horribly((ArchiveHandle *) AH, modulename, fmt, ap);
1317 /* Archiver use (just different arg declaration) */
1319 die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...)
1324 _die_horribly(AH, modulename, fmt, ap);
1329 _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
1331 te->prev->next = te->next;
1332 te->next->prev = te->prev;
1335 te->next = pos->next;
1337 pos->next->prev = te;
1344 _moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
1346 te->prev->next = te->next;
1347 te->next->prev = te->prev;
1349 te->prev = pos->prev;
1351 pos->prev->next = te;
1358 _getTocEntry(ArchiveHandle *AH, int id)
1363 while (te != AH->toc)
1373 TocIDRequired(ArchiveHandle *AH, int id, RestoreOptions *ropt)
1375 TocEntry *te = _getTocEntry(AH, id);
1380 return _tocEntryRequired(te, ropt);
1384 WriteInt(ArchiveHandle *AH, int i)
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.
1399 (*AH->WriteBytePtr) (AH, 1);
1403 (*AH->WriteBytePtr) (AH, 0);
1405 for (b = 0; b < AH->intSize; b++)
1407 (*AH->WriteBytePtr) (AH, i & 0xFF);
1411 return AH->intSize + 1;
1415 ReadInt(ArchiveHandle *AH)
1420 int sign = 0; /* Default positive */
1423 if (AH->version > K_VERS_1_0)
1424 /* Read a sign byte */
1425 sign = (*AH->ReadBytePtr) (AH);
1427 for (b = 0; b < AH->intSize; b++)
1429 bv = (*AH->ReadBytePtr) (AH) & 0xFF;
1431 res = res + (bv << bitShift);
1442 WriteStr(ArchiveHandle *AH, const char *c)
1448 res = WriteInt(AH, strlen(c));
1449 res += (*AH->WriteBufPtr) (AH, c, strlen(c));
1452 res = WriteInt(AH, -1);
1458 ReadStr(ArchiveHandle *AH)
1468 buf = (char *) malloc(l + 1);
1470 die_horribly(AH, modulename, "out of memory\n");
1472 (*AH->ReadBufPtr) (AH, (void *) buf, l);
1480 _discoverArchiveFormat(ArchiveHandle *AH)
1483 char sig[6]; /* More than enough */
1488 write_msg(modulename, "attempting to ascertain archive format\n");
1492 free(AH->lookahead);
1494 AH->lookaheadSize = 512;
1495 AH->lookahead = calloc(1, 512);
1496 AH->lookaheadLen = 0;
1497 AH->lookaheadPos = 0;
1502 fh = fopen(AH->fSpec, PG_BINARY_R);
1508 die_horribly(AH, modulename, "could not open input file: %s\n", strerror(errno));
1510 cnt = fread(sig, 1, 5, fh);
1515 die_horribly(AH, modulename, "could not read input file: %s\n", strerror(errno));
1517 die_horribly(AH, modulename, "input file is too short (read %lu, expected 5)\n",
1518 (unsigned long) cnt);
1521 /* Save it, just in case we need it later */
1522 strncpy(&AH->lookahead[0], sig, 5);
1523 AH->lookaheadLen = 5;
1525 if (strncmp(sig, "PGDMP", 5) == 0)
1527 AH->vmaj = fgetc(fh);
1528 AH->vmin = fgetc(fh);
1530 /* Save these too... */
1531 AH->lookahead[AH->lookaheadLen++] = AH->vmaj;
1532 AH->lookahead[AH->lookaheadLen++] = AH->vmin;
1534 /* Check header version; varies from V1.0 */
1535 if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0))) /* Version > 1.0 */
1537 AH->vrev = fgetc(fh);
1538 AH->lookahead[AH->lookaheadLen++] = AH->vrev;
1543 AH->intSize = fgetc(fh);
1544 AH->lookahead[AH->lookaheadLen++] = AH->intSize;
1546 AH->format = fgetc(fh);
1547 AH->lookahead[AH->lookaheadLen++] = AH->format;
1549 /* Make a convenient integer <maj><min><rev>00 */
1550 AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
1555 * *Maybe* we have a tar archive format file... So, read first 512
1558 cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh);
1559 AH->lookaheadLen += cnt;
1561 if (AH->lookaheadLen != 512)
1562 die_horribly(AH, modulename, "input file does not appear to be a valid archive (too short?)\n");
1564 if (!isValidTarHeader(AH->lookahead))
1565 die_horribly(AH, modulename, "input file does not appear to be a valid archive\n");
1567 AH->format = archTar;
1570 /* If we can't seek, then mark the header as read */
1571 if (fseeko(fh, 0, SEEK_SET) != 0)
1574 * NOTE: Formats that use the looahead buffer can unset this in
1575 * their Init routine.
1580 AH->lookaheadLen = 0; /* Don't bother since we've reset the file */
1583 write_msg(modulename, "read %lu bytes into lookahead buffer\n",
1584 (unsigned long) AH->lookaheadLen);
1587 /* Close the file */
1589 if (fclose(fh) != 0)
1590 die_horribly(AH, modulename, "could not close the input file after reading header: %s\n",
1598 * Allocate an archive handle
1600 static ArchiveHandle *
1601 _allocAH(const char *FileSpec, const ArchiveFormat fmt,
1602 const int compression, ArchiveMode mode)
1607 write_msg(modulename, "allocating AH for %s, format %d\n", FileSpec, fmt);
1610 AH = (ArchiveHandle *) calloc(1, sizeof(ArchiveHandle));
1612 die_horribly(AH, modulename, "out of memory\n");
1614 AH->vmaj = K_VERS_MAJOR;
1615 AH->vmin = K_VERS_MINOR;
1616 AH->vrev = K_VERS_REV;
1618 AH->createDate = time(NULL);
1620 AH->intSize = sizeof(int);
1624 AH->fSpec = strdup(FileSpec);
1627 * Not used; maybe later....
1629 * AH->workDir = strdup(FileSpec); for(i=strlen(FileSpec) ; i > 0 ;
1630 * i--) if (AH->workDir[i-1] == '/')
1636 AH->currUser = strdup(""); /* So it's valid, but we can free() it
1637 * later if necessary */
1638 AH->currSchema = strdup(""); /* ditto */
1640 AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry));
1642 die_horribly(AH, modulename, "out of memory\n");
1644 AH->toc->next = AH->toc;
1645 AH->toc->prev = AH->toc;
1648 AH->compression = compression;
1650 AH->pgCopyBuf = createPQExpBuffer();
1651 AH->sqlBuf = createPQExpBuffer();
1653 /* Open stdout with no compression for AH output handle */
1658 write_msg(modulename, "archive format is %d\n", fmt);
1661 if (fmt == archUnknown)
1662 AH->format = _discoverArchiveFormat(AH);
1670 InitArchiveFmt_Custom(AH);
1674 InitArchiveFmt_Files(AH);
1678 InitArchiveFmt_Null(AH);
1682 InitArchiveFmt_Tar(AH);
1686 die_horribly(AH, modulename, "unrecognized file format '%d'\n", fmt);
1694 WriteDataChunks(ArchiveHandle *AH)
1696 TocEntry *te = AH->toc->next;
1697 StartDataPtr startPtr;
1700 while (te != AH->toc)
1702 if (te->dataDumper != NULL)
1705 /* printf("Writing data for %d (%x)\n", te->id, te); */
1707 if (strcmp(te->desc, "BLOBS") == 0)
1709 startPtr = AH->StartBlobsPtr;
1710 endPtr = AH->EndBlobsPtr;
1714 startPtr = AH->StartDataPtr;
1715 endPtr = AH->EndDataPtr;
1718 if (startPtr != NULL)
1719 (*startPtr) (AH, te);
1722 * printf("Dumper arg for %d is %x\n", te->id,
1723 * te->dataDumperArg);
1727 * The user-provided DataDumper routine needs to call
1730 (*te->dataDumper) ((Archive *) AH, te->oid, te->dataDumperArg);
1741 WriteToc(ArchiveHandle *AH)
1743 TocEntry *te = AH->toc->next;
1747 /* printf("%d TOC Entries to save\n", AH->tocCount); */
1749 WriteInt(AH, AH->tocCount);
1750 while (te != AH->toc)
1752 WriteInt(AH, te->id);
1753 WriteInt(AH, te->dataDumper ? 1 : 0);
1754 WriteStr(AH, te->oid);
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);
1764 /* Dump list of dependencies */
1765 if (te->depOid != NULL)
1768 while ((dep = (*te->depOid)[i++]) != NULL)
1771 WriteStr(AH, NULL); /* Terminate List */
1773 if (AH->WriteExtraTocPtr)
1774 (*AH->WriteExtraTocPtr) (AH, te);
1780 ReadToc(ArchiveHandle *AH)
1787 TocEntry *te = AH->toc->next;
1789 AH->tocCount = ReadInt(AH);
1791 for (i = 0; i < AH->tocCount; i++)
1794 te = (TocEntry *) calloc(1, sizeof(TocEntry));
1795 te->id = ReadInt(AH);
1798 if (te->id <= 0 || te->id > AH->tocCount)
1799 die_horribly(AH, modulename, "entry id out of range - perhaps a corrupt TOC\n");
1801 te->hadDumper = ReadInt(AH);
1802 te->oid = ReadStr(AH);
1803 te->oidVal = atooid(te->oid);
1805 te->tag = ReadStr(AH);
1806 te->desc = ReadStr(AH);
1807 te->defn = ReadStr(AH);
1808 te->dropStmt = ReadStr(AH);
1810 if (AH->version >= K_VERS_1_3)
1811 te->copyStmt = ReadStr(AH);
1813 if (AH->version >= K_VERS_1_6)
1814 te->namespace = ReadStr(AH);
1816 te->owner = ReadStr(AH);
1818 /* Read TOC entry dependencies */
1819 if (AH->version >= K_VERS_1_5)
1822 deps = malloc(sizeof(char *) * depSize);
1826 if (depIdx > depSize)
1829 deps = realloc(deps, sizeof(char *) * depSize);
1831 (*deps)[depIdx] = ReadStr(AH);
1833 if ((*deps)[depIdx])
1834 write_msg(modulename, "read dependency for %s -> %s\n",
1835 te->tag, (*deps)[depIdx]);
1837 } while ((*deps)[depIdx++] != NULL);
1839 if (depIdx > 1) /* We have a non-null entry */
1840 te->depOid = realloc(deps, sizeof(char *) * depIdx); /* trim it */
1842 te->depOid = NULL; /* no deps */
1847 /* Set maxOidVal etc for use in sorting */
1850 if (AH->ReadExtraTocPtr)
1851 (*AH->ReadExtraTocPtr) (AH, te);
1853 ahlog(AH, 3, "read TOC entry %d (id %d) for %s %s\n", i, te->id, te->desc, te->tag);
1855 te->prev = AH->toc->prev;
1856 AH->toc->prev->next = te;
1863 _tocEntryRequired(TocEntry *te, RestoreOptions *ropt)
1865 teReqs res = 3; /* Schema = 1, Data = 2, Both = 3 */
1867 /* If it's an ACL, maybe ignore it */
1868 if (ropt->aclsSkip && strcmp(te->desc, "ACL") == 0)
1871 if (!ropt->create && strcmp(te->desc, "DATABASE") == 0)
1874 /* Check if tablename only is wanted */
1877 if ((strcmp(te->desc, "TABLE") == 0) || (strcmp(te->desc, "TABLE DATA") == 0))
1879 if (!ropt->selTable)
1881 if (ropt->tableNames && strcmp(ropt->tableNames, te->tag) != 0)
1884 else if (strcmp(te->desc, "INDEX") == 0)
1886 if (!ropt->selIndex)
1888 if (ropt->indexNames && strcmp(ropt->indexNames, te->tag) != 0)
1891 else if (strcmp(te->desc, "FUNCTION") == 0)
1893 if (!ropt->selFunction)
1895 if (ropt->functionNames && strcmp(ropt->functionNames, te->tag) != 0)
1898 else if (strcmp(te->desc, "TRIGGER") == 0)
1900 if (!ropt->selTrigger)
1902 if (ropt->triggerNames && strcmp(ropt->triggerNames, te->tag) != 0)
1910 * Check if we had a dataDumper. Indicates if the entry is schema or
1916 * Special Case: If 'SEQUENCE SET' then it is considered a data
1919 if (strcmp(te->desc, "SEQUENCE SET") == 0)
1920 res = res & REQ_DATA;
1922 res = res & ~REQ_DATA;
1926 * Special case: <Init> type with <Max OID> tag; this is part of a
1927 * DATA restore even though it has SQL.
1929 if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
1932 /* Mask it if we only want schema */
1933 if (ropt->schemaOnly)
1934 res = res & REQ_SCHEMA;
1936 /* Mask it we only want data */
1938 res = res & REQ_DATA;
1940 /* Mask it if we don't have a schema contribition */
1941 if (!te->defn || strlen(te->defn) == 0)
1942 res = res & ~REQ_SCHEMA;
1944 /* Finally, if we used a list, limit based on that as well */
1945 if (ropt->limitToList && !ropt->idWanted[te->id - 1])
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.
1957 _doSetSessionAuth(ArchiveHandle *AH, const char *user)
1959 PQExpBuffer cmd = createPQExpBuffer();
1960 appendPQExpBuffer(cmd, "SET SESSION AUTHORIZATION ");
1962 /* SQL requires a string literal here. Might as well be
1964 appendStringLiteral(cmd, user, false);
1966 appendPQExpBuffer(cmd, "DEFAULT");
1967 appendPQExpBuffer(cmd, ";");
1969 if (RestoringToDB(AH))
1973 res = PQexec(AH->connection, cmd->data);
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));
1982 ahprintf(AH, "%s\n\n", cmd->data);
1984 destroyPQExpBuffer(cmd);
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.
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.
1999 _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user)
2001 if (!user || strlen(user) == 0
2002 || (strcmp(AH->currUser, user) == 0 && !dbname))
2003 return; /* no need to do anything */
2006 * Use SET SESSION AUTHORIZATION if allowed and no database change
2009 if (!dbname && AH->ropt->use_setsessauth)
2011 _doSetSessionAuth(AH, user);
2013 else if (AH->ropt && AH->ropt->noReconnect)
2015 /* When -R was given, don't do anything. */
2018 else if (RestoringToDB(AH))
2019 ReconnectToServer(AH, dbname, user);
2022 PQExpBuffer qry = createPQExpBuffer();
2024 appendPQExpBuffer(qry, "\\connect %s",
2025 dbname ? fmtId(dbname) : "-");
2026 appendPQExpBuffer(qry, " %s\n\n",
2029 ahprintf(AH, qry->data);
2031 destroyPQExpBuffer(qry);
2033 /* don't assume we still know the output schema */
2035 free(AH->currSchema);
2036 AH->currSchema = strdup("");
2040 * NOTE: currUser keeps track of what the imaginary session user in
2046 AH->currUser = strdup(user);
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.
2056 _reconnectAsOwner(ArchiveHandle *AH, const char *dbname, TocEntry *te)
2058 if (AH->ropt && AH->ropt->noOwner)
2061 _reconnectAsUser(AH, dbname, te->owner);
2066 * Issue the commands to select the specified schema as the current schema
2067 * in the target database.
2070 _selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
2074 if (!schemaName || *schemaName == '\0' ||
2075 strcmp(AH->currSchema, schemaName) == 0)
2076 return; /* no need to do anything */
2078 qry = createPQExpBuffer();
2080 appendPQExpBuffer(qry, "SET search_path = %s",
2082 if (strcmp(schemaName, "pg_catalog") != 0)
2083 appendPQExpBuffer(qry, ", pg_catalog");
2085 if (RestoringToDB(AH))
2089 res = PQexec(AH->connection, qry->data);
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));
2098 ahprintf(AH, "%s;\n\n", qry->data);
2101 free(AH->currSchema);
2102 AH->currSchema = strdup(schemaName);
2104 destroyPQExpBuffer(qry);
2110 _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData)
2114 /* Select owner and schema as necessary */
2115 _reconnectAsOwner(AH, NULL, te);
2116 _selectOutputSchema(AH, te->namespace);
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 : "-",
2127 if (AH->PrintExtraTocPtr !=NULL)
2128 (*AH->PrintExtraTocPtr) (AH, te);
2129 ahprintf(AH, "--\n\n");
2131 if (strlen(te->defn) > 0)
2132 ahprintf(AH, "%s\n\n", te->defn);
2138 WriteHead(ArchiveHandle *AH)
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);
2150 if (AH->compression != 0)
2151 write_msg(modulename, "WARNING: requested compression not available in this "
2152 "installation - archive will be uncompressed\n");
2154 AH->compression = 0;
2157 WriteInt(AH, AH->compression);
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));
2171 ReadHead(ArchiveHandle *AH)
2177 /* If we haven't already read the header... */
2178 if (!AH->readHeader)
2181 (*AH->ReadBufPtr) (AH, tmpMag, 5);
2183 if (strncmp(tmpMag, "PGDMP", 5) != 0)
2184 die_horribly(AH, modulename, "did not find magic string in file header\n");
2186 AH->vmaj = (*AH->ReadBytePtr) (AH);
2187 AH->vmin = (*AH->ReadBytePtr) (AH);
2189 if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0))) /* Version > 1.0 */
2190 AH->vrev = (*AH->ReadBytePtr) (AH);
2194 AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
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);
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);
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");
2209 fmt = (*AH->ReadBytePtr) (AH);
2211 if (AH->format != fmt)
2212 die_horribly(AH, modulename, "expected format (%d) differs from format found in file (%d)\n",
2216 if (AH->version >= K_VERS_1_2)
2218 if (AH->version < K_VERS_1_4)
2219 AH->compression = (*AH->ReadBytePtr) (AH);
2221 AH->compression = ReadInt(AH);
2224 AH->compression = Z_DEFAULT_COMPRESSION;
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");
2231 if (AH->version >= K_VERS_1_4)
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);
2241 AH->archdbname = ReadStr(AH);
2243 AH->createDate = mktime(&crtm);
2245 if (AH->createDate == (time_t) -1)
2246 write_msg(modulename, "WARNING: invalid creation date in header\n");
2253 _SortToc(ArchiveHandle *AH, TocSortCompareFn fn)
2259 /* Allocate an array for quicksort (TOC size + head & foot) */
2260 tea = (TocEntry **) malloc(sizeof(TocEntry *) * (AH->tocCount + 2));
2262 /* Build array of toc entries, including header at start and end */
2264 for (i = 0; i <= AH->tocCount + 1; i++)
2267 * printf("%d: %x (%x, %x) - %u\n", i, te, te->prev, te->next,
2274 /* Sort it, but ignore the header entries */
2275 qsort(&(tea[1]), AH->tocCount, sizeof(TocEntry *), fn);
2277 /* Rebuild list: this works because we have headers at each end */
2278 for (i = 1; i <= AH->tocCount; i++)
2280 tea[i]->next = tea[i + 1];
2281 tea[i]->prev = tea[i - 1];
2286 for (i = 0; i <= AH->tocCount + 1; i++)
2289 * printf("%d: %x (%x, %x) - %u\n", i, te, te->prev, te->next,
2296 AH->toc->next = tea[1];
2297 AH->toc->prev = tea[AH->tocCount];
2301 _tocSortCompareByOIDNum(const void *p1, const void *p2)
2303 TocEntry *te1 = *(TocEntry **) p1;
2304 TocEntry *te2 = *(TocEntry **) p2;
2305 Oid id1 = te1->maxOidVal;
2306 Oid id2 = te2->maxOidVal;
2309 /* printf("Comparing %u to %u\n", id1, id2); */
2311 cmpval = oidcmp(id1, id2);
2313 /* If we have a deterministic answer, return it. */
2317 /* More comparisons required */
2318 if (oideq(id1, te1->maxDepOidVal)) /* maxOid1 came from deps */
2320 if (oideq(id2, te2->maxDepOidVal)) /* maxOid2 also came from
2323 cmpval = oidcmp(te1->oidVal, te2->oidVal); /* Just compare base
2327 /* MaxOid2 was entry OID */
2329 return 1; /* entry1 > entry2 */
2333 /* must have oideq(id1, te1->oidVal) => maxOid1 = Oid1 */
2335 if (oideq(id2, te2->maxDepOidVal)) /* maxOid2 came from deps */
2337 return -1; /* entry1 < entry2 */
2340 /* MaxOid2 was entry OID - deps don't matter */
2347 * If we get here, then we've done another comparison Once again, a 0
2348 * result means we require even more
2354 * Entire OID details match, so use ID number (ie. original pg_dump
2357 return _tocSortCompareByIDNum(te1, te2);
2361 _tocSortCompareByIDNum(const void *p1, const void *p2)
2363 TocEntry *te1 = *(TocEntry **) p1;
2364 TocEntry *te2 = *(TocEntry **) p2;
2368 /* printf("Comparing %d to %d\n", id1, id2); */
2379 * Assuming Oid and depOid are set, work out the various
2380 * Oid values used in sorting.
2383 _fixupOidInfo(TocEntry *te)
2385 te->oidVal = atooid(te->oid);
2386 te->maxDepOidVal = _findMaxOID(te->depOid);
2388 /* For the purpose of sorting, find the max OID. */
2389 if (oidcmp(te->oidVal, te->maxDepOidVal) >= 0)
2390 te->maxOidVal = te->oidVal;
2392 te->maxOidVal = te->maxDepOidVal;
2396 * Find the max OID value for a given list of string Oid values
2399 _findMaxOID(const char *((*deps)[]))
2403 Oid maxOid = (Oid) 0;
2410 while ((dep = (*deps)[i++]) != NULL)
2412 currOid = atooid(dep);
2413 if (oidcmp(maxOid, currOid) < 0)
2421 * Maybe I can use this somewhere...
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');
2426 *insert into dump_blob_xref select 12345,lo_import(p || '/q.q') from pgdump_blob_path;