pg_backup_archiver.c 58.0 KB
Newer Older
B
Bruce Momjian 已提交
1 2 3 4 5 6 7 8 9 10
/*-------------------------------------------------------------------------
 *
 * pg_backup_archiver.c
 *
 *	Private implementation of the archiver routines.
 *
 *	See the headers to pg_restore for more details.
 *
 * Copyright (c) 2000, Philip Warner
 *	Rights are granted to use this software in any way so long
B
Bruce Momjian 已提交
11
 *	as this notice is not removed.
B
Bruce Momjian 已提交
12 13
 *
 *	The author is not responsible for loss or damages that may
14
 *	result from its use.
B
Bruce Momjian 已提交
15 16 17
 *
 *
 * IDENTIFICATION
18
 *		$PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.91 2004/08/04 17:13:03 tgl Exp $
19
 *
B
Bruce Momjian 已提交
20 21 22 23
 *-------------------------------------------------------------------------
 */

#include "pg_backup.h"
24
#include "pg_dump.h"
B
Bruce Momjian 已提交
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>
B
Bruce Momjian 已提交
32

33 34
#include "pqexpbuffer.h"
#include "libpq/libpq-fs.h"
35

36

37 38
typedef enum _teReqs_
{
39
	REQ_SCHEMA = 1,
40 41
	REQ_DATA = 2,
	REQ_ALL = REQ_SCHEMA + REQ_DATA
42 43
} teReqs;

44 45 46 47
const char *progname;
static char *modulename = gettext_noop("archiver");


B
Bruce Momjian 已提交
48 49
static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
		 const int compression, ArchiveMode mode);
50 51
static char 	*_getObjectFromDropStmt(const char *dropStmt, const char *type);
static void	_printTocHeader(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData);
52
static int	_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass);
53

54

55 56
static void fixPriorBlobRefs(ArchiveHandle *AH, TocEntry *blobte,
							 RestoreOptions *ropt);
57
static void _doSetFixedOutputState(ArchiveHandle *AH);
58
static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
59
static void _doSetWithOids(ArchiveHandle *AH, const bool withOids);
60 61 62
static void _reconnectToDB(ArchiveHandle *AH, const char *dbname, const char *user);
static void _becomeUser(ArchiveHandle *AH, const char *user);
static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
63
static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
64

65
static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool acl_pass);
B
Bruce Momjian 已提交
66 67
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
68
static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
B
Bruce Momjian 已提交
69 70
static void _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te);
static int	_discoverArchiveFormat(ArchiveHandle *AH);
B
Bruce Momjian 已提交
71

72 73
static void _write_msg(const char *modulename, const char *fmt, va_list ap);
static void _die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt, va_list ap);
74

B
Bruce Momjian 已提交
75 76
static int	_canRestoreBlobs(ArchiveHandle *AH);
static int	_restoringToDB(ArchiveHandle *AH);
77

78

B
Bruce Momjian 已提交
79
/*
B
Bruce Momjian 已提交
80 81 82 83
 *	Wrapper functions.
 *
 *	The objective it to make writing new formats and dumpers as simple
 *	as possible, if necessary at the expense of extra function calls etc.
B
Bruce Momjian 已提交
84 85 86 87 88 89
 *
 */


/* Create a new archive */
/* Public */
90
Archive *
B
Bruce Momjian 已提交
91 92
CreateArchive(const char *FileSpec, const ArchiveFormat fmt,
			  const int compression)
93

B
Bruce Momjian 已提交
94
{
B
Bruce Momjian 已提交
95 96 97
	ArchiveHandle *AH = _allocAH(FileSpec, fmt, compression, archModeWrite);

	return (Archive *) AH;
B
Bruce Momjian 已提交
98 99 100 101
}

/* Open an existing archive */
/* Public */
102
Archive *
B
Bruce Momjian 已提交
103
OpenArchive(const char *FileSpec, const ArchiveFormat fmt)
B
Bruce Momjian 已提交
104
{
B
Bruce Momjian 已提交
105 106 107
	ArchiveHandle *AH = _allocAH(FileSpec, fmt, 0, archModeRead);

	return (Archive *) AH;
B
Bruce Momjian 已提交
108 109 110
}

/* Public */
B
Bruce Momjian 已提交
111 112
void
CloseArchive(Archive *AHX)
B
Bruce Momjian 已提交
113
{
B
Bruce Momjian 已提交
114 115 116 117
	int			res = 0;
	ArchiveHandle *AH = (ArchiveHandle *) AHX;

	(*AH->ClosePtr) (AH);
B
Bruce Momjian 已提交
118

B
Bruce Momjian 已提交
119 120
	/* Close the output */
	if (AH->gzOut)
121
		res = GZCLOSE(AH->OF);
B
Bruce Momjian 已提交
122
	else if (AH->OF != stdout)
123 124 125
		res = fclose(AH->OF);

	if (res != 0)
126
		die_horribly(AH, modulename, "could not close output archive file\n");
B
Bruce Momjian 已提交
127 128 129
}

/* Public */
B
Bruce Momjian 已提交
130 131
void
RestoreArchive(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
132
{
B
Bruce Momjian 已提交
133 134
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *te = AH->toc->next;
135
	teReqs		reqs;
B
Bruce Momjian 已提交
136 137
	OutputContext sav;
	int			impliedDataOnly;
138
	bool		defnDumped;
B
Bruce Momjian 已提交
139

140 141
	AH->ropt = ropt;

142 143 144 145 146
	/*
	 * Check for nonsensical option combinations.
	 *
	 * NB: create+dropSchema is useless because if you're creating the DB,
	 * there's no need to drop individual items in it.  Moreover, if we
147 148 149
	 * tried to do that then we'd issue the drops in the database
	 * initially connected to, not the one we will create, which is very
	 * bad...
150 151 152 153
	 */
	if (ropt->create && ropt->dropSchema)
		die_horribly(AH, modulename, "-C and -c are incompatible options\n");

154 155 156 157 158
	/*
	 * If we're using a DB connection, then connect it.
	 */
	if (ropt->useDB)
	{
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 164 165 166
		/* XXX Should get this from the archive */
		AHX->minRemoteVersion = 070100;
		AHX->maxRemoteVersion = 999999;

167 168
		ConnectDatabase(AHX, ropt->dbname,
						ropt->pghost, ropt->pgport, ropt->username,
B
Bruce Momjian 已提交
169
						ropt->requirePassword, ropt->ignoreVersion);
170 171
	}

172
	/*
B
Bruce Momjian 已提交
173 174
	 * Work out if we have an implied data-only restore. This can happen
	 * if the dump was data only or if the user has used a toc list to
B
Bruce Momjian 已提交
175 176
	 * exclude all of the schema data. All we do is look for schema
	 * entries - if none are found then we set the dataOnly flag.
177
	 *
B
Bruce Momjian 已提交
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).
B
Bruce Momjian 已提交
180 181 182
	 */
	if (!ropt->dataOnly)
	{
183 184
		te = AH->toc->next;
		impliedDataOnly = 1;
B
Bruce Momjian 已提交
185 186
		while (te != AH->toc)
		{
187
			reqs = _tocEntryRequired(te, ropt, false);
188
			if ((reqs & REQ_SCHEMA) != 0)
B
Bruce Momjian 已提交
189
			{					/* It's schema, and it's wanted */
190 191 192 193 194 195 196 197
				impliedDataOnly = 0;
				break;
			}
			te = te->next;
		}
		if (impliedDataOnly)
		{
			ropt->dataOnly = impliedDataOnly;
198
			ahlog(AH, 1, "implied data-only restore\n");
199
		}
B
Bruce Momjian 已提交
200
	}
201

202
	/*
B
Bruce Momjian 已提交
203
	 * Setup the output file if necessary.
204
	 */
B
Bruce Momjian 已提交
205
	if (ropt->filename || ropt->compression)
206
		sav = SetOutput(AH, ropt->filename, ropt->compression);
B
Bruce Momjian 已提交
207

208
	ahprintf(AH, "--\n-- PostgreSQL database dump\n--\n\n");
B
Bruce Momjian 已提交
209

210 211 212 213 214
	/*
	 * Establish important parameter values right away.
	 */
	_doSetFixedOutputState(AH);

B
Bruce Momjian 已提交
215 216
	/*
	 * Drop the items at the start, in reverse order
217
	 */
B
Bruce Momjian 已提交
218 219
	if (ropt->dropSchema)
	{
220
		te = AH->toc->prev;
B
Bruce Momjian 已提交
221 222
		while (te != AH->toc)
		{
223
			reqs = _tocEntryRequired(te, ropt, false);
224
			if (((reqs & REQ_SCHEMA) != 0) && te->dropStmt)
225 226
			{
				/* We want the schema */
227
				ahlog(AH, 1, "dropping %s %s\n", te->desc, te->tag);
228
				/* Select owner and schema as necessary */
229
				_becomeOwner(AH, te);
230
				_selectOutputSchema(AH, te->namespace);
231
				/* Drop it */
232 233 234 235
				ahprintf(AH, "%s", te->dropStmt);
			}
			te = te->prev;
		}
B
Bruce Momjian 已提交
236
	}
B
Bruce Momjian 已提交
237

238 239 240
	/*
	 * Now process each TOC entry
	 */
B
Bruce Momjian 已提交
241 242 243
	te = AH->toc->next;
	while (te != AH->toc)
	{
244
		/* Work out what, if anything, we want from this entry */
245
		reqs = _tocEntryRequired(te, ropt, false);
246

247 248 249
		/* Dump any relevant dump warnings to stderr */
		if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
		{
250
			if (!ropt->dataOnly && te->defn != NULL && strlen(te->defn) != 0)
251 252 253
				write_msg(modulename, "warning from original dump file: %s\n", te->defn);
			else if (te->copyStmt != NULL && strlen(te->copyStmt) != 0)
				write_msg(modulename, "warning from original dump file: %s\n", te->copyStmt);
254
		}
255

256 257
		defnDumped = false;

258
		if ((reqs & REQ_SCHEMA) != 0)	/* We want the schema */
259
		{
260
			ahlog(AH, 1, "creating %s %s\n", te->desc, te->tag);
261

262
			_printTocEntry(AH, te, ropt, false, false);
263
			defnDumped = true;
264 265

			/* If we created a DB, connect to it... */
B
Bruce Momjian 已提交
266
			if (strcmp(te->desc, "DATABASE") == 0)
267
			{
268
				ahlog(AH, 1, "connecting to new database \"%s\" as user \"%s\"\n", te->tag, te->owner);
269
				_reconnectToDB(AH, te->tag, te->owner);
270
			}
271
		}
B
Bruce Momjian 已提交
272

B
Bruce Momjian 已提交
273
		/*
274
		 * If we have a data component, then process it
275
		 */
276
		if ((reqs & REQ_DATA) != 0)
B
Bruce Momjian 已提交
277
		{
278 279 280 281 282
			/*
			 * hadDumper will be set if there is genuine data component
			 * for this node. Otherwise, we need to check the defn field
			 * for statements that need to be executed in data-only
			 * restores.
283
			 */
284
			if (te->hadDumper)
285 286
			{
				/*
287
				 * If we can output the data, then restore it.
288
				 */
289
				if (AH->PrintTocDataPtr != NULL && (reqs & REQ_DATA) != 0)
290 291 292
				{
#ifndef HAVE_LIBZ
					if (AH->compression != 0)
293
						die_horribly(AH, modulename, "cannot restore from compressed archive (not configured for compression support)\n");
294
#endif
295

296
					_printTocEntry(AH, te, ropt, true, false);
297 298

					/*
299 300
					 * Maybe we can't do BLOBS, so check if this node is
					 * for BLOBS
301
					 */
302 303
					if ((strcmp(te->desc, "BLOBS") == 0) &&
						!_canRestoreBlobs(AH))
304 305 306 307
					{
						ahprintf(AH, "--\n-- SKIPPED \n--\n\n");

						/*
308 309 310
						 * This is a bit nasty - we assume, for the
						 * moment, that if a custom output is used, then
						 * we don't want warnings.
311 312
						 */
						if (!AH->CustomOutPtr)
313
							write_msg(modulename, "WARNING: skipping large-object restoration\n");
314 315 316 317 318
					}
					else
					{
						_disableTriggersIfNecessary(AH, te, ropt);

319 320
						/* Select owner and schema as necessary */
						_becomeOwner(AH, te);
321
						_selectOutputSchema(AH, te->namespace);
322

323
						ahlog(AH, 1, "restoring data for table \"%s\"\n", te->tag);
324 325

						/*
326 327 328 329 330
						 * If we have a copy statement, use it. As of
						 * V1.3, these are separate to allow easy import
						 * from withing a database connection. Pre 1.3
						 * archives can not use DB connections and are
						 * sent to output only.
331
						 *
332 333 334
						 * For V1.3+, the table data MUST have a copy
						 * statement so that we can go into appropriate
						 * mode with libpq.
335 336 337 338 339 340
						 */
						if (te->copyStmt && strlen(te->copyStmt) > 0)
							ahprintf(AH, te->copyStmt);

						(*AH->PrintTocDataPtr) (AH, te, ropt);

341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
						/*
						 * If we just restored blobs, fix references in
						 * previously-loaded tables; otherwise, if we
						 * previously restored blobs, fix references in
						 * this table.  Note that in standard cases the BLOBS
						 * entry comes after all TABLE DATA entries, but
						 * we should cope with other orders in case the
						 * user demands reordering.
						 */
						if (strcmp(te->desc, "BLOBS") == 0)
							fixPriorBlobRefs(AH, te, ropt);
						else if (AH->createdBlobXref &&
								 strcmp(te->desc, "TABLE DATA") == 0)
						{
							ahlog(AH, 1, "fixing up large-object cross-reference for \"%s\"\n", te->tag);
							FixupBlobRefs(AH, te);
						}

359 360 361
						_enableTriggersIfNecessary(AH, te, ropt);
					}
				}
362 363 364 365
			}
			else if (!defnDumped)
			{
				/* If we haven't already dumped the defn part, do so now */
366
				ahlog(AH, 1, "executing %s %s\n", te->desc, te->tag);
367
				_printTocEntry(AH, te, ropt, false, false);
368 369 370
			}
		}
		te = te->next;
371
	}		/* end loop over TOC entries */
B
Bruce Momjian 已提交
372

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
	/*
	 * Scan TOC again to output ownership commands and ACLs
	 */
	te = AH->toc->next;
	while (te != AH->toc)
	{
		/* Work out what, if anything, we want from this entry */
		reqs = _tocEntryRequired(te, ropt, true);

		defnDumped = false;

		if ((reqs & REQ_SCHEMA) != 0)	/* We want the schema */
		{
			ahlog(AH, 1, "setting owner and acl for %s %s\n", te->desc, te->tag);

			_printTocEntry(AH, te, ropt, false, true);
			defnDumped = true;
		}

		te = te->next;
	}

395
	/*
396
	 * Clean up & we're done.
397
	 */
398 399 400 401 402 403 404 405 406 407 408 409 410 411
	if (ropt->filename || ropt->compression)
		ResetOutput(AH, sav);

	if (ropt->useDB)
	{
		PQfinish(AH->connection);
		AH->connection = NULL;

		if (AH->blobConnection)
		{
			PQfinish(AH->blobConnection);
			AH->blobConnection = NULL;
		}
	}
412 413

	ahprintf(AH, "--\n-- PostgreSQL database dump complete\n--\n\n");
414 415 416 417 418 419 420 421 422 423 424 425 426 427
}

/*
 * After restoring BLOBS, fix all blob references in previously-restored
 * tables.  (Normally, the BLOBS entry should appear after all TABLE DATA
 * entries, so this will in fact handle all blob references.)
 */
static void
fixPriorBlobRefs(ArchiveHandle *AH, TocEntry *blobte, RestoreOptions *ropt)
{
	TocEntry   *te;
	teReqs		reqs;

	if (AH->createdBlobXref)
428
	{
429
		/* NULL parameter means disable ALL user triggers */
430
		_disableTriggersIfNecessary(AH, NULL, ropt);
431

432
		for (te = AH->toc->next; te != blobte; te = te->next)
B
Bruce Momjian 已提交
433 434 435
		{
			if (strcmp(te->desc, "TABLE DATA") == 0)
			{
436
				reqs = _tocEntryRequired(te, ropt, false);
437

438
				if ((reqs & REQ_DATA) != 0)		/* We loaded the data */
439
				{
440
					ahlog(AH, 1, "fixing up large-object cross-reference for \"%s\"\n", te->tag);
441
					FixupBlobRefs(AH, te);
442 443 444
				}
			}
		}
445 446

		/* NULL parameter means enable ALL user triggers */
447
		_enableTriggersIfNecessary(AH, NULL, ropt);
448
	}
B
Bruce Momjian 已提交
449 450
}

451 452 453 454
/*
 * Allocate a new RestoreOptions block.
 * This is mainly so we can initialize it, but also for future expansion,
 */
B
Bruce Momjian 已提交
455 456
RestoreOptions *
NewRestoreOptions(void)
B
Bruce Momjian 已提交
457
{
B
Bruce Momjian 已提交
458
	RestoreOptions *opts;
B
Bruce Momjian 已提交
459

B
Bruce Momjian 已提交
460
	opts = (RestoreOptions *) calloc(1, sizeof(RestoreOptions));
B
Bruce Momjian 已提交
461 462

	opts->format = archUnknown;
463
	opts->suppressDumpWarnings = false;
B
Bruce Momjian 已提交
464 465 466 467

	return opts;
}

468 469 470 471
/*
 * Returns true if we're restoring directly to the database (and
 * aren't just making a psql script that can do the restoration).
 */
B
Bruce Momjian 已提交
472 473
static int
_restoringToDB(ArchiveHandle *AH)
474 475 476 477
{
	return (AH->ropt->useDB && AH->connection);
}

B
Bruce Momjian 已提交
478 479
static int
_canRestoreBlobs(ArchiveHandle *AH)
480 481 482 483
{
	return _restoringToDB(AH);
}

B
Bruce Momjian 已提交
484 485
static void
_disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
B
Bruce Momjian 已提交
486
{
487 488
	/* This hack is only needed in a data-only restore */
	if (!ropt->dataOnly || !ropt->disable_triggers)
489 490
		return;

491 492 493 494
	/* Don't do it for the BLOBS TocEntry, either */
	if (te && strcmp(te->desc, "BLOBS") == 0)
		return;

495
	/*
B
Bruce Momjian 已提交
496
	 * Become superuser if possible, since they are the only ones who can
497 498
	 * update pg_class.  If -S was not given, assume the initial user identity
	 * is a superuser.
499
	 */
500
	_becomeUser(AH, ropt->superuser);
501

502
	ahlog(AH, 1, "disabling triggers\n");
503 504

	/*
B
Bruce Momjian 已提交
505 506
	 * Disable them. This is a hack. Needs to be done via an appropriate
	 * 'SET' command when one is available.
507
	 */
B
Bruce Momjian 已提交
508
	ahprintf(AH, "-- Disable triggers\n");
509 510

	/*
511 512
	 * Just update the AFFECTED table, if known.  Otherwise update all
	 * non-system tables.
513
	 */
514
	if (te && te->tag && strlen(te->tag) > 0)
515 516
		ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = 0 "
				 "WHERE oid = '%s'::pg_catalog.regclass;\n\n",
517
				 fmtId(te->tag));
518
	else
519
		ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = 0 FROM pg_catalog.pg_namespace "
520
				 "WHERE relnamespace = pg_namespace.oid AND nspname !~ '^pg_';\n\n");
B
Bruce Momjian 已提交
521 522
}

B
Bruce Momjian 已提交
523 524
static void
_enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
B
Bruce Momjian 已提交
525
{
526 527
	/* This hack is only needed in a data-only restore */
	if (!ropt->dataOnly || !ropt->disable_triggers)
528 529
		return;

530 531 532 533
	/* Don't do it for the BLOBS TocEntry, either */
	if (te && strcmp(te->desc, "BLOBS") == 0)
		return;

534
	/*
B
Bruce Momjian 已提交
535
	 * Become superuser if possible, since they are the only ones who can
536 537
	 * update pg_class.  If -S was not given, assume the initial user identity
	 * is a superuser.
538
	 */
539
	_becomeUser(AH, ropt->superuser);
540

541
	ahlog(AH, 1, "enabling triggers\n");
542 543

	/*
B
Bruce Momjian 已提交
544 545
	 * Enable them. This is a hack. Needs to be done via an appropriate
	 * 'SET' command when one is available.
546
	 */
B
Bruce Momjian 已提交
547
	ahprintf(AH, "-- Enable triggers\n");
548 549

	/*
550 551
	 * Just update the AFFECTED table, if known.  Otherwise update all
	 * non-system tables.
552
	 */
553
	if (te && te->tag && strlen(te->tag) > 0)
554
		ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = "
555
				 "(SELECT pg_catalog.count(*) FROM pg_catalog.pg_trigger where pg_class.oid = tgrelid) "
556
				 "WHERE oid = '%s'::pg_catalog.regclass;\n\n",
557
				 fmtId(te->tag));
B
Bruce Momjian 已提交
558
	else
559
		ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = "
560
				 "(SELECT pg_catalog.count(*) FROM pg_catalog.pg_trigger where pg_class.oid = tgrelid) "
561
				 "FROM pg_catalog.pg_namespace "
562
				 "WHERE relnamespace = pg_namespace.oid AND nspname !~ '^pg_';\n\n");
563
}
B
Bruce Momjian 已提交
564 565

/*
566
 * This is a routine that is part of the dumper interface, hence the 'Archive*' parameter.
B
Bruce Momjian 已提交
567 568 569
 */

/* Public */
P
Peter Eisentraut 已提交
570 571
size_t
WriteData(Archive *AHX, const void *data, size_t dLen)
B
Bruce Momjian 已提交
572
{
B
Bruce Momjian 已提交
573
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
B
Bruce Momjian 已提交
574

575
	if (!AH->currToc)
576
		die_horribly(AH, modulename, "internal error -- WriteData cannot be called outside the context of a DataDumper routine\n");
577

B
Bruce Momjian 已提交
578
	return (*AH->WriteDataPtr) (AH, data, dLen);
B
Bruce Momjian 已提交
579 580 581
}

/*
B
Bruce Momjian 已提交
582
 * Create a new TOC entry. The TOC was designed as a TOC, but is now the
B
Bruce Momjian 已提交
583 584 585 586
 * repository for all metadata. But the name has stuck.
 */

/* Public */
B
Bruce Momjian 已提交
587
void
588 589 590
ArchiveEntry(Archive *AHX,
			 CatalogId catalogId, DumpId dumpId,
			 const char *tag,
591
			 const char *namespace, const char *owner, bool withOids,
592 593 594
			 const char *desc, const char *defn,
			 const char *dropStmt, const char *copyStmt,
			 const DumpId *deps, int nDeps,
B
Bruce Momjian 已提交
595
			 DataDumperPtr dumpFn, void *dumpArg)
B
Bruce Momjian 已提交
596
{
B
Bruce Momjian 已提交
597 598 599 600 601
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *newToc;

	newToc = (TocEntry *) calloc(1, sizeof(TocEntry));
	if (!newToc)
602
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
603

604 605 606 607
	AH->tocCount++;
	if (dumpId > AH->maxDumpId)
		AH->maxDumpId = dumpId;

B
Bruce Momjian 已提交
608 609 610 611 612
	newToc->prev = AH->toc->prev;
	newToc->next = AH->toc;
	AH->toc->prev->next = newToc;
	AH->toc->prev = newToc;

613 614
	newToc->catalogId = catalogId;
	newToc->dumpId = dumpId;
615

616
	newToc->tag = strdup(tag);
617 618
	newToc->namespace = namespace ? strdup(namespace) : NULL;
	newToc->owner = strdup(owner);
619
	newToc->withOids = withOids;
B
Bruce Momjian 已提交
620
	newToc->desc = strdup(desc);
621 622 623
	newToc->defn = strdup(defn);
	newToc->dropStmt = strdup(dropStmt);
	newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
624

625 626 627 628 629 630 631 632 633 634 635
	if (nDeps > 0)
	{
		newToc->dependencies = (DumpId *) malloc(nDeps * sizeof(DumpId));
		memcpy(newToc->dependencies, deps, nDeps * sizeof(DumpId));
		newToc->nDeps = nDeps;
	}
	else
	{
		newToc->dependencies = NULL;
		newToc->nDeps = 0;
	}
636

637 638
	newToc->dataDumper = dumpFn;
	newToc->dataDumperArg = dumpArg;
639
	newToc->hadDumper = dumpFn ? true : false;
B
Bruce Momjian 已提交
640

641
	newToc->formatData = NULL;
B
Bruce Momjian 已提交
642

643
	if (AH->ArchiveEntryPtr != NULL)
B
Bruce Momjian 已提交
644
		(*AH->ArchiveEntryPtr) (AH, newToc);
B
Bruce Momjian 已提交
645 646 647
}

/* Public */
B
Bruce Momjian 已提交
648 649
void
PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
650
{
B
Bruce Momjian 已提交
651 652 653 654
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *te = AH->toc->next;
	OutputContext sav;
	char	   *fmtName;
B
Bruce Momjian 已提交
655

B
Bruce Momjian 已提交
656
	if (ropt->filename)
657
		sav = SetOutput(AH, ropt->filename, 0 /* no compression */);
B
Bruce Momjian 已提交
658

659 660
	ahprintf(AH, ";\n; Archive created at %s", ctime(&AH->createDate));
	ahprintf(AH, ";     dbname: %s\n;     TOC Entries: %d\n;     Compression: %d\n",
B
Bruce Momjian 已提交
661
			 AH->archdbname, AH->tocCount, AH->compression);
662

B
Bruce Momjian 已提交
663 664
	switch (AH->format)
	{
665 666 667 668 669 670 671 672 673 674 675 676
		case archFiles:
			fmtName = "FILES";
			break;
		case archCustom:
			fmtName = "CUSTOM";
			break;
		case archTar:
			fmtName = "TAR";
			break;
		default:
			fmtName = "UNKNOWN";
	}
677 678

	ahprintf(AH, ";     Dump Version: %d.%d-%d\n", AH->vmaj, AH->vmin, AH->vrev);
679
	ahprintf(AH, ";     Format: %s\n", fmtName);
T
Tom Lane 已提交
680 681
	ahprintf(AH, ";     Integer: %d bytes\n", (int) AH->intSize);
	ahprintf(AH, ";     Offset: %d bytes\n", (int) AH->offSize);
682

683
	ahprintf(AH, ";\n;\n; Selected TOC Entries:\n;\n");
B
Bruce Momjian 已提交
684

B
Bruce Momjian 已提交
685 686
	while (te != AH->toc)
	{
687
		if (_tocEntryRequired(te, ropt, false) != 0)
688 689 690
			ahprintf(AH, "%d; %u %u %s %s %s\n", te->dumpId,
					 te->catalogId.tableoid, te->catalogId.oid,
					 te->desc, te->tag, te->owner);
B
Bruce Momjian 已提交
691
		te = te->next;
B
Bruce Momjian 已提交
692
	}
B
Bruce Momjian 已提交
693

B
Bruce Momjian 已提交
694 695
	if (ropt->filename)
		ResetOutput(AH, sav);
B
Bruce Momjian 已提交
696 697
}

698 699 700 701 702
/***********
 * BLOB Archival
 ***********/

/* Called by a dumper to signal start of a BLOB */
B
Bruce Momjian 已提交
703
int
704
StartBlob(Archive *AHX, Oid oid)
705
{
B
Bruce Momjian 已提交
706
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
707

B
Bruce Momjian 已提交
708
	if (!AH->StartBlobPtr)
709
		die_horribly(AH, modulename, "large-object output not supported in chosen format\n");
710

B
Bruce Momjian 已提交
711
	(*AH->StartBlobPtr) (AH, AH->currToc, oid);
712

B
Bruce Momjian 已提交
713
	return 1;
714 715 716
}

/* Called by a dumper to signal end of a BLOB */
B
Bruce Momjian 已提交
717
int
718
EndBlob(Archive *AHX, Oid oid)
719
{
B
Bruce Momjian 已提交
720
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
721

B
Bruce Momjian 已提交
722 723
	if (AH->EndBlobPtr)
		(*AH->EndBlobPtr) (AH, AH->currToc, oid);
724

B
Bruce Momjian 已提交
725
	return 1;
726 727 728 729 730 731
}

/**********
 * BLOB Restoration
 **********/

732
/*
B
Bruce Momjian 已提交
733
 * Called by a format handler before any blobs are restored
734
 */
B
Bruce Momjian 已提交
735 736
void
StartRestoreBlobs(ArchiveHandle *AH)
737 738 739 740 741
{
	AH->blobCount = 0;
}

/*
B
Bruce Momjian 已提交
742
 * Called by a format handler after all blobs are restored
743
 */
B
Bruce Momjian 已提交
744 745
void
EndRestoreBlobs(ArchiveHandle *AH)
746 747 748
{
	if (AH->txActive)
	{
749
		ahlog(AH, 2, "committing large-object transactions\n");
750 751 752 753 754 755
		CommitTransaction(AH);
	}

	if (AH->blobTxActive)
		CommitTransactionXref(AH);

756 757 758
	if (AH->createdBlobXref)
		CreateBlobXrefIndex(AH);

759
	ahlog(AH, 1, "restored %d large objects\n", AH->blobCount);
760 761 762
}


763 764 765
/*
 * Called by a format handler to initiate restoration of a blob
 */
B
Bruce Momjian 已提交
766
void
767
StartRestoreBlob(ArchiveHandle *AH, Oid oid)
768
{
769
	Oid			loOid;
770

771 772
	AH->blobCount++;

773 774 775
	if (!AH->createdBlobXref)
	{
		if (!AH->connection)
776
			die_horribly(AH, modulename, "cannot restore large objects without a database connection\n");
777 778 779 780 781

		CreateBlobXrefTable(AH);
		AH->createdBlobXref = 1;
	}

782 783 784
	/* Initialize the LO Buffer */
	AH->lo_buf_used = 0;

785 786 787 788 789
	/*
	 * Start long-running TXs if necessary
	 */
	if (!AH->txActive)
	{
790
		ahlog(AH, 2, "starting large-object transactions\n");
791 792 793 794
		StartTransaction(AH);
	}
	if (!AH->blobTxActive)
		StartTransactionXref(AH);
795

796 797
	loOid = lo_creat(AH->connection, INV_READ | INV_WRITE);
	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 803 804 805

	InsertBlobXref(AH, oid, loOid);

	AH->loFd = lo_open(AH->connection, loOid, INV_WRITE);
	if (AH->loFd == -1)
806
		die_horribly(AH, modulename, "could not open large object\n");
807

B
Bruce Momjian 已提交
808
	AH->writingBlob = 1;
809 810
}

B
Bruce Momjian 已提交
811
void
812
EndRestoreBlob(ArchiveHandle *AH, Oid oid)
813
{
814 815 816
	if (AH->lo_buf_used > 0)
	{
		/* Write remaining bytes from the LO buffer */
B
Bruce Momjian 已提交
817
		size_t		res;
818 819 820

		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",
P
Peter Eisentraut 已提交
822
			  (unsigned long) AH->lo_buf_used, (unsigned long) res);
823
		if (res != AH->lo_buf_used)
P
Peter Eisentraut 已提交
824
			die_horribly(AH, modulename, "could not write to large object (result: %lu, expected: %lu)\n",
B
Bruce Momjian 已提交
825
				   (unsigned long) res, (unsigned long) AH->lo_buf_used);
826 827
		AH->lo_buf_used = 0;
	}
828

B
Bruce Momjian 已提交
829 830
	lo_close(AH->connection, AH->loFd);
	AH->writingBlob = 0;
831

832 833 834
	/*
	 * Commit every BLOB_BATCH_SIZE blobs...
	 */
B
Bruce Momjian 已提交
835
	if (((AH->blobCount / BLOB_BATCH_SIZE) * BLOB_BATCH_SIZE) == AH->blobCount)
836
	{
837
		ahlog(AH, 2, "committing large-object transactions\n");
838 839 840
		CommitTransaction(AH);
		CommitTransactionXref(AH);
	}
841 842
}

B
Bruce Momjian 已提交
843 844 845 846
/***********
 * Sorting and Reordering
 ***********/

B
Bruce Momjian 已提交
847 848
void
SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
849
{
B
Bruce Momjian 已提交
850 851 852 853 854
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	FILE	   *fh;
	char		buf[1024];
	char	   *cmnt;
	char	   *endptr;
855
	DumpId		id;
B
Bruce Momjian 已提交
856 857 858 859
	TocEntry   *te;
	TocEntry   *tePrev;

	/* Allocate space for the 'wanted' array, and init it */
860 861 862
	ropt->idWanted = (bool *) malloc(sizeof(bool) * AH->maxDumpId);
	memset(ropt->idWanted, 0, sizeof(bool) * AH->maxDumpId);
	ropt->limitToList = true;
B
Bruce Momjian 已提交
863

B
Bruce Momjian 已提交
864 865
	/* Set prev entry as head of list */
	tePrev = AH->toc;
B
Bruce Momjian 已提交
866

B
Bruce Momjian 已提交
867 868 869
	/* Setup the file */
	fh = fopen(ropt->tocFile, PG_BINARY_R);
	if (!fh)
870
		die_horribly(AH, modulename, "could not open TOC file\n");
B
Bruce Momjian 已提交
871

B
Bruce Momjian 已提交
872
	while (fgets(buf, 1024, fh) != NULL)
B
Bruce Momjian 已提交
873
	{
B
Bruce Momjian 已提交
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
		/* Find a comment */
		cmnt = strchr(buf, ';');
		if (cmnt == buf)
			continue;

		/* End string at comment */
		if (cmnt != NULL)
			cmnt[0] = '\0';

		/* Skip if all spaces */
		if (strspn(buf, " \t") == strlen(buf))
			continue;

		/* Get an ID */
		id = strtol(buf, &endptr, 10);
889
		if (endptr == buf || id <= 0 || id > AH->maxDumpId)
B
Bruce Momjian 已提交
890
		{
891
			write_msg(modulename, "WARNING: line ignored: %s\n", buf);
B
Bruce Momjian 已提交
892 893
			continue;
		}
B
Bruce Momjian 已提交
894

B
Bruce Momjian 已提交
895
		/* Find TOC entry */
896
		te = getTocEntryByDumpId(AH, id);
B
Bruce Momjian 已提交
897
		if (!te)
898 899
			die_horribly(AH, modulename, "could not find entry for ID %d\n",
						 id);
B
Bruce Momjian 已提交
900

901
		ropt->idWanted[id - 1] = true;
B
Bruce Momjian 已提交
902

B
Bruce Momjian 已提交
903 904 905
		_moveAfter(AH, tePrev, te);
		tePrev = te;
	}
B
Bruce Momjian 已提交
906

B
Bruce Momjian 已提交
907
	if (fclose(fh) != 0)
908 909
		die_horribly(AH, modulename, "could not close TOC file: %s\n",
					 strerror(errno));
B
Bruce Momjian 已提交
910 911 912 913 914 915 916 917
}

/**********************
 * 'Convenience functions that look like standard IO functions
 * for writing data when in dump mode.
 **********************/

/* Public */
B
Bruce Momjian 已提交
918 919 920 921
int
archputs(const char *s, Archive *AH)
{
	return WriteData(AH, s, strlen(s));
B
Bruce Momjian 已提交
922 923 924
}

/* Public */
B
Bruce Momjian 已提交
925 926
int
archprintf(Archive *AH, const char *fmt,...)
B
Bruce Momjian 已提交
927
{
B
Bruce Momjian 已提交
928 929 930 931 932 933 934 935 936 937 938 939
	char	   *p = NULL;
	va_list		ap;
	int			bSize = strlen(fmt) + 256;
	int			cnt = -1;

	/*
	 * This is paranoid: deal with the possibility that vsnprintf is
	 * willing to ignore trailing null
	 * or returns > 0 even if string does not fit. It may be the case that
	 * it returns cnt = bufsize
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
B
Bruce Momjian 已提交
940
	{
B
Bruce Momjian 已提交
941 942
		if (p != NULL)
			free(p);
943
		bSize *= 2;
B
Bruce Momjian 已提交
944
		p = (char *) malloc(bSize);
945
		if (p == NULL)
946
			exit_horribly(AH, modulename, "out of memory\n");
947 948 949
		va_start(ap, fmt);
		cnt = vsnprintf(p, bSize, fmt, ap);
		va_end(ap);
B
Bruce Momjian 已提交
950 951 952 953
	}
	WriteData(AH, p, cnt);
	free(p);
	return cnt;
B
Bruce Momjian 已提交
954 955 956 957 958 959 960
}


/*******************************
 * Stuff below here should be 'private' to the archiver routines
 *******************************/

B
Bruce Momjian 已提交
961 962
OutputContext
SetOutput(ArchiveHandle *AH, char *filename, int compression)
B
Bruce Momjian 已提交
963
{
B
Bruce Momjian 已提交
964
	OutputContext sav;
965
	int			fn;
B
Bruce Momjian 已提交
966 967 968 969 970 971

	/* Replace the AH output file handle */
	sav.OF = AH->OF;
	sav.gzOut = AH->gzOut;

	if (filename)
972
		fn = -1;
B
Bruce Momjian 已提交
973 974 975 976
	else if (AH->FH)
		fn = fileno(AH->FH);
	else if (AH->fSpec)
	{
977
		fn = -1;
B
Bruce Momjian 已提交
978 979 980 981 982 983
		filename = AH->fSpec;
	}
	else
		fn = fileno(stdout);

	/* If compression explicitly requested, use gzopen */
984
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
985 986
	if (compression != 0)
	{
987 988 989
		char		fmode[10];

		/* Don't use PG_BINARY_x since this is zlib */
990
		sprintf(fmode, "wb%d", compression);
991 992
		if (fn >= 0)
			AH->OF = gzdopen(dup(fn), fmode);
B
Bruce Momjian 已提交
993 994
		else
			AH->OF = gzopen(filename, fmode);
995
		AH->gzOut = 1;
B
Bruce Momjian 已提交
996 997
	}
	else
B
Bruce Momjian 已提交
998
#endif
999 1000
	{							/* Use fopen */
		if (fn >= 0)
1001
			AH->OF = fdopen(dup(fn), PG_BINARY_W);
B
Bruce Momjian 已提交
1002
		else
1003 1004
			AH->OF = fopen(filename, PG_BINARY_W);
		AH->gzOut = 0;
B
Bruce Momjian 已提交
1005
	}
B
Bruce Momjian 已提交
1006

1007
	if (!AH->OF)
1008
		die_horribly(AH, modulename, "could not open output file: %s\n", strerror(errno));
1009

B
Bruce Momjian 已提交
1010
	return sav;
B
Bruce Momjian 已提交
1011 1012
}

B
Bruce Momjian 已提交
1013 1014
void
ResetOutput(ArchiveHandle *AH, OutputContext sav)
B
Bruce Momjian 已提交
1015
{
B
Bruce Momjian 已提交
1016
	int			res;
1017

B
Bruce Momjian 已提交
1018
	if (AH->gzOut)
1019
		res = GZCLOSE(AH->OF);
B
Bruce Momjian 已提交
1020
	else
1021 1022 1023
		res = fclose(AH->OF);

	if (res != 0)
1024 1025
		die_horribly(AH, modulename, "could not close output file: %s\n",
					 strerror(errno));
B
Bruce Momjian 已提交
1026

B
Bruce Momjian 已提交
1027 1028
	AH->gzOut = sav.gzOut;
	AH->OF = sav.OF;
B
Bruce Momjian 已提交
1029 1030 1031 1032 1033
}



/*
B
Bruce Momjian 已提交
1034
 *	Print formatted text to the output file (usually stdout).
B
Bruce Momjian 已提交
1035
 */
B
Bruce Momjian 已提交
1036 1037
int
ahprintf(ArchiveHandle *AH, const char *fmt,...)
B
Bruce Momjian 已提交
1038
{
B
Bruce Momjian 已提交
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
	char	   *p = NULL;
	va_list		ap;
	int			bSize = strlen(fmt) + 256;		/* Should be enough */
	int			cnt = -1;

	/*
	 * This is paranoid: deal with the possibility that vsnprintf is
	 * willing to ignore trailing null
	 */

	/*
	 * or returns > 0 even if string does not fit. It may be the case that
	 * it returns cnt = bufsize
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
1054
	{
B
Bruce Momjian 已提交
1055 1056
		if (p != NULL)
			free(p);
1057
		bSize *= 2;
B
Bruce Momjian 已提交
1058
		p = (char *) malloc(bSize);
1059
		if (p == NULL)
1060
			die_horribly(AH, modulename, "out of memory\n");
1061
		va_start(ap, fmt);
1062
		cnt = vsnprintf(p, bSize, fmt, ap);
1063
		va_end(ap);
B
Bruce Momjian 已提交
1064 1065 1066 1067
	}
	ahwrite(p, 1, cnt, AH);
	free(p);
	return cnt;
B
Bruce Momjian 已提交
1068 1069
}

B
Bruce Momjian 已提交
1070 1071
void
ahlog(ArchiveHandle *AH, int level, const char *fmt,...)
1072 1073 1074 1075 1076 1077 1078
{
	va_list		ap;

	if (AH->debugLevel < level && (!AH->public.verbose || level > 1))
		return;

	va_start(ap, fmt);
1079
	_write_msg(NULL, fmt, ap);
1080 1081 1082
	va_end(ap);
}

1083 1084 1085
/*
 * Single place for logic which says 'We are restoring to a direct DB connection'.
 */
B
Bruce Momjian 已提交
1086 1087
int
RestoringToDB(ArchiveHandle *AH)
1088 1089 1090 1091
{
	return (AH->ropt && AH->ropt->useDB && AH->connection);
}

B
Bruce Momjian 已提交
1092
/*
B
Bruce Momjian 已提交
1093 1094 1095
 *	Write buffer to the output file (usually stdout). This is user for
 *	outputting 'restore' scripts etc. It is even possible for an archive
 *	format to create a custom output routine to 'fake' a restore if it
1096
 *	wants to generate a script (see TAR output).
B
Bruce Momjian 已提交
1097
 */
B
Bruce Momjian 已提交
1098 1099
int
ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
B
Bruce Momjian 已提交
1100
{
P
Peter Eisentraut 已提交
1101
	size_t		res;
1102

B
Bruce Momjian 已提交
1103
	if (AH->writingBlob)
1104
	{
P
Peter Eisentraut 已提交
1105 1106 1107
		if (AH->lo_buf_used + size * nmemb > AH->lo_buf_size)
		{
			/* Split LO buffer */
B
Bruce Momjian 已提交
1108 1109
			size_t		remaining = AH->lo_buf_size - AH->lo_buf_used;
			size_t		slack = nmemb * size - remaining;
P
Peter Eisentraut 已提交
1110

B
Bruce Momjian 已提交
1111
			memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining);
P
Peter Eisentraut 已提交
1112 1113 1114 1115 1116 1117
			res = lo_write(AH->connection, AH->loFd, AH->lo_buf, AH->lo_buf_size);
			ahlog(AH, 5, "wrote %lu bytes of large object data (result = %lu)\n",
				  (unsigned long) AH->lo_buf_size, (unsigned long) res);
			if (res != AH->lo_buf_size)
				die_horribly(AH, modulename,
							 "could not write to large object (result: %lu, expected: %lu)\n",
B
Bruce Momjian 已提交
1118 1119
				   (unsigned long) res, (unsigned long) AH->lo_buf_size);
			memcpy(AH->lo_buf, (char *) ptr + remaining, slack);
P
Peter Eisentraut 已提交
1120 1121 1122 1123 1124
			AH->lo_buf_used = slack;
		}
		else
		{
			/* LO Buffer is still large enough, buffer it */
B
Bruce Momjian 已提交
1125
			memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, size * nmemb);
P
Peter Eisentraut 已提交
1126 1127 1128 1129
			AH->lo_buf_used += size * nmemb;
		}

		return size * nmemb;
1130
	}
B
Bruce Momjian 已提交
1131
	else if (AH->gzOut)
1132
	{
B
Bruce Momjian 已提交
1133
		res = GZWRITE((void *) ptr, size, nmemb, AH->OF);
1134
		if (res != (nmemb * size))
1135
			die_horribly(AH, modulename, "could not write to compressed archive\n");
1136 1137
		return res;
	}
B
Bruce Momjian 已提交
1138
	else if (AH->CustomOutPtr)
1139
	{
B
Bruce Momjian 已提交
1140 1141
		res = AH->CustomOutPtr (AH, ptr, size * nmemb);

1142
		if (res != (nmemb * size))
1143
			die_horribly(AH, modulename, "could not write to custom output routine\n");
1144 1145
		return res;
	}
1146 1147 1148
	else
	{
		/*
B
Bruce Momjian 已提交
1149 1150 1151
		 * If we're doing a restore, and it's direct to DB, and we're
		 * connected then send it to the DB.
		 */
1152
		if (RestoringToDB(AH))
B
Bruce Momjian 已提交
1153
			return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb);		/* Always 1, currently */
1154
		else
1155
		{
B
Bruce Momjian 已提交
1156
			res = fwrite((void *) ptr, size, nmemb, AH->OF);
1157
			if (res != nmemb)
P
Peter Eisentraut 已提交
1158 1159
				die_horribly(AH, modulename, "could not write to output file (%lu != %lu)\n",
							 (unsigned long) res, (unsigned long) nmemb);
1160 1161
			return res;
		}
1162
	}
B
Bruce Momjian 已提交
1163
}
1164 1165

/* Common exit code */
B
Bruce Momjian 已提交
1166
static void
1167
_write_msg(const char *modulename, const char *fmt, va_list ap)
1168
{
1169
	if (modulename)
1170
		fprintf(stderr, "%s: [%s] ", progname, gettext(modulename));
1171 1172 1173 1174 1175 1176
	else
		fprintf(stderr, "%s: ", progname);
	vfprintf(stderr, gettext(fmt), ap);
}

void
1177
write_msg(const char *modulename, const char *fmt,...)
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
{
	va_list		ap;

	va_start(ap, fmt);
	_write_msg(modulename, fmt, ap);
	va_end(ap);
}


static void
_die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt, va_list ap)
{
	_write_msg(modulename, fmt, ap);
1191

B
Bruce Momjian 已提交
1192 1193
	if (AH)
	{
1194 1195
		if (AH->public.verbose)
			write_msg(NULL, "*** aborted because of error\n");
B
Bruce Momjian 已提交
1196 1197
		if (AH->connection)
			PQfinish(AH->connection);
1198 1199 1200
		if (AH->blobConnection)
			PQfinish(AH->blobConnection);
	}
1201

B
Bruce Momjian 已提交
1202
	exit(1);
B
Bruce Momjian 已提交
1203 1204
}

1205
/* External use */
B
Bruce Momjian 已提交
1206
void
1207
exit_horribly(Archive *AH, const char *modulename, const char *fmt,...)
1208
{
B
Bruce Momjian 已提交
1209
	va_list		ap;
1210

B
Bruce Momjian 已提交
1211
	va_start(ap, fmt);
1212
	_die_horribly((ArchiveHandle *) AH, modulename, fmt, ap);
1213
	va_end(ap);
1214
}
B
Bruce Momjian 已提交
1215

1216
/* Archiver use (just different arg declaration) */
B
Bruce Momjian 已提交
1217
void
1218
die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...)
B
Bruce Momjian 已提交
1219
{
B
Bruce Momjian 已提交
1220
	va_list		ap;
B
Bruce Momjian 已提交
1221

B
Bruce Momjian 已提交
1222
	va_start(ap, fmt);
1223
	_die_horribly(AH, modulename, fmt, ap);
1224
	va_end(ap);
B
Bruce Momjian 已提交
1225 1226
}

1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
/* on some error, we may decide to go on... */
void
warn_or_die_horribly(ArchiveHandle *AH, 
					 const char *modulename, const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	if (AH->public.die_on_errors)
	{
		_die_horribly(AH, modulename, fmt, ap);
	}
	else
	{
		_write_msg(modulename, fmt, ap);
		AH->public.n_errors++;
	}
	va_end(ap);
}
1245

B
Bruce Momjian 已提交
1246 1247
static void
_moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
B
Bruce Momjian 已提交
1248
{
B
Bruce Momjian 已提交
1249 1250
	te->prev->next = te->next;
	te->next->prev = te->prev;
B
Bruce Momjian 已提交
1251

B
Bruce Momjian 已提交
1252 1253
	te->prev = pos;
	te->next = pos->next;
B
Bruce Momjian 已提交
1254

B
Bruce Momjian 已提交
1255 1256
	pos->next->prev = te;
	pos->next = te;
B
Bruce Momjian 已提交
1257 1258
}

1259 1260
#ifdef NOT_USED

B
Bruce Momjian 已提交
1261 1262
static void
_moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
B
Bruce Momjian 已提交
1263
{
B
Bruce Momjian 已提交
1264 1265
	te->prev->next = te->next;
	te->next->prev = te->prev;
B
Bruce Momjian 已提交
1266

B
Bruce Momjian 已提交
1267 1268 1269 1270
	te->prev = pos->prev;
	te->next = pos;
	pos->prev->next = te;
	pos->prev = te;
B
Bruce Momjian 已提交
1271 1272
}

1273 1274
#endif

B
Bruce Momjian 已提交
1275
static TocEntry *
1276
getTocEntryByDumpId(ArchiveHandle *AH, DumpId id)
B
Bruce Momjian 已提交
1277
{
B
Bruce Momjian 已提交
1278 1279 1280 1281 1282
	TocEntry   *te;

	te = AH->toc->next;
	while (te != AH->toc)
	{
1283
		if (te->dumpId == id)
B
Bruce Momjian 已提交
1284 1285 1286 1287
			return te;
		te = te->next;
	}
	return NULL;
B
Bruce Momjian 已提交
1288 1289
}

B
Bruce Momjian 已提交
1290
int
1291
TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
B
Bruce Momjian 已提交
1292
{
1293
	TocEntry   *te = getTocEntryByDumpId(AH, id);
B
Bruce Momjian 已提交
1294

B
Bruce Momjian 已提交
1295 1296
	if (!te)
		return 0;
B
Bruce Momjian 已提交
1297

1298
	return _tocEntryRequired(te, ropt, false);
B
Bruce Momjian 已提交
1299 1300
}

1301 1302 1303
size_t
WriteOffset(ArchiveHandle *AH, off_t o, int wasSet)
{
B
Bruce Momjian 已提交
1304
	int			off;
1305 1306 1307 1308 1309 1310 1311

	/* Save the flag */
	(*AH->WriteBytePtr) (AH, wasSet);

	/* Write out off_t smallest byte first, prevents endian mismatch */
	for (off = 0; off < sizeof(off_t); off++)
	{
B
Bruce Momjian 已提交
1312
		(*AH->WriteBytePtr) (AH, o & 0xFF);
1313 1314 1315 1316 1317 1318 1319 1320
		o >>= 8;
	}
	return sizeof(off_t) + 1;
}

int
ReadOffset(ArchiveHandle *AH, off_t *o)
{
B
Bruce Momjian 已提交
1321 1322 1323
	int			i;
	int			off;
	int			offsetFlg;
1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334

	/* Initialize to zero */
	*o = 0;

	/* Check for old version */
	if (AH->version < K_VERS_1_7)
	{
		/* Prior versions wrote offsets using WriteInt */
		i = ReadInt(AH);
		/* -1 means not set */
		if (i < 0)
B
Bruce Momjian 已提交
1335
			return K_OFFSET_POS_NOT_SET;
1336
		else if (i == 0)
B
Bruce Momjian 已提交
1337
			return K_OFFSET_NO_DATA;
1338 1339

		/* Cast to off_t because it was written as an int. */
B
Bruce Momjian 已提交
1340
		*o = (off_t) i;
1341 1342 1343 1344
		return K_OFFSET_POS_SET;
	}

	/*
B
Bruce Momjian 已提交
1345 1346
	 * Read the flag indicating the state of the data pointer. Check if
	 * valid and die if not.
1347
	 *
B
Bruce Momjian 已提交
1348 1349
	 * This used to be handled by a negative or zero pointer, now we use an
	 * extra byte specifically for the state.
1350 1351 1352 1353 1354 1355 1356 1357 1358
	 */
	offsetFlg = (*AH->ReadBytePtr) (AH) & 0xFF;

	switch (offsetFlg)
	{
		case K_OFFSET_POS_NOT_SET:
		case K_OFFSET_NO_DATA:
		case K_OFFSET_POS_SET:

B
Bruce Momjian 已提交
1359
			break;
1360 1361

		default:
B
Bruce Momjian 已提交
1362
			die_horribly(AH, modulename, "Unexpected data offset flag %d\n", offsetFlg);
1363 1364 1365 1366 1367 1368 1369 1370
	}

	/*
	 * Read the bytes
	 */
	for (off = 0; off < AH->offSize; off++)
	{
		if (off < sizeof(off_t))
1371
			*o |= ((off_t) ((*AH->ReadBytePtr) (AH))) << (off * 8);
1372 1373 1374
		else
		{
			if ((*AH->ReadBytePtr) (AH) != 0)
B
Bruce Momjian 已提交
1375
				die_horribly(AH, modulename, "file offset in dump file is too large\n");
1376 1377 1378 1379 1380 1381
		}
	}

	return offsetFlg;
}

P
Peter Eisentraut 已提交
1382
size_t
B
Bruce Momjian 已提交
1383
WriteInt(ArchiveHandle *AH, int i)
B
Bruce Momjian 已提交
1384
{
B
Bruce Momjian 已提交
1385 1386 1387 1388
	int			b;

	/*
	 * This is a bit yucky, but I don't want to make the binary format
1389
	 * very dependent on representation, and not knowing much about it, I
B
Bruce Momjian 已提交
1390 1391 1392 1393 1394 1395 1396 1397 1398
	 * write out a sign byte. If you change this, don't forget to change
	 * the file version #, and modify readInt to read the new format AS
	 * WELL AS the old formats.
	 */

	/* SIGN byte */
	if (i < 0)
	{
		(*AH->WriteBytePtr) (AH, 1);
1399
		i = -i;
B
Bruce Momjian 已提交
1400 1401 1402 1403 1404 1405 1406
	}
	else
		(*AH->WriteBytePtr) (AH, 0);

	for (b = 0; b < AH->intSize; b++)
	{
		(*AH->WriteBytePtr) (AH, i & 0xFF);
1407
		i >>= 8;
B
Bruce Momjian 已提交
1408 1409 1410
	}

	return AH->intSize + 1;
B
Bruce Momjian 已提交
1411 1412
}

B
Bruce Momjian 已提交
1413 1414
int
ReadInt(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1415
{
B
Bruce Momjian 已提交
1416 1417 1418 1419 1420
	int			res = 0;
	int			bv,
				b;
	int			sign = 0;		/* Default positive */
	int			bitShift = 0;
B
Bruce Momjian 已提交
1421

B
Bruce Momjian 已提交
1422
	if (AH->version > K_VERS_1_0)
1423
		/* Read a sign byte */
B
Bruce Momjian 已提交
1424
		sign = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
1425

B
Bruce Momjian 已提交
1426 1427 1428
	for (b = 0; b < AH->intSize; b++)
	{
		bv = (*AH->ReadBytePtr) (AH) & 0xFF;
1429 1430 1431
		if (bv != 0)
			res = res + (bv << bitShift);
		bitShift += 8;
B
Bruce Momjian 已提交
1432
	}
B
Bruce Momjian 已提交
1433

B
Bruce Momjian 已提交
1434 1435
	if (sign)
		res = -res;
B
Bruce Momjian 已提交
1436

B
Bruce Momjian 已提交
1437
	return res;
B
Bruce Momjian 已提交
1438 1439
}

P
Peter Eisentraut 已提交
1440
size_t
1441
WriteStr(ArchiveHandle *AH, const char *c)
B
Bruce Momjian 已提交
1442
{
P
Peter Eisentraut 已提交
1443
	size_t		res;
1444 1445 1446 1447

	if (c)
	{
		res = WriteInt(AH, strlen(c));
B
Bruce Momjian 已提交
1448
		res += (*AH->WriteBufPtr) (AH, c, strlen(c));
1449 1450 1451 1452
	}
	else
		res = WriteInt(AH, -1);

B
Bruce Momjian 已提交
1453
	return res;
B
Bruce Momjian 已提交
1454 1455
}

B
Bruce Momjian 已提交
1456 1457
char *
ReadStr(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1458
{
B
Bruce Momjian 已提交
1459 1460
	char	   *buf;
	int			l;
B
Bruce Momjian 已提交
1461

B
Bruce Momjian 已提交
1462
	l = ReadInt(AH);
1463 1464 1465 1466
	if (l == -1)
		buf = NULL;
	else
	{
B
Bruce Momjian 已提交
1467
		buf = (char *) malloc(l + 1);
1468
		if (!buf)
1469
			die_horribly(AH, modulename, "out of memory\n");
1470

B
Bruce Momjian 已提交
1471
		(*AH->ReadBufPtr) (AH, (void *) buf, l);
1472 1473
		buf[l] = '\0';
	}
B
Bruce Momjian 已提交
1474

B
Bruce Momjian 已提交
1475
	return buf;
B
Bruce Momjian 已提交
1476 1477
}

T
Tom Lane 已提交
1478
static int
B
Bruce Momjian 已提交
1479
_discoverArchiveFormat(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1480
{
B
Bruce Momjian 已提交
1481 1482
	FILE	   *fh;
	char		sig[6];			/* More than enough */
P
Peter Eisentraut 已提交
1483
	size_t		cnt;
B
Bruce Momjian 已提交
1484
	int			wantClose = 0;
B
Bruce Momjian 已提交
1485

1486
#if 0
1487
	write_msg(modulename, "attempting to ascertain archive format\n");
1488
#endif
1489 1490 1491 1492 1493 1494 1495 1496

	if (AH->lookahead)
		free(AH->lookahead);

	AH->lookaheadSize = 512;
	AH->lookahead = calloc(1, 512);
	AH->lookaheadLen = 0;
	AH->lookaheadPos = 0;
1497

B
Bruce Momjian 已提交
1498 1499
	if (AH->fSpec)
	{
1500 1501
		wantClose = 1;
		fh = fopen(AH->fSpec, PG_BINARY_R);
B
Bruce Momjian 已提交
1502 1503
	}
	else
1504
		fh = stdin;
B
Bruce Momjian 已提交
1505

B
Bruce Momjian 已提交
1506
	if (!fh)
1507
		die_horribly(AH, modulename, "could not open input file: %s\n", strerror(errno));
B
Bruce Momjian 已提交
1508

B
Bruce Momjian 已提交
1509
	cnt = fread(sig, 1, 5, fh);
B
Bruce Momjian 已提交
1510

B
Bruce Momjian 已提交
1511
	if (cnt != 5)
1512 1513 1514 1515
	{
		if (ferror(fh))
			die_horribly(AH, modulename, "could not read input file: %s\n", strerror(errno));
		else
P
Peter Eisentraut 已提交
1516 1517
			die_horribly(AH, modulename, "input file is too short (read %lu, expected 5)\n",
						 (unsigned long) cnt);
1518
	}
B
Bruce Momjian 已提交
1519

B
Bruce Momjian 已提交
1520
	/* Save it, just in case we need it later */
1521 1522
	strncpy(&AH->lookahead[0], sig, 5);
	AH->lookaheadLen = 5;
B
Bruce Momjian 已提交
1523

B
Bruce Momjian 已提交
1524
	if (strncmp(sig, "PGDMP", 5) == 0)
1525 1526 1527 1528 1529 1530 1531 1532 1533
	{
		AH->vmaj = fgetc(fh);
		AH->vmin = fgetc(fh);

		/* Save these too... */
		AH->lookahead[AH->lookaheadLen++] = AH->vmaj;
		AH->lookahead[AH->lookaheadLen++] = AH->vmin;

		/* Check header version; varies from V1.0 */
B
Bruce Momjian 已提交
1534 1535
		if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))		/* Version > 1.0 */
		{
1536 1537 1538 1539 1540 1541
			AH->vrev = fgetc(fh);
			AH->lookahead[AH->lookaheadLen++] = AH->vrev;
		}
		else
			AH->vrev = 0;

1542 1543 1544
		/* Make a convenient integer <maj><min><rev>00 */
		AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;

1545 1546 1547
		AH->intSize = fgetc(fh);
		AH->lookahead[AH->lookaheadLen++] = AH->intSize;

1548 1549 1550 1551 1552 1553 1554 1555
		if (AH->version >= K_VERS_1_7)
		{
			AH->offSize = fgetc(fh);
			AH->lookahead[AH->lookaheadLen++] = AH->offSize;
		}
		else
			AH->offSize = AH->intSize;

1556 1557
		AH->format = fgetc(fh);
		AH->lookahead[AH->lookaheadLen++] = AH->format;
B
Bruce Momjian 已提交
1558 1559 1560
	}
	else
	{
1561
		/*
B
Bruce Momjian 已提交
1562 1563
		 * *Maybe* we have a tar archive format file... So, read first 512
		 * byte header...
1564 1565 1566
		 */
		cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh);
		AH->lookaheadLen += cnt;
B
Bruce Momjian 已提交
1567

1568
		if (AH->lookaheadLen != 512)
1569
			die_horribly(AH, modulename, "input file does not appear to be a valid archive (too short?)\n");
B
Bruce Momjian 已提交
1570

1571
		if (!isValidTarHeader(AH->lookahead))
1572
			die_horribly(AH, modulename, "input file does not appear to be a valid archive\n");
B
Bruce Momjian 已提交
1573

1574 1575
		AH->format = archTar;
	}
B
Bruce Momjian 已提交
1576

B
Bruce Momjian 已提交
1577
	/* If we can't seek, then mark the header as read */
P
Peter Eisentraut 已提交
1578
	if (fseeko(fh, 0, SEEK_SET) != 0)
1579 1580
	{
		/*
1581
		 * NOTE: Formats that use the lookahead buffer can unset this in
B
Bruce Momjian 已提交
1582
		 * their Init routine.
1583 1584 1585 1586
		 */
		AH->readHeader = 1;
	}
	else
B
Bruce Momjian 已提交
1587
		AH->lookaheadLen = 0;	/* Don't bother since we've reset the file */
1588

1589
#if 0
P
Peter Eisentraut 已提交
1590 1591
	write_msg(modulename, "read %lu bytes into lookahead buffer\n",
			  (unsigned long) AH->lookaheadLen);
1592
#endif
B
Bruce Momjian 已提交
1593

B
Bruce Momjian 已提交
1594 1595
	/* Close the file */
	if (wantClose)
1596
		if (fclose(fh) != 0)
1597 1598
			die_horribly(AH, modulename, "could not close the input file after reading header: %s\n",
						 strerror(errno));
B
Bruce Momjian 已提交
1599

B
Bruce Momjian 已提交
1600
	return AH->format;
B
Bruce Momjian 已提交
1601 1602 1603 1604 1605 1606
}


/*
 * Allocate an archive handle
 */
B
Bruce Momjian 已提交
1607 1608 1609
static ArchiveHandle *
_allocAH(const char *FileSpec, const ArchiveFormat fmt,
		 const int compression, ArchiveMode mode)
1610
{
B
Bruce Momjian 已提交
1611
	ArchiveHandle *AH;
B
Bruce Momjian 已提交
1612

1613
#if 0
1614
	write_msg(modulename, "allocating AH for %s, format %d\n", FileSpec, fmt);
1615
#endif
1616

B
Bruce Momjian 已提交
1617 1618
	AH = (ArchiveHandle *) calloc(1, sizeof(ArchiveHandle));
	if (!AH)
1619
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
1620

1621 1622
	/* AH->debugLevel = 100; */

B
Bruce Momjian 已提交
1623 1624
	AH->vmaj = K_VERS_MAJOR;
	AH->vmin = K_VERS_MINOR;
1625
	AH->vrev = K_VERS_REV;
B
Bruce Momjian 已提交
1626

1627 1628
	AH->createDate = time(NULL);

B
Bruce Momjian 已提交
1629
	AH->intSize = sizeof(int);
1630
	AH->offSize = sizeof(off_t);
B
Bruce Momjian 已提交
1631 1632
	if (FileSpec)
	{
1633
		AH->fSpec = strdup(FileSpec);
B
Bruce Momjian 已提交
1634

1635 1636 1637
		/*
		 * Not used; maybe later....
		 *
B
Bruce Momjian 已提交
1638 1639
		 * AH->workDir = strdup(FileSpec); for(i=strlen(FileSpec) ; i > 0 ;
		 * i--) if (AH->workDir[i-1] == '/')
1640
		 */
B
Bruce Momjian 已提交
1641 1642
	}
	else
1643
		AH->fSpec = NULL;
B
Bruce Momjian 已提交
1644

B
Bruce Momjian 已提交
1645 1646
	AH->currUser = strdup("");	/* So it's valid, but we can free() it
								 * later if necessary */
B
Bruce Momjian 已提交
1647
	AH->currSchema = strdup("");	/* ditto */
1648 1649
	AH->currWithOids = -1;		/* force SET */
	
B
Bruce Momjian 已提交
1650 1651
	AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry));
	if (!AH->toc)
1652
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
1653

B
Bruce Momjian 已提交
1654 1655 1656 1657 1658
	AH->toc->next = AH->toc;
	AH->toc->prev = AH->toc;

	AH->mode = mode;
	AH->compression = compression;
B
Bruce Momjian 已提交
1659

1660 1661
	AH->pgCopyBuf = createPQExpBuffer();
	AH->sqlBuf = createPQExpBuffer();
B
Bruce Momjian 已提交
1662

B
Bruce Momjian 已提交
1663 1664 1665
	/* Open stdout with no compression for AH output handle */
	AH->gzOut = 0;
	AH->OF = stdout;
B
Bruce Momjian 已提交
1666

1667
#if 0
1668
	write_msg(modulename, "archive format is %d\n", fmt);
1669
#endif
1670

B
Bruce Momjian 已提交
1671
	if (fmt == archUnknown)
1672 1673 1674
		AH->format = _discoverArchiveFormat(AH);
	else
		AH->format = fmt;
B
Bruce Momjian 已提交
1675

B
Bruce Momjian 已提交
1676 1677
	switch (AH->format)
	{
B
Bruce Momjian 已提交
1678

1679 1680 1681
		case archCustom:
			InitArchiveFmt_Custom(AH);
			break;
B
Bruce Momjian 已提交
1682

1683 1684 1685
		case archFiles:
			InitArchiveFmt_Files(AH);
			break;
B
Bruce Momjian 已提交
1686

1687 1688 1689
		case archNull:
			InitArchiveFmt_Null(AH);
			break;
B
Bruce Momjian 已提交
1690

1691 1692 1693 1694 1695
		case archTar:
			InitArchiveFmt_Tar(AH);
			break;

		default:
1696
			die_horribly(AH, modulename, "unrecognized file format \"%d\"\n", fmt);
B
Bruce Momjian 已提交
1697
	}
B
Bruce Momjian 已提交
1698

1699 1700 1701 1702
	/* sql error handling */
	AH->public.die_on_errors = true;
	AH->public.n_errors = 0;

B
Bruce Momjian 已提交
1703
	return AH;
B
Bruce Momjian 已提交
1704 1705 1706
}


B
Bruce Momjian 已提交
1707 1708
void
WriteDataChunks(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1709
{
B
Bruce Momjian 已提交
1710 1711 1712
	TocEntry   *te = AH->toc->next;
	StartDataPtr startPtr;
	EndDataPtr	endPtr;
B
Bruce Momjian 已提交
1713

B
Bruce Momjian 已提交
1714 1715 1716
	while (te != AH->toc)
	{
		if (te->dataDumper != NULL)
1717
		{
B
Bruce Momjian 已提交
1718 1719
			AH->currToc = te;
			/* printf("Writing data for %d (%x)\n", te->id, te); */
1720

B
Bruce Momjian 已提交
1721 1722 1723 1724 1725 1726 1727 1728 1729 1730
			if (strcmp(te->desc, "BLOBS") == 0)
			{
				startPtr = AH->StartBlobsPtr;
				endPtr = AH->EndBlobsPtr;
			}
			else
			{
				startPtr = AH->StartDataPtr;
				endPtr = AH->EndDataPtr;
			}
B
Bruce Momjian 已提交
1731

B
Bruce Momjian 已提交
1732 1733
			if (startPtr != NULL)
				(*startPtr) (AH, te);
B
Bruce Momjian 已提交
1734

B
Bruce Momjian 已提交
1735 1736 1737 1738 1739 1740 1741 1742 1743
			/*
			 * printf("Dumper arg for %d is %x\n", te->id,
			 * te->dataDumperArg);
			 */

			/*
			 * The user-provided DataDumper routine needs to call
			 * AH->WriteData
			 */
1744
			(*te->dataDumper) ((Archive *) AH, te->dataDumperArg);
B
Bruce Momjian 已提交
1745 1746 1747 1748 1749

			if (endPtr != NULL)
				(*endPtr) (AH, te);
			AH->currToc = NULL;
		}
1750
		te = te->next;
B
Bruce Momjian 已提交
1751
	}
B
Bruce Momjian 已提交
1752 1753
}

B
Bruce Momjian 已提交
1754 1755
void
WriteToc(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1756
{
1757 1758
	TocEntry   *te;
	char		workbuf[32];
1759
	int			i;
B
Bruce Momjian 已提交
1760 1761 1762 1763

	/* printf("%d TOC Entries to save\n", AH->tocCount); */

	WriteInt(AH, AH->tocCount);
1764 1765

	for (te = AH->toc->next; te != AH->toc; te = te->next)
B
Bruce Momjian 已提交
1766
	{
1767
		WriteInt(AH, te->dumpId);
B
Bruce Momjian 已提交
1768
		WriteInt(AH, te->dataDumper ? 1 : 0);
1769 1770 1771 1772 1773 1774

		/* OID is recorded as a string for historical reasons */
		sprintf(workbuf, "%u", te->catalogId.tableoid);
		WriteStr(AH, workbuf);
		sprintf(workbuf, "%u", te->catalogId.oid);
		WriteStr(AH, workbuf);
1775

1776
		WriteStr(AH, te->tag);
B
Bruce Momjian 已提交
1777 1778 1779 1780
		WriteStr(AH, te->desc);
		WriteStr(AH, te->defn);
		WriteStr(AH, te->dropStmt);
		WriteStr(AH, te->copyStmt);
1781
		WriteStr(AH, te->namespace);
B
Bruce Momjian 已提交
1782
		WriteStr(AH, te->owner);
1783
		WriteStr(AH, te->withOids ? "true" : "false");
1784 1785

		/* Dump list of dependencies */
1786
		for (i = 0; i < te->nDeps; i++)
1787
		{
1788 1789
			sprintf(workbuf, "%d", te->dependencies[i]);
			WriteStr(AH, workbuf);
1790
		}
1791
		WriteStr(AH, NULL);		/* Terminate List */
1792

B
Bruce Momjian 已提交
1793 1794 1795
		if (AH->WriteExtraTocPtr)
			(*AH->WriteExtraTocPtr) (AH, te);
	}
B
Bruce Momjian 已提交
1796 1797
}

B
Bruce Momjian 已提交
1798 1799
void
ReadToc(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1800
{
B
Bruce Momjian 已提交
1801
	int			i;
1802 1803
	char	   *tmp;
	DumpId	   *deps;
1804 1805
	int			depIdx;
	int			depSize;
B
Bruce Momjian 已提交
1806

B
Bruce Momjian 已提交
1807
	TocEntry   *te = AH->toc->next;
B
Bruce Momjian 已提交
1808

B
Bruce Momjian 已提交
1809
	AH->tocCount = ReadInt(AH);
1810
	AH->maxDumpId = 0;
B
Bruce Momjian 已提交
1811

B
Bruce Momjian 已提交
1812 1813 1814
	for (i = 0; i < AH->tocCount; i++)
	{
		te = (TocEntry *) calloc(1, sizeof(TocEntry));
1815 1816 1817 1818
		te->dumpId = ReadInt(AH);

		if (te->dumpId > AH->maxDumpId)
			AH->maxDumpId = te->dumpId;
1819 1820

		/* Sanity check */
1821 1822 1823 1824
		if (te->dumpId <= 0)
			die_horribly(AH, modulename,
						 "entry ID %d out of range -- perhaps a corrupt TOC\n",
						 te->dumpId);
1825 1826

		te->hadDumper = ReadInt(AH);
1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838

		if (AH->version >= K_VERS_1_8)
		{
			tmp = ReadStr(AH);
			sscanf(tmp, "%u", &te->catalogId.tableoid);
			free(tmp);
		}
		else
			te->catalogId.tableoid = InvalidOid;
		tmp = ReadStr(AH);
		sscanf(tmp, "%u", &te->catalogId.oid);
		free(tmp);
1839

1840
		te->tag = ReadStr(AH);
1841 1842 1843 1844 1845 1846 1847
		te->desc = ReadStr(AH);
		te->defn = ReadStr(AH);
		te->dropStmt = ReadStr(AH);

		if (AH->version >= K_VERS_1_3)
			te->copyStmt = ReadStr(AH);

1848 1849 1850
		if (AH->version >= K_VERS_1_6)
			te->namespace = ReadStr(AH);

1851
		te->owner = ReadStr(AH);
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861
		if (AH->version >= K_VERS_1_9)
		{
			if (strcmp(ReadStr(AH), "true") == 0)
				te->withOids = true;
			else
				te->withOids = false;
		}
		else
			te->withOids = true;
		
1862 1863 1864 1865
		/* Read TOC entry dependencies */
		if (AH->version >= K_VERS_1_5)
		{
			depSize = 100;
1866
			deps = (DumpId *) malloc(sizeof(DumpId) * depSize);
1867
			depIdx = 0;
1868
			for (;;)
1869
			{
1870 1871 1872
				tmp = ReadStr(AH);
				if (!tmp)
					break;		/* end of list */
1873
				if (depIdx >= depSize)
1874 1875
				{
					depSize *= 2;
1876
					deps = (DumpId *) realloc(deps, sizeof(DumpId) * depSize);
1877
				}
1878 1879 1880 1881
				sscanf(tmp, "%d", &deps[depIdx]);
				free(tmp);
				depIdx++;
			}
1882

1883 1884 1885 1886 1887 1888
			if (depIdx > 0)		/* We have a non-null entry */
			{
				deps = (DumpId *) realloc(deps, sizeof(DumpId) * depIdx);
				te->dependencies = deps;
				te->nDeps = depIdx;
			}
1889
			else
1890 1891
			{
				free(deps);
1892 1893
				te->dependencies = NULL;
				te->nDeps = 0;
1894
			}
1895
		}
1896
		else
1897 1898 1899 1900
		{
			te->dependencies = NULL;
			te->nDeps = 0;
		}
1901

B
Bruce Momjian 已提交
1902 1903
		if (AH->ReadExtraTocPtr)
			(*AH->ReadExtraTocPtr) (AH, te);
1904

1905 1906
		ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n",
			  i, te->dumpId, te->desc, te->tag);
1907 1908 1909 1910 1911

		te->prev = AH->toc->prev;
		AH->toc->prev->next = te;
		AH->toc->prev = te;
		te->next = AH->toc;
B
Bruce Momjian 已提交
1912
	}
B
Bruce Momjian 已提交
1913 1914
}

1915
static teReqs
1916
_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool acl_pass)
B
Bruce Momjian 已提交
1917
{
1918
	teReqs		res = 3;		/* Schema = 1, Data = 2, Both = 3 */
B
Bruce Momjian 已提交
1919

1920 1921 1922 1923
	/* ENCODING objects are dumped specially, so always reject here */
	if (strcmp(te->desc, "ENCODING") == 0)
		return 0;

B
Bruce Momjian 已提交
1924
	/* If it's an ACL, maybe ignore it */
1925
	if ((!acl_pass || ropt->aclsSkip) && strcmp(te->desc, "ACL") == 0)
1926
		return 0;
B
Bruce Momjian 已提交
1927

B
Bruce Momjian 已提交
1928
	if (!ropt->create && strcmp(te->desc, "DATABASE") == 0)
1929 1930
		return 0;

B
Bruce Momjian 已提交
1931 1932 1933 1934
	/* Check if tablename only is wanted */
	if (ropt->selTypes)
	{
		if ((strcmp(te->desc, "TABLE") == 0) || (strcmp(te->desc, "TABLE DATA") == 0))
1935 1936 1937
		{
			if (!ropt->selTable)
				return 0;
1938
			if (ropt->tableNames && strcmp(ropt->tableNames, te->tag) != 0)
1939
				return 0;
B
Bruce Momjian 已提交
1940 1941 1942
		}
		else if (strcmp(te->desc, "INDEX") == 0)
		{
1943 1944
			if (!ropt->selIndex)
				return 0;
1945
			if (ropt->indexNames && strcmp(ropt->indexNames, te->tag) != 0)
1946
				return 0;
B
Bruce Momjian 已提交
1947 1948 1949
		}
		else if (strcmp(te->desc, "FUNCTION") == 0)
		{
1950 1951
			if (!ropt->selFunction)
				return 0;
1952
			if (ropt->functionNames && strcmp(ropt->functionNames, te->tag) != 0)
1953
				return 0;
B
Bruce Momjian 已提交
1954 1955 1956
		}
		else if (strcmp(te->desc, "TRIGGER") == 0)
		{
1957 1958
			if (!ropt->selTrigger)
				return 0;
1959
			if (ropt->triggerNames && strcmp(ropt->triggerNames, te->tag) != 0)
1960 1961
				return 0;
		}
B
Bruce Momjian 已提交
1962 1963
		else
			return 0;
B
Bruce Momjian 已提交
1964 1965
	}

1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978
	/*
	 * Check if we had a dataDumper. Indicates if the entry is schema or
	 * data
	 */
	if (!te->hadDumper)
	{
		/*
		 * Special Case: If 'SEQUENCE SET' then it is considered a data
		 * entry
		 */
		if (strcmp(te->desc, "SEQUENCE SET") == 0)
			res = res & REQ_DATA;
		else
1979 1980
			res = res & ~REQ_DATA;
	}
1981

1982
	/*
1983
	 * Special case: <Init> type with <Max OID> tag; this is part of a
1984 1985
	 * DATA restore even though it has SQL.
	 */
1986
	if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
1987 1988
		res = REQ_DATA;

B
Bruce Momjian 已提交
1989 1990
	/* Mask it if we only want schema */
	if (ropt->schemaOnly)
1991
		res = res & REQ_SCHEMA;
B
Bruce Momjian 已提交
1992

B
Bruce Momjian 已提交
1993
	/* Mask it we only want data */
1994
	if (ropt->dataOnly)
1995
		res = res & REQ_DATA;
B
Bruce Momjian 已提交
1996

1997
	/* Mask it if we don't have a schema contribution */
B
Bruce Momjian 已提交
1998
	if (!te->defn || strlen(te->defn) == 0)
1999
		res = res & ~REQ_SCHEMA;
B
Bruce Momjian 已提交
2000

B
Bruce Momjian 已提交
2001
	/* Finally, if we used a list, limit based on that as well */
2002
	if (ropt->limitToList && !ropt->idWanted[te->dumpId - 1])
2003
		return 0;
B
Bruce Momjian 已提交
2004

B
Bruce Momjian 已提交
2005
	return res;
B
Bruce Momjian 已提交
2006 2007
}

2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034
/*
 * Issue SET commands for parameters that we want to have set the same way
 * at all times during execution of a restore script.
 */
static void
_doSetFixedOutputState(ArchiveHandle *AH)
{
	TocEntry   *te;

	/* If we have an encoding setting, emit that */
	te = AH->toc->next;
	while (te != AH->toc)
	{
		if (strcmp(te->desc, "ENCODING") == 0)
		{
			ahprintf(AH, "%s", te->defn);
			break;
		}
		te = te->next;
	}

	/* Make sure function checking is disabled */
	ahprintf(AH, "SET check_function_bodies = false;\n");

	ahprintf(AH, "\n");
}

2035 2036
/*
 * Issue a SET SESSION AUTHORIZATION command.  Caller is responsible
2037 2038
 * for updating state if appropriate.  If user is NULL or an empty string,
 * the specification DEFAULT will be used.
2039 2040
 */
static void
2041
_doSetSessionAuth(ArchiveHandle *AH, const char *user)
2042
{
2043
	PQExpBuffer cmd = createPQExpBuffer();
B
Bruce Momjian 已提交
2044

2045
	appendPQExpBuffer(cmd, "SET SESSION AUTHORIZATION ");
B
Bruce Momjian 已提交
2046

2047 2048 2049 2050
	/*
	 * SQL requires a string literal here.	Might as well be correct.
	 */
	if (user && *user)
2051 2052 2053 2054 2055
		appendStringLiteral(cmd, user, false);
	else
		appendPQExpBuffer(cmd, "DEFAULT");
	appendPQExpBuffer(cmd, ";");

2056 2057 2058 2059
	if (RestoringToDB(AH))
	{
		PGresult   *res;

2060
		res = PQexec(AH->connection, cmd->data);
2061 2062

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2063
			/* NOT warn_or_die_horribly... use -O instead to skip this. */
2064
			die_horribly(AH, modulename, "could not set session user to \"%s\": %s",
2065
						 user, PQerrorMessage(AH->connection));
2066 2067 2068 2069

		PQclear(res);
	}
	else
2070 2071 2072
		ahprintf(AH, "%s\n\n", cmd->data);

	destroyPQExpBuffer(cmd);
2073 2074
}

2075

2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094
/*
 * Issue a SET default_with_oids command.  Caller is responsible
 * for updating state if appropriate.
 */
static void
_doSetWithOids(ArchiveHandle *AH, const bool withOids)
{
	PQExpBuffer cmd = createPQExpBuffer();

	appendPQExpBuffer(cmd, "SET default_with_oids = %s;", withOids ?
			"true" : "false");

	if (RestoringToDB(AH))
	{
		PGresult   *res;

		res = PQexec(AH->connection, cmd->data);

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2095 2096 2097
			warn_or_die_horribly(AH, modulename, 
								 "could not set default_with_oids: %s",
								 PQerrorMessage(AH->connection));
2098 2099 2100 2101 2102 2103 2104 2105 2106 2107

		PQclear(res);
	}
	else
		ahprintf(AH, "%s\n\n", cmd->data);

	destroyPQExpBuffer(cmd);
}


2108
/*
2109 2110
 * Issue the commands to connect to the specified database
 * as the specified user.
2111 2112
 *
 * If we're currently restoring right into a database, this will
B
Bruce Momjian 已提交
2113
 * actually establish a connection. Otherwise it puts a \connect into
2114 2115
 * the script output.
 */
B
Bruce Momjian 已提交
2116
static void
2117
_reconnectToDB(ArchiveHandle *AH, const char *dbname, const char *user)
2118
{
2119
	if (RestoringToDB(AH))
2120 2121
		ReconnectToServer(AH, dbname, user);
	else
2122 2123 2124 2125
	{
		PQExpBuffer qry = createPQExpBuffer();

		appendPQExpBuffer(qry, "\\connect %s",
2126
						  dbname ? fmtId(dbname) : "-");
2127
		appendPQExpBuffer(qry, " %s\n\n",
2128
						  fmtId(user));
B
Bruce Momjian 已提交
2129

2130 2131 2132 2133
		ahprintf(AH, qry->data);

		destroyPQExpBuffer(qry);
	}
2134

2135 2136 2137 2138
	/*
	 * NOTE: currUser keeps track of what the imaginary session user in
	 * our script is
	 */
2139 2140 2141 2142
	if (AH->currUser)
		free(AH->currUser);

	AH->currUser = strdup(user);
2143 2144 2145 2146 2147

	/* don't assume we still know the output schema */
	if (AH->currSchema)
		free(AH->currSchema);
	AH->currSchema = strdup("");
2148 2149
	AH->currWithOids = -1;
	
2150 2151
	/* re-establish fixed state */
	_doSetFixedOutputState(AH);
2152 2153
}

2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178
/*
 * Become the specified user, and update state to avoid redundant commands
 *
 * NULL or empty argument is taken to mean restoring the session default
 */
static void
_becomeUser(ArchiveHandle *AH, const char *user)
{
	if (!user)
		user = "";				/* avoid null pointers */

	if (AH->currUser && strcmp(AH->currUser, user) == 0)
		return;					/* no need to do anything */

	_doSetSessionAuth(AH, user);

	/*
	 * NOTE: currUser keeps track of what the imaginary session user in
	 * our script is
	 */
	if (AH->currUser)
		free(AH->currUser);

	AH->currUser = strdup(user);
}
2179 2180

/*
2181
 * Become the owner of the the given TOC entry object.  If
2182 2183
 * changes in ownership are not allowed, this doesn't do anything.
 */
B
Bruce Momjian 已提交
2184
static void
2185
_becomeOwner(ArchiveHandle *AH, TocEntry *te)
2186
{
2187
	if (AH->ropt && (AH->ropt->noOwner || !AH->ropt->use_setsessauth))
2188 2189
		return;

2190
	_becomeUser(AH, te->owner);
2191 2192
}

2193

2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
/*
 * Set the proper default_with_oids value for the table.
 */
static void
_setWithOids(ArchiveHandle *AH, TocEntry *te)
{
	if (AH->currWithOids != te->withOids)
	{
		_doSetWithOids(AH, te->withOids);
		AH->currWithOids = te->withOids;
	}
}


2208 2209 2210 2211 2212 2213 2214
/*
 * Issue the commands to select the specified schema as the current schema
 * in the target database.
 */
static void
_selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
{
2215 2216
	PQExpBuffer qry;

2217 2218 2219 2220
	if (!schemaName || *schemaName == '\0' ||
		strcmp(AH->currSchema, schemaName) == 0)
		return;					/* no need to do anything */

2221 2222 2223
	qry = createPQExpBuffer();

	appendPQExpBuffer(qry, "SET search_path = %s",
2224
					  fmtId(schemaName));
2225 2226 2227
	if (strcmp(schemaName, "pg_catalog") != 0)
		appendPQExpBuffer(qry, ", pg_catalog");

2228 2229 2230 2231 2232 2233 2234
	if (RestoringToDB(AH))
	{
		PGresult   *res;

		res = PQexec(AH->connection, qry->data);

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2235 2236 2237
			warn_or_die_horribly(AH, modulename, 
								 "could not set search_path to \"%s\": %s",
								 schemaName, PQerrorMessage(AH->connection));
2238 2239 2240 2241

		PQclear(res);
	}
	else
2242
		ahprintf(AH, "%s;\n\n", qry->data);
2243 2244 2245 2246

	if (AH->currSchema)
		free(AH->currSchema);
	AH->currSchema = strdup(schemaName);
2247 2248

	destroyPQExpBuffer(qry);
2249 2250 2251
}


2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271
/**
 * Parses the dropStmt part of a TOC entry and returns
 * a newly allocated string that is the object identifier
 * The caller must free the result.
 */
static char *
_getObjectFromDropStmt(const char *dropStmt, const char *type)
{
	/* Chop "DROP" off the front and make a copy */
	char *first = strdup(dropStmt + 5);
	char *last = first + strlen(first) - 1; /* Points to the last real char in extract */
	char *buf = NULL;

	/* Loop from the end of the string until last char is no longer '\n' or ';' */
	while (last >= first && (*last == '\n' || *last == ';')) {
		last--;
	}

	/* Insert end of string one place after last */
	*(last + 1) = '\0';
2272

2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307
	/* Take off CASCADE if necessary.  Only TYPEs seem to have this, but may
	 * as well check for all */
	if ((last - first) >= 8) {
		if (strcmp(last - 7, " CASCADE") == 0)
			last -= 8;
	}

	/* Insert end of string one place after last */
	*(last + 1) = '\0';

	/* Special case VIEWs and SEQUENCEs.  They must use ALTER TABLE. */
	if (strcmp(type, "VIEW") == 0 && (last - first) >= 5)
	{
		int len = 6 + strlen(first + 5) + 1;
		buf = malloc(len);
		snprintf(buf, len, "TABLE %s", first + 5);
		free (first);
	}
	else if (strcmp(type, "SEQUENCE") == 0 && (last - first) >= 9)
	{
		int len = 6 + strlen(first + 9) + 1;
		buf = malloc(len);
		snprintf(buf, len, "TABLE %s", first + 9);
		free (first);
	}
	else
	{
		buf = first;
	}

	return buf;
}

static void
_printTocHeader(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData)
B
Bruce Momjian 已提交
2308
{
2309
	const char	   *pfx;
2310 2311 2312

	if (isData)
		pfx = "Data for ";
2313
	else
2314 2315
		pfx = "";

2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332
	ahprintf(AH, "--\n");
	if (AH->public.verbose)
	{
		ahprintf(AH, "-- TOC entry %d (class %u OID %u)\n",
				 te->dumpId, te->catalogId.tableoid, te->catalogId.oid);
		if (te->nDeps > 0)
		{
			int		i;

			ahprintf(AH, "-- Dependencies:");
			for (i = 0; i < te->nDeps; i++)
				ahprintf(AH, " %d", te->dependencies[i]);
			ahprintf(AH, "\n");
		}
	}
	ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s\n",
			 pfx, te->tag, te->desc,
2333 2334
			 te->namespace ? te->namespace : "-",
			 te->owner);
2335
	if (AH->PrintExtraTocPtr != NULL)
B
Bruce Momjian 已提交
2336 2337
		(*AH->PrintExtraTocPtr) (AH, te);
	ahprintf(AH, "--\n\n");
2338
}
B
Bruce Momjian 已提交
2339

2340
static int
2341
_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass)
2342 2343 2344 2345
{
	/* Select schema as necessary */
	_becomeOwner(AH, te);
	_selectOutputSchema(AH, te->namespace);
2346
	if (strcmp(te->desc, "TABLE") == 0 && !acl_pass)
2347 2348
		_setWithOids(AH, te);

2349
	if (acl_pass && strcmp(te->desc, "ACL") == 0)
2350 2351 2352
	{
		_printTocHeader(AH, te, ropt, isData);
		ahprintf(AH, "%s\n\n", te->defn);
2353
	}
2354
	else if (!acl_pass && strlen(te->defn) > 0)
2355
	{
2356 2357 2358 2359 2360
		_printTocHeader(AH, te, ropt, isData);

		/*
		 * Really crude hack for suppressing AUTHORIZATION clause of CREATE SCHEMA
		 * when --no-owner mode is selected.  This is ugly, but I see no other
2361 2362
		 * good way ...  Also, avoid dumping the public schema as it will already be
		 * created.
2363
		 */
2364 2365 2366 2367 2368 2369 2370 2371
		if (strcmp(te->tag, "public") != 0) {
			if (AH->ropt && AH->ropt->noOwner && strcmp(te->desc, "SCHEMA") == 0)
			{
				ahprintf(AH, "CREATE SCHEMA %s;\n\n\n", te->tag);
			}
			else
			{
				ahprintf(AH, "%s\n\n", te->defn);
2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390

				if (!ropt->noOwner && !ropt->use_setsessauth && strlen(te->owner) > 0 && strlen(te->dropStmt) > 0 && (
										strcmp(te->desc, "AGGREGATE") == 0 ||
										strcmp(te->desc, "CONVERSION") == 0 ||
										strcmp(te->desc, "DOMAIN") == 0 ||
										strcmp(te->desc, "FUNCTION") == 0 ||
										strcmp(te->desc, "OPERATOR") == 0 ||
										strcmp(te->desc, "OPERATOR CLASS") == 0 ||
										strcmp(te->desc, "TABLE") == 0 ||
										strcmp(te->desc, "TYPE") == 0 ||
										strcmp(te->desc, "VIEW") == 0 ||
										strcmp(te->desc, "SEQUENCE") == 0 ||
										(strcmp(te->desc, "SCHEMA") == 0 && strcmp(te->tag, "public") == 0) /* Only public schema */
										))
				{
					char *temp = _getObjectFromDropStmt(te->dropStmt, te->desc);
					ahprintf(AH, "ALTER %s OWNER TO %s;\n\n", temp, fmtId(te->owner));
					free (temp);
				} 
2391
			}
2392 2393 2394 2395
		}
	}
	else if (isData) {
		_printTocHeader(AH, te, ropt, isData);
2396
	}
B
Bruce Momjian 已提交
2397

2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408
	/*
	 * If it's an ACL entry, it might contain SET SESSION AUTHORIZATION
	 * commands, so we can no longer assume we know the current auth setting.
	 */
	if (strncmp(te->desc, "ACL", 3) == 0)
	{
		if (AH->currUser)
			free(AH->currUser);
		AH->currUser = NULL;
	}

B
Bruce Momjian 已提交
2409
	return 1;
B
Bruce Momjian 已提交
2410 2411
}

B
Bruce Momjian 已提交
2412 2413
void
WriteHead(ArchiveHandle *AH)
B
Bruce Momjian 已提交
2414
{
B
Bruce Momjian 已提交
2415
	struct tm	crtm;
2416

B
Bruce Momjian 已提交
2417 2418 2419 2420 2421
	(*AH->WriteBufPtr) (AH, "PGDMP", 5);		/* Magic code */
	(*AH->WriteBytePtr) (AH, AH->vmaj);
	(*AH->WriteBytePtr) (AH, AH->vmin);
	(*AH->WriteBytePtr) (AH, AH->vrev);
	(*AH->WriteBytePtr) (AH, AH->intSize);
2422
	(*AH->WriteBytePtr) (AH, AH->offSize);
B
Bruce Momjian 已提交
2423
	(*AH->WriteBytePtr) (AH, AH->format);
B
Bruce Momjian 已提交
2424

2425
#ifndef HAVE_LIBZ
B
Bruce Momjian 已提交
2426
	if (AH->compression != 0)
2427
		write_msg(modulename, "WARNING: requested compression not available in this "
2428
				  "installation -- archive will be uncompressed\n");
B
Bruce Momjian 已提交
2429

B
Bruce Momjian 已提交
2430
	AH->compression = 0;
2431
#endif
B
Bruce Momjian 已提交
2432

2433 2434 2435 2436 2437 2438 2439 2440 2441 2442
	WriteInt(AH, AH->compression);

	crtm = *localtime(&AH->createDate);
	WriteInt(AH, crtm.tm_sec);
	WriteInt(AH, crtm.tm_min);
	WriteInt(AH, crtm.tm_hour);
	WriteInt(AH, crtm.tm_mday);
	WriteInt(AH, crtm.tm_mon);
	WriteInt(AH, crtm.tm_year);
	WriteInt(AH, crtm.tm_isdst);
2443
	WriteStr(AH, PQdb(AH->connection));
B
Bruce Momjian 已提交
2444 2445
}

B
Bruce Momjian 已提交
2446 2447
void
ReadHead(ArchiveHandle *AH)
B
Bruce Momjian 已提交
2448
{
B
Bruce Momjian 已提交
2449 2450
	char		tmpMag[7];
	int			fmt;
2451
	struct tm	crtm;
B
Bruce Momjian 已提交
2452

2453
	/* If we haven't already read the header... */
B
Bruce Momjian 已提交
2454 2455
	if (!AH->readHeader)
	{
B
Bruce Momjian 已提交
2456

B
Bruce Momjian 已提交
2457
		(*AH->ReadBufPtr) (AH, tmpMag, 5);
B
Bruce Momjian 已提交
2458

B
Bruce Momjian 已提交
2459
		if (strncmp(tmpMag, "PGDMP", 5) != 0)
2460
			die_horribly(AH, modulename, "did not find magic string in file header\n");
B
Bruce Momjian 已提交
2461

B
Bruce Momjian 已提交
2462 2463
		AH->vmaj = (*AH->ReadBytePtr) (AH);
		AH->vmin = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
2464

B
Bruce Momjian 已提交
2465 2466 2467
		if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))		/* Version > 1.0 */
			AH->vrev = (*AH->ReadBytePtr) (AH);
		else
2468
			AH->vrev = 0;
B
Bruce Momjian 已提交
2469

B
Bruce Momjian 已提交
2470
		AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
B
Bruce Momjian 已提交
2471 2472


2473
		if (AH->version < K_VERS_1_0 || AH->version > K_VERS_MAX)
2474 2475
			die_horribly(AH, modulename, "unsupported version (%d.%d) in file header\n",
						 AH->vmaj, AH->vmin);
B
Bruce Momjian 已提交
2476

B
Bruce Momjian 已提交
2477
		AH->intSize = (*AH->ReadBytePtr) (AH);
2478
		if (AH->intSize > 32)
P
Peter Eisentraut 已提交
2479 2480
			die_horribly(AH, modulename, "sanity check on integer size (%lu) failed\n",
						 (unsigned long) AH->intSize);
B
Bruce Momjian 已提交
2481

2482
		if (AH->intSize > sizeof(int))
2483
			write_msg(modulename, "WARNING: archive was made on a machine with larger integers, some operations may fail\n");
B
Bruce Momjian 已提交
2484

2485
		if (AH->version >= K_VERS_1_7)
B
Bruce Momjian 已提交
2486
			AH->offSize = (*AH->ReadBytePtr) (AH);
2487
		else
B
Bruce Momjian 已提交
2488
			AH->offSize = AH->intSize;
2489

B
Bruce Momjian 已提交
2490
		fmt = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
2491

2492
		if (AH->format != fmt)
2493 2494
			die_horribly(AH, modulename, "expected format (%d) differs from format found in file (%d)\n",
						 AH->format, fmt);
B
Bruce Momjian 已提交
2495
	}
B
Bruce Momjian 已提交
2496

B
Bruce Momjian 已提交
2497 2498
	if (AH->version >= K_VERS_1_2)
	{
2499
		if (AH->version < K_VERS_1_4)
B
Bruce Momjian 已提交
2500
			AH->compression = (*AH->ReadBytePtr) (AH);
2501 2502
		else
			AH->compression = ReadInt(AH);
B
Bruce Momjian 已提交
2503 2504
	}
	else
2505
		AH->compression = Z_DEFAULT_COMPRESSION;
B
Bruce Momjian 已提交
2506

2507
#ifndef HAVE_LIBZ
B
Bruce Momjian 已提交
2508
	if (AH->compression != 0)
2509
		write_msg(modulename, "WARNING: archive is compressed, but this installation does not support compression -- no data will be available\n");
B
Bruce Momjian 已提交
2510 2511
#endif

2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525
	if (AH->version >= K_VERS_1_4)
	{
		crtm.tm_sec = ReadInt(AH);
		crtm.tm_min = ReadInt(AH);
		crtm.tm_hour = ReadInt(AH);
		crtm.tm_mday = ReadInt(AH);
		crtm.tm_mon = ReadInt(AH);
		crtm.tm_year = ReadInt(AH);
		crtm.tm_isdst = ReadInt(AH);

		AH->archdbname = ReadStr(AH);

		AH->createDate = mktime(&crtm);

B
Bruce Momjian 已提交
2526
		if (AH->createDate == (time_t) -1)
2527
			write_msg(modulename, "WARNING: invalid creation date in header\n");
2528 2529
	}

B
Bruce Momjian 已提交
2530 2531 2532
}


2533 2534 2535 2536 2537 2538 2539 2540 2541
/*
 * checkSeek
 *	  check to see if fseek can be performed.
 */

bool
checkSeek(FILE *fp)
{

B
Bruce Momjian 已提交
2542
	if (fseeko(fp, 0, SEEK_CUR) != 0)
2543 2544
		return false;
	else if (sizeof(off_t) > sizeof(long))
B
Bruce Momjian 已提交
2545 2546 2547 2548 2549

		/*
		 * At this point, off_t is too large for long, so we return based
		 * on whether an off_t version of fseek is available.
		 */
2550 2551 2552 2553 2554 2555 2556 2557
#ifdef HAVE_FSEEKO
		return true;
#else
		return false;
#endif
	else
		return true;
}