pg_backup_archiver.c 60.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
B
Bruce Momjian 已提交
18
 *		$PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.117 2005/10/15 02:49:38 momjian 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 <unistd.h>
B
Bruce Momjian 已提交
31

32 33 34 35
#ifdef WIN32
#include <io.h>
#endif

36 37
#include "pqexpbuffer.h"
#include "libpq/libpq-fs.h"
38

39

40
const char *progname;
41

42 43 44
static char *modulename = gettext_noop("archiver");


B
Bruce Momjian 已提交
45 46
static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
		 const int compression, ArchiveMode mode);
47
static void _getObjectDescription(PQExpBuffer buf, TocEntry *te,
B
Bruce Momjian 已提交
48
					  ArchiveHandle *AH);
49
static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass);
50

51

52
static void _doSetFixedOutputState(ArchiveHandle *AH);
53
static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
54
static void _doSetWithOids(ArchiveHandle *AH, const bool withOids);
55
static void _reconnectToDB(ArchiveHandle *AH, const char *dbname);
56 57
static void _becomeUser(ArchiveHandle *AH, const char *user);
static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
58
static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
59
static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
60

61
static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls);
B
Bruce Momjian 已提交
62 63
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
64
static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
B
Bruce Momjian 已提交
65 66
static void _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te);
static int	_discoverArchiveFormat(ArchiveHandle *AH);
B
Bruce Momjian 已提交
67

68
static void dump_lo_buf(ArchiveHandle *AH);
69 70
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);
71

72 73
static void dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim);

74

B
Bruce Momjian 已提交
75
/*
B
Bruce Momjian 已提交
76 77 78 79
 *	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 已提交
80 81 82 83 84 85
 *
 */


/* Create a new archive */
/* Public */
86
Archive *
B
Bruce Momjian 已提交
87 88
CreateArchive(const char *FileSpec, const ArchiveFormat fmt,
			  const int compression)
89

B
Bruce Momjian 已提交
90
{
B
Bruce Momjian 已提交
91 92 93
	ArchiveHandle *AH = _allocAH(FileSpec, fmt, compression, archModeWrite);

	return (Archive *) AH;
B
Bruce Momjian 已提交
94 95 96 97
}

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

	return (Archive *) AH;
B
Bruce Momjian 已提交
104 105 106
}

/* Public */
B
Bruce Momjian 已提交
107 108
void
CloseArchive(Archive *AHX)
B
Bruce Momjian 已提交
109
{
B
Bruce Momjian 已提交
110 111 112 113
	int			res = 0;
	ArchiveHandle *AH = (ArchiveHandle *) AHX;

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

B
Bruce Momjian 已提交
115 116
	/* Close the output */
	if (AH->gzOut)
117
		res = GZCLOSE(AH->OF);
B
Bruce Momjian 已提交
118
	else if (AH->OF != stdout)
119 120 121
		res = fclose(AH->OF);

	if (res != 0)
122
		die_horribly(AH, modulename, "could not close output archive file\n");
B
Bruce Momjian 已提交
123 124 125
}

/* Public */
B
Bruce Momjian 已提交
126 127
void
RestoreArchive(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
128
{
B
Bruce Momjian 已提交
129
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
130
	TocEntry   *te;
131
	teReqs		reqs;
B
Bruce Momjian 已提交
132
	OutputContext sav;
133
	bool		defnDumped;
B
Bruce Momjian 已提交
134

135
	AH->ropt = ropt;
136
	AH->stage = STAGE_INITIALIZING;
137

138 139 140 141
	/*
	 * Check for nonsensical option combinations.
	 *
	 * NB: create+dropSchema is useless because if you're creating the DB,
B
Bruce Momjian 已提交
142 143 144
	 * there's no need to drop individual items in it.  Moreover, if we 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...
145 146 147 148
	 */
	if (ropt->create && ropt->dropSchema)
		die_horribly(AH, modulename, "-C and -c are incompatible options\n");

149 150 151 152 153
	/*
	 * If we're using a DB connection, then connect it.
	 */
	if (ropt->useDB)
	{
154
		ahlog(AH, 1, "connecting to database for restore\n");
155
		if (AH->version < K_VERS_1_3)
156
			die_horribly(AH, modulename, "direct database connections are not supported in pre-1.3 archives\n");
157

158 159 160 161
		/* XXX Should get this from the archive */
		AHX->minRemoteVersion = 070100;
		AHX->maxRemoteVersion = 999999;

162 163
		ConnectDatabase(AHX, ropt->dbname,
						ropt->pghost, ropt->pgport, ropt->username,
B
Bruce Momjian 已提交
164
						ropt->requirePassword, ropt->ignoreVersion);
B
Bruce Momjian 已提交
165 166

		/*
B
Bruce Momjian 已提交
167 168
		 * If we're talking to the DB directly, don't send comments since they
		 * obscure SQL when displaying errors
B
Bruce Momjian 已提交
169
		 */
170
		AH->noTocComments = 1;
171 172
	}

173
	/*
B
Bruce Momjian 已提交
174 175 176 177
	 * 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 exclude
	 * all of the schema data. All we do is look for schema entries - if none
	 * are found then we set the dataOnly flag.
178
	 *
B
Bruce Momjian 已提交
179
	 * We could scan for wanted TABLE entries, but that is not the same as
180
	 * dataOnly. At this stage, it seems unnecessary (6-Mar-2001).
B
Bruce Momjian 已提交
181 182 183
	 */
	if (!ropt->dataOnly)
	{
B
Bruce Momjian 已提交
184
		int			impliedDataOnly = 1;
185 186

		for (te = AH->toc->next; te != AH->toc; te = te->next)
B
Bruce Momjian 已提交
187
		{
188
			reqs = _tocEntryRequired(te, ropt, true);
189
			if ((reqs & REQ_SCHEMA) != 0)
B
Bruce Momjian 已提交
190
			{					/* It's schema, and it's wanted */
191 192 193 194 195 196 197
				impliedDataOnly = 0;
				break;
			}
		}
		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
	if (AH->public.verbose)
		dumpTimestamp(AH, "Started on", AH->createDate);

213 214 215 216 217
	/*
	 * Establish important parameter values right away.
	 */
	_doSetFixedOutputState(AH);

218 219
	AH->stage = STAGE_PROCESSING;

B
Bruce Momjian 已提交
220 221
	/*
	 * Drop the items at the start, in reverse order
222
	 */
B
Bruce Momjian 已提交
223 224
	if (ropt->dropSchema)
	{
225
		for (te = AH->toc->prev; te != AH->toc; te = te->prev)
B
Bruce Momjian 已提交
226
		{
227 228
			AH->currentTE = te;

B
Bruce Momjian 已提交
229
			reqs = _tocEntryRequired(te, ropt, false /* needn't drop ACLs */ );
230
			if (((reqs & REQ_SCHEMA) != 0) && te->dropStmt)
231 232
			{
				/* We want the schema */
233
				ahlog(AH, 1, "dropping %s %s\n", te->desc, te->tag);
234
				/* Select owner and schema as necessary */
235
				_becomeOwner(AH, te);
236
				_selectOutputSchema(AH, te->namespace);
237
				/* Drop it */
238 239 240
				ahprintf(AH, "%s", te->dropStmt);
			}
		}
B
Bruce Momjian 已提交
241
	}
B
Bruce Momjian 已提交
242

243
	/*
244
	 * Now process each non-ACL TOC entry
245
	 */
246
	for (te = AH->toc->next; te != AH->toc; te = te->next)
B
Bruce Momjian 已提交
247
	{
248 249
		AH->currentTE = te;

250
		/* Work out what, if anything, we want from this entry */
251
		reqs = _tocEntryRequired(te, ropt, false);
252

253 254 255
		/* Dump any relevant dump warnings to stderr */
		if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
		{
256
			if (!ropt->dataOnly && te->defn != NULL && strlen(te->defn) != 0)
257 258 259
				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);
260
		}
261

262 263
		defnDumped = false;

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

268
			_printTocEntry(AH, te, ropt, false, false);
269
			defnDumped = true;
270 271

			/* If we created a DB, connect to it... */
B
Bruce Momjian 已提交
272
			if (strcmp(te->desc, "DATABASE") == 0)
273
			{
274 275
				ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag);
				_reconnectToDB(AH, te->tag);
276
			}
277
		}
B
Bruce Momjian 已提交
278

B
Bruce Momjian 已提交
279
		/*
280
		 * If we have a data component, then process it
281
		 */
282
		if ((reqs & REQ_DATA) != 0)
B
Bruce Momjian 已提交
283
		{
284
			/*
B
Bruce Momjian 已提交
285 286 287
			 * 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.
288
			 */
289
			if (te->hadDumper)
290 291
			{
				/*
292
				 * If we can output the data, then restore it.
293
				 */
B
Bruce Momjian 已提交
294
				if (AH->PrintTocDataPtr !=NULL && (reqs & REQ_DATA) != 0)
295 296 297
				{
#ifndef HAVE_LIBZ
					if (AH->compression != 0)
298
						die_horribly(AH, modulename, "cannot restore from compressed archive (not configured for compression support)\n");
299
#endif
300

301
					_printTocEntry(AH, te, ropt, true, false);
302

303
					if (strcmp(te->desc, "BLOBS") == 0)
304
					{
P
Peter Eisentraut 已提交
305
						ahlog(AH, 1, "restoring large object data\n");
306

307 308 309
						_selectOutputSchema(AH, "pg_catalog");

						(*AH->PrintTocDataPtr) (AH, te, ropt);
310 311 312 313 314
					}
					else
					{
						_disableTriggersIfNecessary(AH, te, ropt);

315 316
						/* Select owner and schema as necessary */
						_becomeOwner(AH, te);
317
						_selectOutputSchema(AH, te->namespace);
318

319 320
						ahlog(AH, 1, "restoring data for table \"%s\"\n",
							  te->tag);
321 322

						/*
B
Bruce Momjian 已提交
323 324 325 326
						 * 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.
327
						 *
B
Bruce Momjian 已提交
328 329
						 * For V1.3+, the table data MUST have a copy statement
						 * so that we can go into appropriate mode with libpq.
330 331
						 */
						if (te->copyStmt && strlen(te->copyStmt) > 0)
332
							ahprintf(AH, "%s", te->copyStmt);
333 334 335 336 337 338

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

						_enableTriggersIfNecessary(AH, te, ropt);
					}
				}
339 340 341 342
			}
			else if (!defnDumped)
			{
				/* If we haven't already dumped the defn part, do so now */
343
				ahlog(AH, 1, "executing %s %s\n", te->desc, te->tag);
344
				_printTocEntry(AH, te, ropt, false, false);
345 346
			}
		}
B
Bruce Momjian 已提交
347
	}							/* end loop over TOC entries */
B
Bruce Momjian 已提交
348

349 350 351
	/*
	 * Scan TOC again to output ownership commands and ACLs
	 */
352
	for (te = AH->toc->next; te != AH->toc; te = te->next)
353
	{
354 355
		AH->currentTE = te;

356 357 358 359 360
		/* Work out what, if anything, we want from this entry */
		reqs = _tocEntryRequired(te, ropt, true);

		if ((reqs & REQ_SCHEMA) != 0)	/* We want the schema */
		{
P
Peter Eisentraut 已提交
361
			ahlog(AH, 1, "setting owner and privileges for %s %s\n",
362
				  te->desc, te->tag);
363 364 365 366
			_printTocEntry(AH, te, ropt, false, true);
		}
	}

367 368 369
	if (AH->public.verbose)
		dumpTimestamp(AH, "Completed on", time(NULL));

370 371
	ahprintf(AH, "--\n-- PostgreSQL database dump complete\n--\n\n");

372
	/*
373
	 * Clean up & we're done.
374
	 */
375 376
	AH->stage = STAGE_FINALIZING;

377 378 379 380 381 382 383
	if (ropt->filename || ropt->compression)
		ResetOutput(AH, sav);

	if (ropt->useDB)
	{
		PQfinish(AH->connection);
		AH->connection = NULL;
384
	}
B
Bruce Momjian 已提交
385 386
}

387 388 389 390
/*
 * Allocate a new RestoreOptions block.
 * This is mainly so we can initialize it, but also for future expansion,
 */
B
Bruce Momjian 已提交
391 392
RestoreOptions *
NewRestoreOptions(void)
B
Bruce Momjian 已提交
393
{
B
Bruce Momjian 已提交
394
	RestoreOptions *opts;
B
Bruce Momjian 已提交
395

B
Bruce Momjian 已提交
396
	opts = (RestoreOptions *) calloc(1, sizeof(RestoreOptions));
B
Bruce Momjian 已提交
397 398

	opts->format = archUnknown;
399
	opts->suppressDumpWarnings = false;
400
	opts->exit_on_error = false;
B
Bruce Momjian 已提交
401 402 403 404

	return opts;
}

B
Bruce Momjian 已提交
405 406
static void
_disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
B
Bruce Momjian 已提交
407
{
408 409
	/* This hack is only needed in a data-only restore */
	if (!ropt->dataOnly || !ropt->disable_triggers)
410 411
		return;

412 413
	ahlog(AH, 1, "disabling triggers for %s\n", te->tag);

414
	/*
B
Bruce Momjian 已提交
415
	 * Become superuser if possible, since they are the only ones who can
416 417 418
	 * disable constraint triggers.  If -S was not given, assume the initial
	 * user identity is a superuser.  (XXX would it be better to become the
	 * table owner?)
419
	 */
420
	_becomeUser(AH, ropt->superuser);
421 422

	/*
423
	 * Disable them.
424
	 */
425
	_selectOutputSchema(AH, te->namespace);
426

427 428
	ahprintf(AH, "ALTER TABLE %s DISABLE TRIGGER ALL;\n\n",
			 fmtId(te->tag));
B
Bruce Momjian 已提交
429 430
}

B
Bruce Momjian 已提交
431 432
static void
_enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
B
Bruce Momjian 已提交
433
{
434 435
	/* This hack is only needed in a data-only restore */
	if (!ropt->dataOnly || !ropt->disable_triggers)
436 437
		return;

438 439
	ahlog(AH, 1, "enabling triggers for %s\n", te->tag);

440
	/*
B
Bruce Momjian 已提交
441
	 * Become superuser if possible, since they are the only ones who can
442 443 444
	 * disable constraint triggers.  If -S was not given, assume the initial
	 * user identity is a superuser.  (XXX would it be better to become the
	 * table owner?)
445
	 */
446
	_becomeUser(AH, ropt->superuser);
447 448

	/*
449
	 * Enable them.
450
	 */
451
	_selectOutputSchema(AH, te->namespace);
452

453 454
	ahprintf(AH, "ALTER TABLE %s ENABLE TRIGGER ALL;\n\n",
			 fmtId(te->tag));
455
}
B
Bruce Momjian 已提交
456 457

/*
458
 * This is a routine that is part of the dumper interface, hence the 'Archive*' parameter.
B
Bruce Momjian 已提交
459 460 461
 */

/* Public */
P
Peter Eisentraut 已提交
462 463
size_t
WriteData(Archive *AHX, const void *data, size_t dLen)
B
Bruce Momjian 已提交
464
{
B
Bruce Momjian 已提交
465
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
B
Bruce Momjian 已提交
466

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

B
Bruce Momjian 已提交
470
	return (*AH->WriteDataPtr) (AH, data, dLen);
B
Bruce Momjian 已提交
471 472 473
}

/*
B
Bruce Momjian 已提交
474
 * Create a new TOC entry. The TOC was designed as a TOC, but is now the
B
Bruce Momjian 已提交
475 476 477 478
 * repository for all metadata. But the name has stuck.
 */

/* Public */
B
Bruce Momjian 已提交
479
void
480 481 482
ArchiveEntry(Archive *AHX,
			 CatalogId catalogId, DumpId dumpId,
			 const char *tag,
483
			 const char *namespace,
B
Bruce Momjian 已提交
484
			 const char *tablespace,
485
			 const char *owner, bool withOids,
486 487 488
			 const char *desc, const char *defn,
			 const char *dropStmt, const char *copyStmt,
			 const DumpId *deps, int nDeps,
B
Bruce Momjian 已提交
489
			 DataDumperPtr dumpFn, void *dumpArg)
B
Bruce Momjian 已提交
490
{
B
Bruce Momjian 已提交
491 492 493 494 495
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *newToc;

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

498 499 500 501
	AH->tocCount++;
	if (dumpId > AH->maxDumpId)
		AH->maxDumpId = dumpId;

B
Bruce Momjian 已提交
502 503 504 505 506
	newToc->prev = AH->toc->prev;
	newToc->next = AH->toc;
	AH->toc->prev->next = newToc;
	AH->toc->prev = newToc;

507 508
	newToc->catalogId = catalogId;
	newToc->dumpId = dumpId;
509

510
	newToc->tag = strdup(tag);
511
	newToc->namespace = namespace ? strdup(namespace) : NULL;
512
	newToc->tablespace = tablespace ? strdup(tablespace) : NULL;
513
	newToc->owner = strdup(owner);
514
	newToc->withOids = withOids;
B
Bruce Momjian 已提交
515
	newToc->desc = strdup(desc);
516 517 518
	newToc->defn = strdup(defn);
	newToc->dropStmt = strdup(dropStmt);
	newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
519

520 521 522 523 524 525 526 527 528 529 530
	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;
	}
531

532 533
	newToc->dataDumper = dumpFn;
	newToc->dataDumperArg = dumpArg;
534
	newToc->hadDumper = dumpFn ? true : false;
B
Bruce Momjian 已提交
535

536
	newToc->formatData = NULL;
B
Bruce Momjian 已提交
537

B
Bruce Momjian 已提交
538
	if (AH->ArchiveEntryPtr !=NULL)
B
Bruce Momjian 已提交
539
		(*AH->ArchiveEntryPtr) (AH, newToc);
B
Bruce Momjian 已提交
540 541 542
}

/* Public */
B
Bruce Momjian 已提交
543 544
void
PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
545
{
B
Bruce Momjian 已提交
546 547 548 549
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *te = AH->toc->next;
	OutputContext sav;
	char	   *fmtName;
B
Bruce Momjian 已提交
550

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

554 555
	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 已提交
556
			 AH->archdbname, AH->tocCount, AH->compression);
557

B
Bruce Momjian 已提交
558 559
	switch (AH->format)
	{
560 561 562 563 564 565 566 567 568 569 570 571
		case archFiles:
			fmtName = "FILES";
			break;
		case archCustom:
			fmtName = "CUSTOM";
			break;
		case archTar:
			fmtName = "TAR";
			break;
		default:
			fmtName = "UNKNOWN";
	}
572 573

	ahprintf(AH, ";     Dump Version: %d.%d-%d\n", AH->vmaj, AH->vmin, AH->vrev);
574
	ahprintf(AH, ";     Format: %s\n", fmtName);
T
Tom Lane 已提交
575 576
	ahprintf(AH, ";     Integer: %d bytes\n", (int) AH->intSize);
	ahprintf(AH, ";     Offset: %d bytes\n", (int) AH->offSize);
577 578 579 580 581 582
	if (AH->archiveRemoteVersion)
		ahprintf(AH, ";     Dumped from database version: %s\n",
				 AH->archiveRemoteVersion);
	if (AH->archiveDumpVersion)
		ahprintf(AH, ";     Dumped by pg_dump version: %s\n",
				 AH->archiveDumpVersion);
583

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

B
Bruce Momjian 已提交
586 587
	while (te != AH->toc)
	{
588
		if (_tocEntryRequired(te, ropt, true) != 0)
589
			ahprintf(AH, "%d; %u %u %s %s %s %s\n", te->dumpId,
590
					 te->catalogId.tableoid, te->catalogId.oid,
591 592
					 te->desc, te->namespace ? te->namespace : "-",
					 te->tag, te->owner);
B
Bruce Momjian 已提交
593
		te = te->next;
B
Bruce Momjian 已提交
594
	}
B
Bruce Momjian 已提交
595

B
Bruce Momjian 已提交
596 597
	if (ropt->filename)
		ResetOutput(AH, sav);
B
Bruce Momjian 已提交
598 599
}

600 601 602 603 604
/***********
 * BLOB Archival
 ***********/

/* Called by a dumper to signal start of a BLOB */
B
Bruce Momjian 已提交
605
int
606
StartBlob(Archive *AHX, Oid oid)
607
{
B
Bruce Momjian 已提交
608
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
609

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

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

B
Bruce Momjian 已提交
615
	return 1;
616 617 618
}

/* Called by a dumper to signal end of a BLOB */
B
Bruce Momjian 已提交
619
int
620
EndBlob(Archive *AHX, Oid oid)
621
{
B
Bruce Momjian 已提交
622
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
623

B
Bruce Momjian 已提交
624 625
	if (AH->EndBlobPtr)
		(*AH->EndBlobPtr) (AH, AH->currToc, oid);
626

B
Bruce Momjian 已提交
627
	return 1;
628 629 630 631 632 633
}

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

634
/*
B
Bruce Momjian 已提交
635
 * Called by a format handler before any blobs are restored
636
 */
B
Bruce Momjian 已提交
637 638
void
StartRestoreBlobs(ArchiveHandle *AH)
639
{
640 641 642 643 644
	if (AH->connection)
		StartTransaction(AH);
	else
		ahprintf(AH, "BEGIN;\n\n");

645 646 647 648
	AH->blobCount = 0;
}

/*
B
Bruce Momjian 已提交
649
 * Called by a format handler after all blobs are restored
650
 */
B
Bruce Momjian 已提交
651 652
void
EndRestoreBlobs(ArchiveHandle *AH)
653
{
654
	if (AH->connection)
655
		CommitTransaction(AH);
656 657
	else
		ahprintf(AH, "COMMIT;\n\n");
658

659
	ahlog(AH, 1, "restored %d large objects\n", AH->blobCount);
660 661 662
}


663 664 665
/*
 * Called by a format handler to initiate restoration of a blob
 */
B
Bruce Momjian 已提交
666
void
667
StartRestoreBlob(ArchiveHandle *AH, Oid oid)
668
{
669
	Oid			loOid;
670

671 672
	AH->blobCount++;

673 674 675
	/* Initialize the LO Buffer */
	AH->lo_buf_used = 0;

676 677 678
	ahlog(AH, 2, "restoring large object with OID %u\n", oid);

	if (AH->connection)
679
	{
680 681 682 683 684 685 686 687 688 689 690 691
		loOid = lo_create(AH->connection, oid);
		if (loOid == 0 || loOid != oid)
			die_horribly(AH, modulename, "could not create large object %u\n",
						 oid);

		AH->loFd = lo_open(AH->connection, oid, INV_WRITE);
		if (AH->loFd == -1)
			die_horribly(AH, modulename, "could not open large object\n");
	}
	else
	{
		ahprintf(AH, "SELECT lo_open(lo_create(%u), %d);\n", oid, INV_WRITE);
692
	}
693

B
Bruce Momjian 已提交
694
	AH->writingBlob = 1;
695 696
}

B
Bruce Momjian 已提交
697
void
698
EndRestoreBlob(ArchiveHandle *AH, Oid oid)
699
{
700 701 702
	if (AH->lo_buf_used > 0)
	{
		/* Write remaining bytes from the LO buffer */
703
		dump_lo_buf(AH);
704
	}
705

B
Bruce Momjian 已提交
706
	AH->writingBlob = 0;
707

708
	if (AH->connection)
709
	{
710 711 712 713 714 715
		lo_close(AH->connection, AH->loFd);
		AH->loFd = -1;
	}
	else
	{
		ahprintf(AH, "SELECT lo_close(0);\n\n");
716
	}
717 718
}

B
Bruce Momjian 已提交
719 720 721 722
/***********
 * Sorting and Reordering
 ***********/

B
Bruce Momjian 已提交
723 724
void
SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
725
{
B
Bruce Momjian 已提交
726 727 728 729 730
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	FILE	   *fh;
	char		buf[1024];
	char	   *cmnt;
	char	   *endptr;
731
	DumpId		id;
B
Bruce Momjian 已提交
732 733 734 735
	TocEntry   *te;
	TocEntry   *tePrev;

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

B
Bruce Momjian 已提交
740 741
	/* Set prev entry as head of list */
	tePrev = AH->toc;
B
Bruce Momjian 已提交
742

B
Bruce Momjian 已提交
743 744 745
	/* Setup the file */
	fh = fopen(ropt->tocFile, PG_BINARY_R);
	if (!fh)
746
		die_horribly(AH, modulename, "could not open TOC file\n");
B
Bruce Momjian 已提交
747

748
	while (fgets(buf, sizeof(buf), fh) != NULL)
B
Bruce Momjian 已提交
749
	{
750
		/* Truncate line at comment, if any */
B
Bruce Momjian 已提交
751 752 753 754
		cmnt = strchr(buf, ';');
		if (cmnt != NULL)
			cmnt[0] = '\0';

755 756
		/* Ignore if all blank */
		if (strspn(buf, " \t\r") == strlen(buf))
B
Bruce Momjian 已提交
757 758
			continue;

759
		/* Get an ID, check it's valid and not already seen */
B
Bruce Momjian 已提交
760
		id = strtol(buf, &endptr, 10);
761 762
		if (endptr == buf || id <= 0 || id > AH->maxDumpId ||
			ropt->idWanted[id - 1])
B
Bruce Momjian 已提交
763
		{
764
			write_msg(modulename, "WARNING: line ignored: %s\n", buf);
B
Bruce Momjian 已提交
765 766
			continue;
		}
B
Bruce Momjian 已提交
767

B
Bruce Momjian 已提交
768
		/* Find TOC entry */
769
		te = getTocEntryByDumpId(AH, id);
B
Bruce Momjian 已提交
770
		if (!te)
771 772
			die_horribly(AH, modulename, "could not find entry for ID %d\n",
						 id);
B
Bruce Momjian 已提交
773

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

B
Bruce Momjian 已提交
776 777 778
		_moveAfter(AH, tePrev, te);
		tePrev = te;
	}
B
Bruce Momjian 已提交
779

B
Bruce Momjian 已提交
780
	if (fclose(fh) != 0)
781 782
		die_horribly(AH, modulename, "could not close TOC file: %s\n",
					 strerror(errno));
B
Bruce Momjian 已提交
783 784 785 786 787 788 789 790
}

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

/* Public */
B
Bruce Momjian 已提交
791 792 793 794
int
archputs(const char *s, Archive *AH)
{
	return WriteData(AH, s, strlen(s));
B
Bruce Momjian 已提交
795 796 797
}

/* Public */
B
Bruce Momjian 已提交
798 799
int
archprintf(Archive *AH, const char *fmt,...)
B
Bruce Momjian 已提交
800
{
B
Bruce Momjian 已提交
801 802 803 804 805 806
	char	   *p = NULL;
	va_list		ap;
	int			bSize = strlen(fmt) + 256;
	int			cnt = -1;

	/*
B
Bruce Momjian 已提交
807 808 809
	 * 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
B
Bruce Momjian 已提交
810 811
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
B
Bruce Momjian 已提交
812
	{
B
Bruce Momjian 已提交
813 814
		if (p != NULL)
			free(p);
815
		bSize *= 2;
B
Bruce Momjian 已提交
816
		p = (char *) malloc(bSize);
817
		if (p == NULL)
818
			exit_horribly(AH, modulename, "out of memory\n");
819 820 821
		va_start(ap, fmt);
		cnt = vsnprintf(p, bSize, fmt, ap);
		va_end(ap);
B
Bruce Momjian 已提交
822 823 824 825
	}
	WriteData(AH, p, cnt);
	free(p);
	return cnt;
B
Bruce Momjian 已提交
826 827 828 829 830 831 832
}


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

B
Bruce Momjian 已提交
833 834
OutputContext
SetOutput(ArchiveHandle *AH, char *filename, int compression)
B
Bruce Momjian 已提交
835
{
B
Bruce Momjian 已提交
836
	OutputContext sav;
837
	int			fn;
B
Bruce Momjian 已提交
838 839 840 841 842 843

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

	if (filename)
844
		fn = -1;
B
Bruce Momjian 已提交
845 846 847 848
	else if (AH->FH)
		fn = fileno(AH->FH);
	else if (AH->fSpec)
	{
849
		fn = -1;
B
Bruce Momjian 已提交
850 851 852 853 854 855
		filename = AH->fSpec;
	}
	else
		fn = fileno(stdout);

	/* If compression explicitly requested, use gzopen */
856
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
857 858
	if (compression != 0)
	{
859 860 861
		char		fmode[10];

		/* Don't use PG_BINARY_x since this is zlib */
862
		sprintf(fmode, "wb%d", compression);
863 864
		if (fn >= 0)
			AH->OF = gzdopen(dup(fn), fmode);
B
Bruce Momjian 已提交
865 866
		else
			AH->OF = gzopen(filename, fmode);
867
		AH->gzOut = 1;
B
Bruce Momjian 已提交
868 869
	}
	else
B
Bruce Momjian 已提交
870
#endif
871 872
	{							/* Use fopen */
		if (fn >= 0)
873
			AH->OF = fdopen(dup(fn), PG_BINARY_W);
B
Bruce Momjian 已提交
874
		else
875 876
			AH->OF = fopen(filename, PG_BINARY_W);
		AH->gzOut = 0;
B
Bruce Momjian 已提交
877
	}
B
Bruce Momjian 已提交
878

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

B
Bruce Momjian 已提交
882
	return sav;
B
Bruce Momjian 已提交
883 884
}

B
Bruce Momjian 已提交
885 886
void
ResetOutput(ArchiveHandle *AH, OutputContext sav)
B
Bruce Momjian 已提交
887
{
B
Bruce Momjian 已提交
888
	int			res;
889

B
Bruce Momjian 已提交
890
	if (AH->gzOut)
891
		res = GZCLOSE(AH->OF);
B
Bruce Momjian 已提交
892
	else
893 894 895
		res = fclose(AH->OF);

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

B
Bruce Momjian 已提交
899 900
	AH->gzOut = sav.gzOut;
	AH->OF = sav.OF;
B
Bruce Momjian 已提交
901 902 903 904 905
}



/*
B
Bruce Momjian 已提交
906
 *	Print formatted text to the output file (usually stdout).
B
Bruce Momjian 已提交
907
 */
B
Bruce Momjian 已提交
908 909
int
ahprintf(ArchiveHandle *AH, const char *fmt,...)
B
Bruce Momjian 已提交
910
{
B
Bruce Momjian 已提交
911 912 913 914 915 916
	char	   *p = NULL;
	va_list		ap;
	int			bSize = strlen(fmt) + 256;		/* Should be enough */
	int			cnt = -1;

	/*
B
Bruce Momjian 已提交
917 918
	 * This is paranoid: deal with the possibility that vsnprintf is willing
	 * to ignore trailing null
B
Bruce Momjian 已提交
919 920 921
	 */

	/*
B
Bruce Momjian 已提交
922 923
	 * or returns > 0 even if string does not fit. It may be the case that it
	 * returns cnt = bufsize
B
Bruce Momjian 已提交
924 925
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
926
	{
B
Bruce Momjian 已提交
927 928
		if (p != NULL)
			free(p);
929
		bSize *= 2;
B
Bruce Momjian 已提交
930
		p = (char *) malloc(bSize);
931
		if (p == NULL)
932
			die_horribly(AH, modulename, "out of memory\n");
933
		va_start(ap, fmt);
934
		cnt = vsnprintf(p, bSize, fmt, ap);
935
		va_end(ap);
B
Bruce Momjian 已提交
936 937 938 939
	}
	ahwrite(p, 1, cnt, AH);
	free(p);
	return cnt;
B
Bruce Momjian 已提交
940 941
}

B
Bruce Momjian 已提交
942 943
void
ahlog(ArchiveHandle *AH, int level, const char *fmt,...)
944 945 946 947 948 949 950
{
	va_list		ap;

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

	va_start(ap, fmt);
951
	_write_msg(NULL, fmt, ap);
952 953 954
	va_end(ap);
}

955 956 957
/*
 * Single place for logic which says 'We are restoring to a direct DB connection'.
 */
B
Bruce Momjian 已提交
958 959
int
RestoringToDB(ArchiveHandle *AH)
960 961 962 963
{
	return (AH->ropt && AH->ropt->useDB && AH->connection);
}

964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
/*
 * Dump the current contents of the LO data buffer while writing a BLOB
 */
static void
dump_lo_buf(ArchiveHandle *AH)
{
	if (AH->connection)
	{
		size_t		res;

		res = lo_write(AH->connection, AH->loFd, AH->lo_buf, AH->lo_buf_used);
		ahlog(AH, 5, "wrote %lu bytes of large object data (result = %lu)\n",
			  (unsigned long) AH->lo_buf_used, (unsigned long) res);
		if (res != AH->lo_buf_used)
			die_horribly(AH, modulename,
B
Bruce Momjian 已提交
979 980
			"could not write to large object (result: %lu, expected: %lu)\n",
					   (unsigned long) res, (unsigned long) AH->lo_buf_used);
981 982 983 984
	}
	else
	{
		unsigned char *str;
B
Bruce Momjian 已提交
985
		size_t		len;
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002

		str = PQescapeBytea((const unsigned char *) AH->lo_buf,
							AH->lo_buf_used, &len);
		if (!str)
			die_horribly(AH, modulename, "out of memory\n");

		/* Hack: turn off writingBlob so ahwrite doesn't recurse to here */
		AH->writingBlob = 0;
		ahprintf(AH, "SELECT lowrite(0, '%s');\n", str);
		AH->writingBlob = 1;

		free(str);
	}
	AH->lo_buf_used = 0;
}


B
Bruce Momjian 已提交
1003
/*
B
Bruce Momjian 已提交
1004 1005 1006
 *	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
1007
 *	wants to generate a script (see TAR output).
B
Bruce Momjian 已提交
1008
 */
B
Bruce Momjian 已提交
1009 1010
int
ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
B
Bruce Momjian 已提交
1011
{
P
Peter Eisentraut 已提交
1012
	size_t		res;
1013

B
Bruce Momjian 已提交
1014
	if (AH->writingBlob)
1015
	{
B
Bruce Momjian 已提交
1016
		size_t		remaining = size * nmemb;
1017 1018

		while (AH->lo_buf_used + remaining > AH->lo_buf_size)
P
Peter Eisentraut 已提交
1019
		{
1020 1021 1022 1023 1024 1025 1026
			size_t		avail = AH->lo_buf_size - AH->lo_buf_used;

			memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, avail);
			ptr = (const void *) ((const char *) ptr + avail);
			remaining -= avail;
			AH->lo_buf_used += avail;
			dump_lo_buf(AH);
P
Peter Eisentraut 已提交
1027 1028
		}

1029 1030 1031
		memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining);
		AH->lo_buf_used += remaining;

P
Peter Eisentraut 已提交
1032
		return size * nmemb;
1033
	}
B
Bruce Momjian 已提交
1034
	else if (AH->gzOut)
1035
	{
B
Bruce Momjian 已提交
1036
		res = GZWRITE((void *) ptr, size, nmemb, AH->OF);
1037
		if (res != (nmemb * size))
1038
			die_horribly(AH, modulename, "could not write to compressed archive\n");
1039 1040
		return res;
	}
B
Bruce Momjian 已提交
1041
	else if (AH->CustomOutPtr)
1042
	{
B
Bruce Momjian 已提交
1043 1044
		res = AH->CustomOutPtr (AH, ptr, size * nmemb);

1045
		if (res != (nmemb * size))
1046
			die_horribly(AH, modulename, "could not write to custom output routine\n");
1047 1048
		return res;
	}
1049 1050 1051
	else
	{
		/*
B
Bruce Momjian 已提交
1052 1053 1054
		 * If we're doing a restore, and it's direct to DB, and we're
		 * connected then send it to the DB.
		 */
1055
		if (RestoringToDB(AH))
B
Bruce Momjian 已提交
1056
			return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb);		/* Always 1, currently */
1057
		else
1058
		{
B
Bruce Momjian 已提交
1059
			res = fwrite((void *) ptr, size, nmemb, AH->OF);
1060
			if (res != nmemb)
P
Peter Eisentraut 已提交
1061 1062
				die_horribly(AH, modulename, "could not write to output file (%lu != %lu)\n",
							 (unsigned long) res, (unsigned long) nmemb);
1063 1064
			return res;
		}
1065
	}
B
Bruce Momjian 已提交
1066
}
1067 1068

/* Common exit code */
B
Bruce Momjian 已提交
1069
static void
1070
_write_msg(const char *modulename, const char *fmt, va_list ap)
1071
{
1072
	if (modulename)
1073
		fprintf(stderr, "%s: [%s] ", progname, _(modulename));
1074 1075
	else
		fprintf(stderr, "%s: ", progname);
1076
	vfprintf(stderr, _(fmt), ap);
1077 1078 1079
}

void
1080
write_msg(const char *modulename, const char *fmt,...)
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
{
	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);
1094

B
Bruce Momjian 已提交
1095 1096
	if (AH)
	{
1097 1098
		if (AH->public.verbose)
			write_msg(NULL, "*** aborted because of error\n");
B
Bruce Momjian 已提交
1099 1100
		if (AH->connection)
			PQfinish(AH->connection);
1101
	}
1102

B
Bruce Momjian 已提交
1103
	exit(1);
B
Bruce Momjian 已提交
1104 1105
}

1106
/* External use */
B
Bruce Momjian 已提交
1107
void
1108
exit_horribly(Archive *AH, const char *modulename, const char *fmt,...)
1109
{
B
Bruce Momjian 已提交
1110
	va_list		ap;
1111

B
Bruce Momjian 已提交
1112
	va_start(ap, fmt);
1113
	_die_horribly((ArchiveHandle *) AH, modulename, fmt, ap);
1114
	va_end(ap);
1115
}
B
Bruce Momjian 已提交
1116

1117
/* Archiver use (just different arg declaration) */
B
Bruce Momjian 已提交
1118
void
1119
die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...)
B
Bruce Momjian 已提交
1120
{
B
Bruce Momjian 已提交
1121
	va_list		ap;
B
Bruce Momjian 已提交
1122

B
Bruce Momjian 已提交
1123
	va_start(ap, fmt);
1124
	_die_horribly(AH, modulename, fmt, ap);
1125
	va_end(ap);
B
Bruce Momjian 已提交
1126 1127
}

1128 1129
/* on some error, we may decide to go on... */
void
B
Bruce Momjian 已提交
1130 1131
warn_or_die_horribly(ArchiveHandle *AH,
					 const char *modulename, const char *fmt,...)
1132
{
B
Bruce Momjian 已提交
1133
	va_list		ap;
1134

B
Bruce Momjian 已提交
1135 1136
	switch (AH->stage)
	{
1137 1138 1139 1140 1141 1142

		case STAGE_NONE:
			/* Do nothing special */
			break;

		case STAGE_INITIALIZING:
B
Bruce Momjian 已提交
1143
			if (AH->stage != AH->lastErrorStage)
1144 1145 1146 1147
				write_msg(modulename, "Error while INITIALIZING:\n");
			break;

		case STAGE_PROCESSING:
B
Bruce Momjian 已提交
1148
			if (AH->stage != AH->lastErrorStage)
1149 1150 1151 1152
				write_msg(modulename, "Error while PROCESSING TOC:\n");
			break;

		case STAGE_FINALIZING:
B
Bruce Momjian 已提交
1153
			if (AH->stage != AH->lastErrorStage)
1154 1155 1156
				write_msg(modulename, "Error while FINALIZING:\n");
			break;
	}
B
Bruce Momjian 已提交
1157 1158
	if (AH->currentTE != NULL && AH->currentTE != AH->lastErrorTE)
	{
1159 1160
		write_msg(modulename, "Error from TOC entry %d; %u %u %s %s %s\n",
				  AH->currentTE->dumpId,
B
Bruce Momjian 已提交
1161 1162
			 AH->currentTE->catalogId.tableoid, AH->currentTE->catalogId.oid,
			  AH->currentTE->desc, AH->currentTE->tag, AH->currentTE->owner);
1163 1164 1165 1166
	}
	AH->lastErrorStage = AH->stage;
	AH->lastErrorTE = AH->currentTE;

1167
	va_start(ap, fmt);
1168
	if (AH->public.exit_on_error)
1169 1170 1171 1172 1173 1174 1175 1176
		_die_horribly(AH, modulename, fmt, ap);
	else
	{
		_write_msg(modulename, fmt, ap);
		AH->public.n_errors++;
	}
	va_end(ap);
}
1177

B
Bruce Momjian 已提交
1178 1179
static void
_moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
B
Bruce Momjian 已提交
1180
{
B
Bruce Momjian 已提交
1181 1182
	te->prev->next = te->next;
	te->next->prev = te->prev;
B
Bruce Momjian 已提交
1183

B
Bruce Momjian 已提交
1184 1185
	te->prev = pos;
	te->next = pos->next;
B
Bruce Momjian 已提交
1186

B
Bruce Momjian 已提交
1187 1188
	pos->next->prev = te;
	pos->next = te;
B
Bruce Momjian 已提交
1189 1190
}

1191 1192
#ifdef NOT_USED

B
Bruce Momjian 已提交
1193 1194
static void
_moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
B
Bruce Momjian 已提交
1195
{
B
Bruce Momjian 已提交
1196 1197
	te->prev->next = te->next;
	te->next->prev = te->prev;
B
Bruce Momjian 已提交
1198

B
Bruce Momjian 已提交
1199 1200 1201 1202
	te->prev = pos->prev;
	te->next = pos;
	pos->prev->next = te;
	pos->prev = te;
B
Bruce Momjian 已提交
1203
}
1204 1205
#endif

B
Bruce Momjian 已提交
1206
static TocEntry *
1207
getTocEntryByDumpId(ArchiveHandle *AH, DumpId id)
B
Bruce Momjian 已提交
1208
{
B
Bruce Momjian 已提交
1209 1210 1211 1212 1213
	TocEntry   *te;

	te = AH->toc->next;
	while (te != AH->toc)
	{
1214
		if (te->dumpId == id)
B
Bruce Momjian 已提交
1215 1216 1217 1218
			return te;
		te = te->next;
	}
	return NULL;
B
Bruce Momjian 已提交
1219 1220
}

1221
teReqs
1222
TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
B
Bruce Momjian 已提交
1223
{
1224
	TocEntry   *te = getTocEntryByDumpId(AH, id);
B
Bruce Momjian 已提交
1225

B
Bruce Momjian 已提交
1226 1227
	if (!te)
		return 0;
B
Bruce Momjian 已提交
1228

1229
	return _tocEntryRequired(te, ropt, true);
B
Bruce Momjian 已提交
1230 1231
}

1232 1233 1234
size_t
WriteOffset(ArchiveHandle *AH, off_t o, int wasSet)
{
B
Bruce Momjian 已提交
1235
	int			off;
1236 1237 1238 1239 1240 1241 1242

	/* 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 已提交
1243
		(*AH->WriteBytePtr) (AH, o & 0xFF);
1244 1245 1246 1247 1248 1249 1250 1251
		o >>= 8;
	}
	return sizeof(off_t) + 1;
}

int
ReadOffset(ArchiveHandle *AH, off_t *o)
{
B
Bruce Momjian 已提交
1252 1253 1254
	int			i;
	int			off;
	int			offsetFlg;
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265

	/* 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 已提交
1266
			return K_OFFSET_POS_NOT_SET;
1267
		else if (i == 0)
B
Bruce Momjian 已提交
1268
			return K_OFFSET_NO_DATA;
1269 1270

		/* Cast to off_t because it was written as an int. */
B
Bruce Momjian 已提交
1271
		*o = (off_t) i;
1272 1273 1274 1275
		return K_OFFSET_POS_SET;
	}

	/*
B
Bruce Momjian 已提交
1276 1277
	 * Read the flag indicating the state of the data pointer. Check if valid
	 * and die if not.
1278
	 *
B
Bruce Momjian 已提交
1279 1280
	 * This used to be handled by a negative or zero pointer, now we use an extra
	 * byte specifically for the state.
1281 1282 1283 1284 1285 1286 1287 1288 1289
	 */
	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 已提交
1290
			break;
1291 1292

		default:
B
Bruce Momjian 已提交
1293
			die_horribly(AH, modulename, "Unexpected data offset flag %d\n", offsetFlg);
1294 1295 1296 1297 1298 1299 1300 1301
	}

	/*
	 * Read the bytes
	 */
	for (off = 0; off < AH->offSize; off++)
	{
		if (off < sizeof(off_t))
1302
			*o |= ((off_t) ((*AH->ReadBytePtr) (AH))) << (off * 8);
1303 1304 1305
		else
		{
			if ((*AH->ReadBytePtr) (AH) != 0)
B
Bruce Momjian 已提交
1306
				die_horribly(AH, modulename, "file offset in dump file is too large\n");
1307 1308 1309 1310 1311 1312
		}
	}

	return offsetFlg;
}

P
Peter Eisentraut 已提交
1313
size_t
B
Bruce Momjian 已提交
1314
WriteInt(ArchiveHandle *AH, int i)
B
Bruce Momjian 已提交
1315
{
B
Bruce Momjian 已提交
1316 1317 1318
	int			b;

	/*
B
Bruce Momjian 已提交
1319 1320 1321 1322 1323
	 * This is a bit yucky, but I don't want to make the binary format very
	 * dependent on representation, and not knowing much about it, I 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.
B
Bruce Momjian 已提交
1324 1325 1326 1327 1328 1329
	 */

	/* SIGN byte */
	if (i < 0)
	{
		(*AH->WriteBytePtr) (AH, 1);
1330
		i = -i;
B
Bruce Momjian 已提交
1331 1332 1333 1334 1335 1336 1337
	}
	else
		(*AH->WriteBytePtr) (AH, 0);

	for (b = 0; b < AH->intSize; b++)
	{
		(*AH->WriteBytePtr) (AH, i & 0xFF);
1338
		i >>= 8;
B
Bruce Momjian 已提交
1339 1340 1341
	}

	return AH->intSize + 1;
B
Bruce Momjian 已提交
1342 1343
}

B
Bruce Momjian 已提交
1344 1345
int
ReadInt(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1346
{
B
Bruce Momjian 已提交
1347 1348 1349 1350 1351
	int			res = 0;
	int			bv,
				b;
	int			sign = 0;		/* Default positive */
	int			bitShift = 0;
B
Bruce Momjian 已提交
1352

B
Bruce Momjian 已提交
1353
	if (AH->version > K_VERS_1_0)
1354
		/* Read a sign byte */
B
Bruce Momjian 已提交
1355
		sign = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
1356

B
Bruce Momjian 已提交
1357 1358 1359
	for (b = 0; b < AH->intSize; b++)
	{
		bv = (*AH->ReadBytePtr) (AH) & 0xFF;
1360 1361 1362
		if (bv != 0)
			res = res + (bv << bitShift);
		bitShift += 8;
B
Bruce Momjian 已提交
1363
	}
B
Bruce Momjian 已提交
1364

B
Bruce Momjian 已提交
1365 1366
	if (sign)
		res = -res;
B
Bruce Momjian 已提交
1367

B
Bruce Momjian 已提交
1368
	return res;
B
Bruce Momjian 已提交
1369 1370
}

P
Peter Eisentraut 已提交
1371
size_t
1372
WriteStr(ArchiveHandle *AH, const char *c)
B
Bruce Momjian 已提交
1373
{
P
Peter Eisentraut 已提交
1374
	size_t		res;
1375 1376 1377 1378

	if (c)
	{
		res = WriteInt(AH, strlen(c));
B
Bruce Momjian 已提交
1379
		res += (*AH->WriteBufPtr) (AH, c, strlen(c));
1380 1381 1382 1383
	}
	else
		res = WriteInt(AH, -1);

B
Bruce Momjian 已提交
1384
	return res;
B
Bruce Momjian 已提交
1385 1386
}

B
Bruce Momjian 已提交
1387 1388
char *
ReadStr(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1389
{
B
Bruce Momjian 已提交
1390 1391
	char	   *buf;
	int			l;
B
Bruce Momjian 已提交
1392

B
Bruce Momjian 已提交
1393
	l = ReadInt(AH);
1394 1395 1396 1397
	if (l == -1)
		buf = NULL;
	else
	{
B
Bruce Momjian 已提交
1398
		buf = (char *) malloc(l + 1);
1399
		if (!buf)
1400
			die_horribly(AH, modulename, "out of memory\n");
1401

B
Bruce Momjian 已提交
1402
		(*AH->ReadBufPtr) (AH, (void *) buf, l);
1403 1404
		buf[l] = '\0';
	}
B
Bruce Momjian 已提交
1405

B
Bruce Momjian 已提交
1406
	return buf;
B
Bruce Momjian 已提交
1407 1408
}

T
Tom Lane 已提交
1409
static int
B
Bruce Momjian 已提交
1410
_discoverArchiveFormat(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1411
{
B
Bruce Momjian 已提交
1412 1413
	FILE	   *fh;
	char		sig[6];			/* More than enough */
P
Peter Eisentraut 已提交
1414
	size_t		cnt;
B
Bruce Momjian 已提交
1415
	int			wantClose = 0;
B
Bruce Momjian 已提交
1416

1417
#if 0
1418
	write_msg(modulename, "attempting to ascertain archive format\n");
1419
#endif
1420 1421 1422 1423 1424 1425 1426 1427

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

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

B
Bruce Momjian 已提交
1429 1430
	if (AH->fSpec)
	{
1431 1432
		wantClose = 1;
		fh = fopen(AH->fSpec, PG_BINARY_R);
B
Bruce Momjian 已提交
1433 1434
	}
	else
1435
		fh = stdin;
B
Bruce Momjian 已提交
1436

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

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

B
Bruce Momjian 已提交
1442
	if (cnt != 5)
1443 1444 1445 1446
	{
		if (ferror(fh))
			die_horribly(AH, modulename, "could not read input file: %s\n", strerror(errno));
		else
P
Peter Eisentraut 已提交
1447 1448
			die_horribly(AH, modulename, "input file is too short (read %lu, expected 5)\n",
						 (unsigned long) cnt);
1449
	}
B
Bruce Momjian 已提交
1450

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

B
Bruce Momjian 已提交
1455
	if (strncmp(sig, "PGDMP", 5) == 0)
1456 1457 1458 1459 1460 1461 1462 1463 1464
	{
		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 已提交
1465 1466
		if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))		/* Version > 1.0 */
		{
1467 1468 1469 1470 1471 1472
			AH->vrev = fgetc(fh);
			AH->lookahead[AH->lookaheadLen++] = AH->vrev;
		}
		else
			AH->vrev = 0;

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

1476 1477 1478
		AH->intSize = fgetc(fh);
		AH->lookahead[AH->lookaheadLen++] = AH->intSize;

1479 1480 1481 1482 1483 1484 1485 1486
		if (AH->version >= K_VERS_1_7)
		{
			AH->offSize = fgetc(fh);
			AH->lookahead[AH->lookaheadLen++] = AH->offSize;
		}
		else
			AH->offSize = AH->intSize;

1487 1488
		AH->format = fgetc(fh);
		AH->lookahead[AH->lookaheadLen++] = AH->format;
B
Bruce Momjian 已提交
1489 1490 1491
	}
	else
	{
1492
		/*
B
Bruce Momjian 已提交
1493 1494
		 * *Maybe* we have a tar archive format file... So, read first 512
		 * byte header...
1495 1496 1497
		 */
		cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh);
		AH->lookaheadLen += cnt;
B
Bruce Momjian 已提交
1498

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

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

1505 1506
		AH->format = archTar;
	}
B
Bruce Momjian 已提交
1507

B
Bruce Momjian 已提交
1508
	/* If we can't seek, then mark the header as read */
P
Peter Eisentraut 已提交
1509
	if (fseeko(fh, 0, SEEK_SET) != 0)
1510 1511
	{
		/*
B
Bruce Momjian 已提交
1512 1513
		 * NOTE: Formats that use the lookahead buffer can unset this in their
		 * Init routine.
1514 1515 1516 1517
		 */
		AH->readHeader = 1;
	}
	else
B
Bruce Momjian 已提交
1518
		AH->lookaheadLen = 0;	/* Don't bother since we've reset the file */
1519

1520
#if 0
P
Peter Eisentraut 已提交
1521 1522
	write_msg(modulename, "read %lu bytes into lookahead buffer\n",
			  (unsigned long) AH->lookaheadLen);
1523
#endif
B
Bruce Momjian 已提交
1524

B
Bruce Momjian 已提交
1525 1526
	/* Close the file */
	if (wantClose)
1527
		if (fclose(fh) != 0)
1528 1529
			die_horribly(AH, modulename, "could not close the input file after reading header: %s\n",
						 strerror(errno));
B
Bruce Momjian 已提交
1530

B
Bruce Momjian 已提交
1531
	return AH->format;
B
Bruce Momjian 已提交
1532 1533 1534 1535 1536 1537
}


/*
 * Allocate an archive handle
 */
B
Bruce Momjian 已提交
1538 1539 1540
static ArchiveHandle *
_allocAH(const char *FileSpec, const ArchiveFormat fmt,
		 const int compression, ArchiveMode mode)
1541
{
B
Bruce Momjian 已提交
1542
	ArchiveHandle *AH;
B
Bruce Momjian 已提交
1543

1544
#if 0
1545
	write_msg(modulename, "allocating AH for %s, format %d\n", FileSpec, fmt);
1546
#endif
1547

B
Bruce Momjian 已提交
1548 1549
	AH = (ArchiveHandle *) calloc(1, sizeof(ArchiveHandle));
	if (!AH)
1550
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
1551

1552 1553
	/* AH->debugLevel = 100; */

B
Bruce Momjian 已提交
1554 1555
	AH->vmaj = K_VERS_MAJOR;
	AH->vmin = K_VERS_MINOR;
1556
	AH->vrev = K_VERS_REV;
B
Bruce Momjian 已提交
1557

1558 1559
	AH->createDate = time(NULL);

B
Bruce Momjian 已提交
1560
	AH->intSize = sizeof(int);
1561
	AH->offSize = sizeof(off_t);
B
Bruce Momjian 已提交
1562 1563
	if (FileSpec)
	{
1564
		AH->fSpec = strdup(FileSpec);
B
Bruce Momjian 已提交
1565

1566 1567 1568
		/*
		 * Not used; maybe later....
		 *
B
Bruce Momjian 已提交
1569 1570
		 * AH->workDir = strdup(FileSpec); for(i=strlen(FileSpec) ; i > 0 ; i--)
		 * if (AH->workDir[i-1] == '/')
1571
		 */
B
Bruce Momjian 已提交
1572 1573
	}
	else
1574
		AH->fSpec = NULL;
B
Bruce Momjian 已提交
1575

B
Bruce Momjian 已提交
1576 1577
	AH->currUser = strdup("");	/* So it's valid, but we can free() it later
								 * if necessary */
B
Bruce Momjian 已提交
1578
	AH->currSchema = strdup("");	/* ditto */
1579
	AH->currWithOids = -1;		/* force SET */
B
Bruce Momjian 已提交
1580

B
Bruce Momjian 已提交
1581 1582
	AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry));
	if (!AH->toc)
1583
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
1584

B
Bruce Momjian 已提交
1585 1586 1587 1588 1589
	AH->toc->next = AH->toc;
	AH->toc->prev = AH->toc;

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

1591 1592
	AH->pgCopyBuf = createPQExpBuffer();
	AH->sqlBuf = createPQExpBuffer();
B
Bruce Momjian 已提交
1593

B
Bruce Momjian 已提交
1594 1595 1596
	/* Open stdout with no compression for AH output handle */
	AH->gzOut = 0;
	AH->OF = stdout;
B
Bruce Momjian 已提交
1597

1598 1599
	/*
	 * On Windows, we need to use binary mode to read/write non-text archive
B
Bruce Momjian 已提交
1600 1601
	 * formats.  Force stdin/stdout into binary mode if that is what we are
	 * using.
1602 1603
	 */
#ifdef WIN32
1604 1605
	if (fmt != archNull &&
		(AH->fSpec == NULL || strcmp(AH->fSpec, "") == 0))
1606 1607 1608 1609 1610 1611 1612 1613
	{
		if (mode == archModeWrite)
			setmode(fileno(stdout), O_BINARY);
		else
			setmode(fileno(stdin), O_BINARY);
	}
#endif

1614
#if 0
1615
	write_msg(modulename, "archive format is %d\n", fmt);
1616
#endif
1617

B
Bruce Momjian 已提交
1618
	if (fmt == archUnknown)
1619 1620 1621
		AH->format = _discoverArchiveFormat(AH);
	else
		AH->format = fmt;
B
Bruce Momjian 已提交
1622

B
Bruce Momjian 已提交
1623 1624
	switch (AH->format)
	{
1625 1626 1627
		case archCustom:
			InitArchiveFmt_Custom(AH);
			break;
B
Bruce Momjian 已提交
1628

1629 1630 1631
		case archFiles:
			InitArchiveFmt_Files(AH);
			break;
B
Bruce Momjian 已提交
1632

1633 1634 1635
		case archNull:
			InitArchiveFmt_Null(AH);
			break;
B
Bruce Momjian 已提交
1636

1637 1638 1639 1640 1641
		case archTar:
			InitArchiveFmt_Tar(AH);
			break;

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

1645
	/* sql error handling */
1646
	AH->public.exit_on_error = true;
1647 1648
	AH->public.n_errors = 0;

B
Bruce Momjian 已提交
1649
	return AH;
B
Bruce Momjian 已提交
1650 1651 1652
}


B
Bruce Momjian 已提交
1653 1654
void
WriteDataChunks(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1655
{
B
Bruce Momjian 已提交
1656 1657 1658
	TocEntry   *te = AH->toc->next;
	StartDataPtr startPtr;
	EndDataPtr	endPtr;
B
Bruce Momjian 已提交
1659

B
Bruce Momjian 已提交
1660 1661 1662
	while (te != AH->toc)
	{
		if (te->dataDumper != NULL)
1663
		{
B
Bruce Momjian 已提交
1664 1665
			AH->currToc = te;
			/* printf("Writing data for %d (%x)\n", te->id, te); */
1666

B
Bruce Momjian 已提交
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676
			if (strcmp(te->desc, "BLOBS") == 0)
			{
				startPtr = AH->StartBlobsPtr;
				endPtr = AH->EndBlobsPtr;
			}
			else
			{
				startPtr = AH->StartDataPtr;
				endPtr = AH->EndDataPtr;
			}
B
Bruce Momjian 已提交
1677

B
Bruce Momjian 已提交
1678 1679
			if (startPtr != NULL)
				(*startPtr) (AH, te);
B
Bruce Momjian 已提交
1680

B
Bruce Momjian 已提交
1681
			/*
B
Bruce Momjian 已提交
1682
			 * printf("Dumper arg for %d is %x\n", te->id, te->dataDumperArg);
B
Bruce Momjian 已提交
1683 1684 1685 1686 1687 1688
			 */

			/*
			 * The user-provided DataDumper routine needs to call
			 * AH->WriteData
			 */
1689
			(*te->dataDumper) ((Archive *) AH, te->dataDumperArg);
B
Bruce Momjian 已提交
1690 1691 1692 1693 1694

			if (endPtr != NULL)
				(*endPtr) (AH, te);
			AH->currToc = NULL;
		}
1695
		te = te->next;
B
Bruce Momjian 已提交
1696
	}
B
Bruce Momjian 已提交
1697 1698
}

B
Bruce Momjian 已提交
1699 1700
void
WriteToc(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1701
{
1702 1703
	TocEntry   *te;
	char		workbuf[32];
1704
	int			i;
B
Bruce Momjian 已提交
1705 1706 1707 1708

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

	WriteInt(AH, AH->tocCount);
1709 1710

	for (te = AH->toc->next; te != AH->toc; te = te->next)
B
Bruce Momjian 已提交
1711
	{
1712
		WriteInt(AH, te->dumpId);
B
Bruce Momjian 已提交
1713
		WriteInt(AH, te->dataDumper ? 1 : 0);
1714 1715 1716 1717 1718 1719

		/* 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);
1720

1721
		WriteStr(AH, te->tag);
B
Bruce Momjian 已提交
1722 1723 1724 1725
		WriteStr(AH, te->desc);
		WriteStr(AH, te->defn);
		WriteStr(AH, te->dropStmt);
		WriteStr(AH, te->copyStmt);
1726
		WriteStr(AH, te->namespace);
1727
		WriteStr(AH, te->tablespace);
B
Bruce Momjian 已提交
1728
		WriteStr(AH, te->owner);
1729
		WriteStr(AH, te->withOids ? "true" : "false");
1730 1731

		/* Dump list of dependencies */
1732
		for (i = 0; i < te->nDeps; i++)
1733
		{
1734 1735
			sprintf(workbuf, "%d", te->dependencies[i]);
			WriteStr(AH, workbuf);
1736
		}
1737
		WriteStr(AH, NULL);		/* Terminate List */
1738

B
Bruce Momjian 已提交
1739 1740 1741
		if (AH->WriteExtraTocPtr)
			(*AH->WriteExtraTocPtr) (AH, te);
	}
B
Bruce Momjian 已提交
1742 1743
}

B
Bruce Momjian 已提交
1744 1745
void
ReadToc(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1746
{
B
Bruce Momjian 已提交
1747
	int			i;
1748 1749
	char	   *tmp;
	DumpId	   *deps;
1750 1751
	int			depIdx;
	int			depSize;
B
Bruce Momjian 已提交
1752

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

B
Bruce Momjian 已提交
1755
	AH->tocCount = ReadInt(AH);
1756
	AH->maxDumpId = 0;
B
Bruce Momjian 已提交
1757

B
Bruce Momjian 已提交
1758 1759 1760
	for (i = 0; i < AH->tocCount; i++)
	{
		te = (TocEntry *) calloc(1, sizeof(TocEntry));
1761 1762 1763 1764
		te->dumpId = ReadInt(AH);

		if (te->dumpId > AH->maxDumpId)
			AH->maxDumpId = te->dumpId;
1765 1766

		/* Sanity check */
1767 1768
		if (te->dumpId <= 0)
			die_horribly(AH, modulename,
B
Bruce Momjian 已提交
1769
					   "entry ID %d out of range -- perhaps a corrupt TOC\n",
1770
						 te->dumpId);
1771 1772

		te->hadDumper = ReadInt(AH);
1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784

		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);
1785

1786
		te->tag = ReadStr(AH);
1787 1788 1789 1790 1791 1792 1793
		te->desc = ReadStr(AH);
		te->defn = ReadStr(AH);
		te->dropStmt = ReadStr(AH);

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

1794 1795 1796
		if (AH->version >= K_VERS_1_6)
			te->namespace = ReadStr(AH);

1797 1798 1799
		if (AH->version >= K_VERS_1_10)
			te->tablespace = ReadStr(AH);

1800
		te->owner = ReadStr(AH);
1801 1802 1803 1804 1805 1806 1807 1808 1809
		if (AH->version >= K_VERS_1_9)
		{
			if (strcmp(ReadStr(AH), "true") == 0)
				te->withOids = true;
			else
				te->withOids = false;
		}
		else
			te->withOids = true;
B
Bruce Momjian 已提交
1810

1811 1812 1813 1814
		/* Read TOC entry dependencies */
		if (AH->version >= K_VERS_1_5)
		{
			depSize = 100;
1815
			deps = (DumpId *) malloc(sizeof(DumpId) * depSize);
1816
			depIdx = 0;
1817
			for (;;)
1818
			{
1819 1820 1821
				tmp = ReadStr(AH);
				if (!tmp)
					break;		/* end of list */
1822
				if (depIdx >= depSize)
1823 1824
				{
					depSize *= 2;
1825
					deps = (DumpId *) realloc(deps, sizeof(DumpId) * depSize);
1826
				}
1827 1828 1829 1830
				sscanf(tmp, "%d", &deps[depIdx]);
				free(tmp);
				depIdx++;
			}
1831

1832 1833 1834 1835 1836 1837
			if (depIdx > 0)		/* We have a non-null entry */
			{
				deps = (DumpId *) realloc(deps, sizeof(DumpId) * depIdx);
				te->dependencies = deps;
				te->nDeps = depIdx;
			}
1838
			else
1839 1840
			{
				free(deps);
1841 1842
				te->dependencies = NULL;
				te->nDeps = 0;
1843
			}
1844
		}
1845
		else
1846 1847 1848 1849
		{
			te->dependencies = NULL;
			te->nDeps = 0;
		}
1850

B
Bruce Momjian 已提交
1851 1852
		if (AH->ReadExtraTocPtr)
			(*AH->ReadExtraTocPtr) (AH, te);
1853

1854 1855
		ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n",
			  i, te->dumpId, te->desc, te->tag);
1856 1857 1858 1859 1860

		te->prev = AH->toc->prev;
		AH->toc->prev->next = te;
		AH->toc->prev = te;
		te->next = AH->toc;
B
Bruce Momjian 已提交
1861
	}
B
Bruce Momjian 已提交
1862 1863
}

1864
static teReqs
1865
_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
B
Bruce Momjian 已提交
1866
{
1867
	teReqs		res = REQ_ALL;
B
Bruce Momjian 已提交
1868

1869 1870 1871 1872
	/* ENCODING objects are dumped specially, so always reject here */
	if (strcmp(te->desc, "ENCODING") == 0)
		return 0;

B
Bruce Momjian 已提交
1873
	/* If it's an ACL, maybe ignore it */
1874
	if ((!include_acls || ropt->aclsSkip) && strcmp(te->desc, "ACL") == 0)
1875
		return 0;
B
Bruce Momjian 已提交
1876

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

B
Bruce Momjian 已提交
1880 1881 1882
	/* Check if tablename only is wanted */
	if (ropt->selTypes)
	{
1883 1884 1885 1886 1887
		if (ropt->schemaNames)
		{
			/* If no namespace is specified, it means all. */
			if (!te->namespace)
				return 0;
B
Bruce Momjian 已提交
1888
			if (strcmp(ropt->schemaNames, te->namespace) != 0)
1889 1890
				return 0;
		}
B
Bruce Momjian 已提交
1891
		if ((strcmp(te->desc, "TABLE") == 0) || (strcmp(te->desc, "TABLE DATA") == 0))
1892 1893 1894
		{
			if (!ropt->selTable)
				return 0;
1895
			if (ropt->tableNames && strcmp(ropt->tableNames, te->tag) != 0)
1896
				return 0;
B
Bruce Momjian 已提交
1897 1898 1899
		}
		else if (strcmp(te->desc, "INDEX") == 0)
		{
1900 1901
			if (!ropt->selIndex)
				return 0;
1902
			if (ropt->indexNames && strcmp(ropt->indexNames, te->tag) != 0)
1903
				return 0;
B
Bruce Momjian 已提交
1904 1905 1906
		}
		else if (strcmp(te->desc, "FUNCTION") == 0)
		{
1907 1908
			if (!ropt->selFunction)
				return 0;
1909
			if (ropt->functionNames && strcmp(ropt->functionNames, te->tag) != 0)
1910
				return 0;
B
Bruce Momjian 已提交
1911 1912 1913
		}
		else if (strcmp(te->desc, "TRIGGER") == 0)
		{
1914 1915
			if (!ropt->selTrigger)
				return 0;
1916
			if (ropt->triggerNames && strcmp(ropt->triggerNames, te->tag) != 0)
1917 1918
				return 0;
		}
B
Bruce Momjian 已提交
1919 1920
		else
			return 0;
B
Bruce Momjian 已提交
1921 1922
	}

1923
	/*
B
Bruce Momjian 已提交
1924
	 * Check if we had a dataDumper. Indicates if the entry is schema or data
1925 1926 1927 1928
	 */
	if (!te->hadDumper)
	{
		/*
B
Bruce Momjian 已提交
1929
		 * Special Case: If 'SEQUENCE SET' then it is considered a data entry
1930 1931 1932 1933
		 */
		if (strcmp(te->desc, "SEQUENCE SET") == 0)
			res = res & REQ_DATA;
		else
1934 1935
			res = res & ~REQ_DATA;
	}
1936

1937
	/*
B
Bruce Momjian 已提交
1938 1939
	 * Special case: <Init> type with <Max OID> tag; this is obsolete and we
	 * always ignore it.
1940
	 */
1941
	if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
1942
		return 0;
1943

B
Bruce Momjian 已提交
1944 1945
	/* Mask it if we only want schema */
	if (ropt->schemaOnly)
1946
		res = res & REQ_SCHEMA;
B
Bruce Momjian 已提交
1947

B
Bruce Momjian 已提交
1948
	/* Mask it we only want data */
1949
	if (ropt->dataOnly)
1950
		res = res & REQ_DATA;
B
Bruce Momjian 已提交
1951

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

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

B
Bruce Momjian 已提交
1960
	return res;
B
Bruce Momjian 已提交
1961 1962
}

1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986
/*
 * 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");

1987 1988 1989
	/* Avoid annoying notices etc */
	ahprintf(AH, "SET client_min_messages = warning;\n");

1990 1991 1992
	ahprintf(AH, "\n");
}

1993 1994
/*
 * Issue a SET SESSION AUTHORIZATION command.  Caller is responsible
1995 1996
 * for updating state if appropriate.  If user is NULL or an empty string,
 * the specification DEFAULT will be used.
1997 1998
 */
static void
1999
_doSetSessionAuth(ArchiveHandle *AH, const char *user)
2000
{
2001
	PQExpBuffer cmd = createPQExpBuffer();
B
Bruce Momjian 已提交
2002

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

2005 2006 2007 2008
	/*
	 * SQL requires a string literal here.	Might as well be correct.
	 */
	if (user && *user)
2009 2010 2011 2012 2013
		appendStringLiteral(cmd, user, false);
	else
		appendPQExpBuffer(cmd, "DEFAULT");
	appendPQExpBuffer(cmd, ";");

2014 2015 2016 2017
	if (RestoringToDB(AH))
	{
		PGresult   *res;

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2021
			/* NOT warn_or_die_horribly... use -O instead to skip this. */
2022
			die_horribly(AH, modulename, "could not set session user to \"%s\": %s",
2023
						 user, PQerrorMessage(AH->connection));
2024 2025 2026 2027

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

	destroyPQExpBuffer(cmd);
2031 2032
}

2033

2034 2035 2036 2037 2038 2039 2040 2041 2042 2043
/*
 * 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 ?
B
Bruce Momjian 已提交
2044
					  "true" : "false");
2045 2046 2047 2048 2049 2050 2051 2052

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

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
2053
			warn_or_die_horribly(AH, modulename,
2054 2055
								 "could not set default_with_oids: %s",
								 PQerrorMessage(AH->connection));
2056 2057 2058 2059 2060 2061 2062 2063 2064 2065

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

	destroyPQExpBuffer(cmd);
}


2066
/*
2067
 * Issue the commands to connect to the specified database.
2068 2069
 *
 * If we're currently restoring right into a database, this will
B
Bruce Momjian 已提交
2070
 * actually establish a connection. Otherwise it puts a \connect into
2071
 * the script output.
2072 2073
 *
 * NULL dbname implies reconnecting to the current DB (pretty useless).
2074
 */
B
Bruce Momjian 已提交
2075
static void
2076
_reconnectToDB(ArchiveHandle *AH, const char *dbname)
2077
{
2078
	if (RestoringToDB(AH))
2079
		ReconnectToServer(AH, dbname, NULL);
2080
	else
2081 2082 2083
	{
		PQExpBuffer qry = createPQExpBuffer();

2084
		appendPQExpBuffer(qry, "\\connect %s\n\n",
2085
						  dbname ? fmtId(dbname) : "-");
2086
		ahprintf(AH, "%s", qry->data);
2087 2088
		destroyPQExpBuffer(qry);
	}
2089

2090
	/*
B
Bruce Momjian 已提交
2091 2092
	 * NOTE: currUser keeps track of what the imaginary session user in our
	 * script is.  It's now effectively reset to the original userID.
2093
	 */
2094 2095 2096
	if (AH->currUser)
		free(AH->currUser);

2097
	AH->currUser = strdup("");
2098 2099 2100 2101 2102

	/* don't assume we still know the output schema */
	if (AH->currSchema)
		free(AH->currSchema);
	AH->currSchema = strdup("");
2103
	AH->currWithOids = -1;
B
Bruce Momjian 已提交
2104

2105 2106
	/* re-establish fixed state */
	_doSetFixedOutputState(AH);
2107 2108
}

2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125
/*
 * 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);

	/*
B
Bruce Momjian 已提交
2126 2127
	 * NOTE: currUser keeps track of what the imaginary session user in our
	 * script is
2128 2129 2130 2131 2132 2133
	 */
	if (AH->currUser)
		free(AH->currUser);

	AH->currUser = strdup(user);
}
2134 2135

/*
B
Bruce Momjian 已提交
2136
 * Become the owner of the the given TOC entry object.	If
2137 2138
 * changes in ownership are not allowed, this doesn't do anything.
 */
B
Bruce Momjian 已提交
2139
static void
2140
_becomeOwner(ArchiveHandle *AH, TocEntry *te)
2141
{
2142
	if (AH->ropt && (AH->ropt->noOwner || !AH->ropt->use_setsessauth))
2143 2144
		return;

2145
	_becomeUser(AH, te->owner);
2146 2147
}

2148

2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162
/*
 * 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;
	}
}


2163 2164 2165 2166 2167 2168 2169
/*
 * Issue the commands to select the specified schema as the current schema
 * in the target database.
 */
static void
_selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
{
2170 2171
	PQExpBuffer qry;

2172 2173 2174 2175
	if (!schemaName || *schemaName == '\0' ||
		strcmp(AH->currSchema, schemaName) == 0)
		return;					/* no need to do anything */

2176 2177 2178
	qry = createPQExpBuffer();

	appendPQExpBuffer(qry, "SET search_path = %s",
2179
					  fmtId(schemaName));
2180 2181 2182
	if (strcmp(schemaName, "pg_catalog") != 0)
		appendPQExpBuffer(qry, ", pg_catalog");

2183 2184 2185 2186 2187 2188 2189
	if (RestoringToDB(AH))
	{
		PGresult   *res;

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
2190
			warn_or_die_horribly(AH, modulename,
B
Bruce Momjian 已提交
2191 2192
								 "could not set search_path to \"%s\": %s",
								 schemaName, PQerrorMessage(AH->connection));
2193 2194 2195 2196

		PQclear(res);
	}
	else
2197
		ahprintf(AH, "%s;\n\n", qry->data);
2198 2199 2200 2201

	if (AH->currSchema)
		free(AH->currSchema);
	AH->currSchema = strdup(schemaName);
2202 2203

	destroyPQExpBuffer(qry);
2204 2205
}

2206 2207 2208 2209 2210 2211 2212 2213
/*
 * Issue the commands to select the specified tablespace as the current one
 * in the target database.
 */
static void
_selectTablespace(ArchiveHandle *AH, const char *tablespace)
{
	PQExpBuffer qry;
B
Bruce Momjian 已提交
2214 2215
	const char *want,
			   *have;
2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246

	have = AH->currTablespace;
	want = tablespace;

	/* no need to do anything for non-tablespace object */
	if (!want)
		return;

	if (have && strcmp(want, have) == 0)
		return;					/* no need to do anything */

	qry = createPQExpBuffer();

	if (strcmp(want, "") == 0)
	{
		/* We want the tablespace to be the database's default */
		appendPQExpBuffer(qry, "SET default_tablespace = ''");
	}
	else
	{
		/* We want an explicit tablespace */
		appendPQExpBuffer(qry, "SET default_tablespace = %s", fmtId(want));
	}

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

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
2247
			warn_or_die_horribly(AH, modulename,
2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261
								 "could not set default_tablespace to %s: %s",
								 fmtId(want), PQerrorMessage(AH->connection));

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

	if (AH->currTablespace)
		free(AH->currTablespace);
	AH->currTablespace = strdup(want);

	destroyPQExpBuffer(qry);
}
2262

2263 2264 2265 2266 2267 2268 2269 2270
/*
 * Extract an object description for a TOC entry, and append it to buf.
 *
 * This is not quite as general as it may seem, since it really only
 * handles constructing the right thing to put into ALTER ... OWNER TO.
 *
 * The whole thing is pretty grotty, but we are kind of stuck since the
 * information used is all that's available in older dump files.
2271
 */
2272
static void
2273
_getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
2274
{
2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
	const char *type = te->desc;

	/* Use ALTER TABLE for views and sequences */
	if (strcmp(type, "VIEW") == 0 ||
		strcmp(type, "SEQUENCE") == 0)
		type = "TABLE";

	/* objects named by a schema and name */
	if (strcmp(type, "CONVERSION") == 0 ||
		strcmp(type, "DOMAIN") == 0 ||
		strcmp(type, "TABLE") == 0 ||
		strcmp(type, "TYPE") == 0)
	{
2288
		appendPQExpBuffer(buf, "%s ", type);
B
Bruce Momjian 已提交
2289
		if (te->namespace && te->namespace[0])	/* is null pre-7.3 */
2290
			appendPQExpBuffer(buf, "%s.", fmtId(te->namespace));
B
Bruce Momjian 已提交
2291

2292
		/*
B
Bruce Momjian 已提交
2293 2294 2295
		 * Pre-7.3 pg_dump would sometimes (not always) put a fmtId'd name
		 * into te->tag for an index. This check is heuristic, so make its
		 * scope as narrow as possible.
2296 2297 2298
		 */
		if (AH->version < K_VERS_1_7 &&
			te->tag[0] == '"' &&
B
Bruce Momjian 已提交
2299
			te->tag[strlen(te->tag) - 1] == '"' &&
2300 2301 2302 2303
			strcmp(type, "INDEX") == 0)
			appendPQExpBuffer(buf, "%s", te->tag);
		else
			appendPQExpBuffer(buf, "%s", fmtId(te->tag));
2304 2305
		return;
	}
2306

2307 2308 2309 2310 2311 2312 2313
	/* objects named by just a name */
	if (strcmp(type, "DATABASE") == 0 ||
		strcmp(type, "SCHEMA") == 0)
	{
		appendPQExpBuffer(buf, "%s %s", type, fmtId(te->tag));
		return;
	}
2314

B
Bruce Momjian 已提交
2315
	/*
B
Bruce Momjian 已提交
2316 2317
	 * These object types require additional decoration.  Fortunately, the
	 * information needed is exactly what's in the DROP command.
B
Bruce Momjian 已提交
2318
	 */
2319 2320 2321 2322
	if (strcmp(type, "AGGREGATE") == 0 ||
		strcmp(type, "FUNCTION") == 0 ||
		strcmp(type, "OPERATOR") == 0 ||
		strcmp(type, "OPERATOR CLASS") == 0)
B
Bruce Momjian 已提交
2323
	{
2324 2325 2326
		/* Chop "DROP " off the front and make a modifiable copy */
		char	   *first = strdup(te->dropStmt + 5);
		char	   *last;
2327

2328 2329
		/* point to last character in string */
		last = first + strlen(first) - 1;
2330

2331 2332 2333 2334
		/* Strip off any ';' or '\n' at the end */
		while (last >= first && (*last == '\n' || *last == ';'))
			last--;
		*(last + 1) = '\0';
B
Bruce Momjian 已提交
2335

2336
		appendPQExpBufferStr(buf, first);
B
Bruce Momjian 已提交
2337 2338

		free(first);
2339
		return;
2340 2341
	}

2342 2343
	write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n",
			  type);
2344 2345 2346
}

static void
2347
_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass)
B
Bruce Momjian 已提交
2348
{
2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362
	/* ACLs are dumped only during acl pass */
	if (acl_pass)
	{
		if (strcmp(te->desc, "ACL") != 0)
			return;
	}
	else
	{
		if (strcmp(te->desc, "ACL") == 0)
			return;
	}

	/*
	 * Avoid dumping the public schema, as it will already be created ...
B
Bruce Momjian 已提交
2363 2364
	 * unless we are using --clean mode, in which case it's been deleted and
	 * we'd better recreate it.
2365 2366 2367 2368 2369
	 */
	if (!ropt->dropSchema &&
		strcmp(te->desc, "SCHEMA") == 0 && strcmp(te->tag, "public") == 0)
		return;

2370
	/* Select owner, schema, and tablespace as necessary */
2371 2372
	_becomeOwner(AH, te);
	_selectOutputSchema(AH, te->namespace);
2373
	_selectTablespace(AH, te->tablespace);
2374 2375 2376 2377 2378 2379

	/* Set up OID mode too */
	if (strcmp(te->desc, "TABLE") == 0)
		_setWithOids(AH, te);

	/* Emit header comment for item */
2380
	if (!AH->noTocComments)
2381
	{
2382 2383 2384 2385 2386 2387 2388 2389 2390
		const char *pfx;

		if (isData)
			pfx = "Data for ";
		else
			pfx = "";

		ahprintf(AH, "--\n");
		if (AH->public.verbose)
2391
		{
2392 2393 2394 2395 2396
			ahprintf(AH, "-- TOC entry %d (class %u OID %u)\n",
					 te->dumpId, te->catalogId.tableoid, te->catalogId.oid);
			if (te->nDeps > 0)
			{
				int			i;
2397

2398 2399 2400 2401 2402
				ahprintf(AH, "-- Dependencies:");
				for (i = 0; i < te->nDeps; i++)
					ahprintf(AH, " %d", te->dependencies[i]);
				ahprintf(AH, "\n");
			}
2403
		}
2404
		ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s",
2405 2406 2407
				 pfx, te->tag, te->desc,
				 te->namespace ? te->namespace : "-",
				 te->owner);
B
Bruce Momjian 已提交
2408
		if (te->tablespace)
2409 2410 2411
			ahprintf(AH, "; Tablespace: %s", te->tablespace);
		ahprintf(AH, "\n");

B
Bruce Momjian 已提交
2412
		if (AH->PrintExtraTocPtr !=NULL)
2413 2414
			(*AH->PrintExtraTocPtr) (AH, te);
		ahprintf(AH, "--\n\n");
2415
	}
B
Bruce Momjian 已提交
2416

2417 2418 2419
	/*
	 * Actually print the definition.
	 *
B
Bruce Momjian 已提交
2420 2421 2422
	 * Really crude hack for suppressing AUTHORIZATION clause that old pg_dump
	 * versions put into CREATE SCHEMA.  We have to do this when --no-owner
	 * mode is selected.  This is ugly, but I see no other good way ...
2423
	 */
2424
	if (ropt->noOwner && strcmp(te->desc, "SCHEMA") == 0)
2425
	{
2426
		ahprintf(AH, "CREATE SCHEMA %s;\n\n\n", fmtId(te->tag));
2427
	}
2428
	else
2429
	{
2430 2431
		if (strlen(te->defn) > 0)
			ahprintf(AH, "%s\n\n", te->defn);
2432
	}
2433 2434 2435

	/*
	 * If we aren't using SET SESSION AUTH to determine ownership, we must
2436 2437 2438
	 * instead issue an ALTER OWNER command.  We assume that anything without
	 * a DROP command is not a separately ownable object.  All the categories
	 * with DROP commands must appear in one list or the other.
2439 2440
	 */
	if (!ropt->noOwner && !ropt->use_setsessauth &&
2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458
		strlen(te->owner) > 0 && strlen(te->dropStmt) > 0)
	{
		if (strcmp(te->desc, "AGGREGATE") == 0 ||
			strcmp(te->desc, "CONVERSION") == 0 ||
			strcmp(te->desc, "DATABASE") == 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, "SCHEMA") == 0 ||
			strcmp(te->desc, "TABLE") == 0 ||
			strcmp(te->desc, "TYPE") == 0 ||
			strcmp(te->desc, "VIEW") == 0 ||
			strcmp(te->desc, "SEQUENCE") == 0)
		{
			PQExpBuffer temp = createPQExpBuffer();

			appendPQExpBuffer(temp, "ALTER ");
2459
			_getObjectDescription(temp, te, AH);
2460 2461 2462 2463 2464 2465
			appendPQExpBuffer(temp, " OWNER TO %s;", fmtId(te->owner));
			ahprintf(AH, "%s\n\n", temp->data);
			destroyPQExpBuffer(temp);
		}
		else if (strcmp(te->desc, "CAST") == 0 ||
				 strcmp(te->desc, "CHECK CONSTRAINT") == 0 ||
2466
				 strcmp(te->desc, "CONSTRAINT") == 0 ||
2467 2468
				 strcmp(te->desc, "DEFAULT") == 0 ||
				 strcmp(te->desc, "FK CONSTRAINT") == 0 ||
2469
				 strcmp(te->desc, "INDEX") == 0 ||
2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480
				 strcmp(te->desc, "PROCEDURAL LANGUAGE") == 0 ||
				 strcmp(te->desc, "RULE") == 0 ||
				 strcmp(te->desc, "TRIGGER") == 0)
		{
			/* these object types don't have separate owners */
		}
		else
		{
			write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n",
					  te->desc);
		}
2481
	}
B
Bruce Momjian 已提交
2482

2483 2484
	/*
	 * If it's an ACL entry, it might contain SET SESSION AUTHORIZATION
B
Bruce Momjian 已提交
2485
	 * commands, so we can no longer assume we know the current auth setting.
2486 2487 2488 2489 2490 2491 2492
	 */
	if (strncmp(te->desc, "ACL", 3) == 0)
	{
		if (AH->currUser)
			free(AH->currUser);
		AH->currUser = NULL;
	}
B
Bruce Momjian 已提交
2493 2494
}

B
Bruce Momjian 已提交
2495 2496
void
WriteHead(ArchiveHandle *AH)
B
Bruce Momjian 已提交
2497
{
B
Bruce Momjian 已提交
2498
	struct tm	crtm;
2499

B
Bruce Momjian 已提交
2500 2501 2502 2503 2504
	(*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);
2505
	(*AH->WriteBytePtr) (AH, AH->offSize);
B
Bruce Momjian 已提交
2506
	(*AH->WriteBytePtr) (AH, AH->format);
B
Bruce Momjian 已提交
2507

2508
#ifndef HAVE_LIBZ
B
Bruce Momjian 已提交
2509
	if (AH->compression != 0)
2510
		write_msg(modulename, "WARNING: requested compression not available in this "
2511
				  "installation -- archive will be uncompressed\n");
B
Bruce Momjian 已提交
2512

B
Bruce Momjian 已提交
2513
	AH->compression = 0;
2514
#endif
B
Bruce Momjian 已提交
2515

2516 2517 2518 2519 2520 2521 2522 2523 2524 2525
	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);
2526
	WriteStr(AH, PQdb(AH->connection));
2527 2528
	WriteStr(AH, AH->public.remoteVersionStr);
	WriteStr(AH, PG_VERSION);
B
Bruce Momjian 已提交
2529 2530
}

B
Bruce Momjian 已提交
2531 2532
void
ReadHead(ArchiveHandle *AH)
B
Bruce Momjian 已提交
2533
{
B
Bruce Momjian 已提交
2534 2535
	char		tmpMag[7];
	int			fmt;
2536
	struct tm	crtm;
B
Bruce Momjian 已提交
2537

2538
	/* If we haven't already read the header... */
B
Bruce Momjian 已提交
2539 2540
	if (!AH->readHeader)
	{
B
Bruce Momjian 已提交
2541

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

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

B
Bruce Momjian 已提交
2547 2548
		AH->vmaj = (*AH->ReadBytePtr) (AH);
		AH->vmin = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
2549

B
Bruce Momjian 已提交
2550 2551 2552
		if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))		/* Version > 1.0 */
			AH->vrev = (*AH->ReadBytePtr) (AH);
		else
2553
			AH->vrev = 0;
B
Bruce Momjian 已提交
2554

B
Bruce Momjian 已提交
2555
		AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
B
Bruce Momjian 已提交
2556 2557


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

B
Bruce Momjian 已提交
2562
		AH->intSize = (*AH->ReadBytePtr) (AH);
2563
		if (AH->intSize > 32)
P
Peter Eisentraut 已提交
2564 2565
			die_horribly(AH, modulename, "sanity check on integer size (%lu) failed\n",
						 (unsigned long) AH->intSize);
B
Bruce Momjian 已提交
2566

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

2570
		if (AH->version >= K_VERS_1_7)
B
Bruce Momjian 已提交
2571
			AH->offSize = (*AH->ReadBytePtr) (AH);
2572
		else
B
Bruce Momjian 已提交
2573
			AH->offSize = AH->intSize;
2574

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

2577
		if (AH->format != fmt)
2578 2579
			die_horribly(AH, modulename, "expected format (%d) differs from format found in file (%d)\n",
						 AH->format, fmt);
B
Bruce Momjian 已提交
2580
	}
B
Bruce Momjian 已提交
2581

B
Bruce Momjian 已提交
2582 2583
	if (AH->version >= K_VERS_1_2)
	{
2584
		if (AH->version < K_VERS_1_4)
B
Bruce Momjian 已提交
2585
			AH->compression = (*AH->ReadBytePtr) (AH);
2586 2587
		else
			AH->compression = ReadInt(AH);
B
Bruce Momjian 已提交
2588 2589
	}
	else
2590
		AH->compression = Z_DEFAULT_COMPRESSION;
B
Bruce Momjian 已提交
2591

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

2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610
	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 已提交
2611
		if (AH->createDate == (time_t) -1)
2612
			write_msg(modulename, "WARNING: invalid creation date in header\n");
2613 2614
	}

2615 2616 2617 2618 2619 2620
	if (AH->version >= K_VERS_1_10)
	{
		AH->archiveRemoteVersion = ReadStr(AH);
		AH->archiveDumpVersion = ReadStr(AH);
	}

B
Bruce Momjian 已提交
2621 2622 2623
}


2624 2625 2626 2627 2628 2629 2630 2631 2632
/*
 * checkSeek
 *	  check to see if fseek can be performed.
 */

bool
checkSeek(FILE *fp)
{

B
Bruce Momjian 已提交
2633
	if (fseeko(fp, 0, SEEK_CUR) != 0)
2634 2635
		return false;
	else if (sizeof(off_t) > sizeof(long))
B
Bruce Momjian 已提交
2636 2637

		/*
B
Bruce Momjian 已提交
2638 2639
		 * At this point, off_t is too large for long, so we return based on
		 * whether an off_t version of fseek is available.
B
Bruce Momjian 已提交
2640
		 */
2641 2642 2643 2644 2645 2646 2647 2648
#ifdef HAVE_FSEEKO
		return true;
#else
		return false;
#endif
	else
		return true;
}
2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661


/*
 * dumpTimestamp
 */
static void
dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim)
{
	char		buf[256];

	if (strftime(buf, 256, "%Y-%m-%d %H:%M:%S %Z", localtime(&tim)) != 0)
		ahprintf(AH, "-- %s %s\n\n", msg, buf);
}