pg_backup_archiver.c 65.4 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.152 2008/01/14 19:27:41 tgl Exp $
19
 *
B
Bruce Momjian 已提交
20 21 22
 *-------------------------------------------------------------------------
 */

23
#include "pg_backup_db.h"
24
#include "dumputils.h"
25

26
#include <ctype.h>
27

28
#include <unistd.h>
B
Bruce Momjian 已提交
29

30 31 32 33
#ifdef WIN32
#include <io.h>
#endif

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

36

37
const char *progname;
38

39
static const char *modulename = gettext_noop("archiver");
40 41


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

48

49
static void _doSetFixedOutputState(ArchiveHandle *AH);
50
static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
51
static void _doSetWithOids(ArchiveHandle *AH, const bool withOids);
52
static void _reconnectToDB(ArchiveHandle *AH, const char *dbname);
53 54
static void _becomeUser(ArchiveHandle *AH, const char *user);
static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
55
static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
56
static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
57 58
static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
59
static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls);
B
Bruce Momjian 已提交
60 61
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
62
static TocEntry *getTocEntryByDumpId(ArchiveHandle *AH, DumpId id);
B
Bruce Momjian 已提交
63 64
static void _moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te);
static int	_discoverArchiveFormat(ArchiveHandle *AH);
B
Bruce Momjian 已提交
65

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

70
static void dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim);
71 72
static OutputContext SetOutput(ArchiveHandle *AH, char *filename, int compression);
static void ResetOutput(ArchiveHandle *AH, OutputContext savedContext);
73

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
CreateArchive(const char *FileSpec, const ArchiveFormat fmt,
88
			  const int compression, ArchiveMode mode)
89

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

	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 123
		die_horribly(AH, modulename, "could not close output file: %s\n",
					 strerror(errno));
B
Bruce Momjian 已提交
124 125 126
}

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

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

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

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

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

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

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

174
	/*
B
Bruce Momjian 已提交
175 176 177 178
	 * 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.
179
	 *
B
Bruce Momjian 已提交
180
	 * We could scan for wanted TABLE entries, but that is not the same as
181
	 * dataOnly. At this stage, it seems unnecessary (6-Mar-2001).
B
Bruce Momjian 已提交
182 183 184
	 */
	if (!ropt->dataOnly)
	{
B
Bruce Momjian 已提交
185
		int			impliedDataOnly = 1;
186 187

		for (te = AH->toc->next; te != AH->toc; te = te->next)
B
Bruce Momjian 已提交
188
		{
189
			reqs = _tocEntryRequired(te, ropt, true);
190
			if ((reqs & REQ_SCHEMA) != 0)
B
Bruce Momjian 已提交
191
			{					/* It's schema, and it's wanted */
192 193 194 195 196 197 198
				impliedDataOnly = 0;
				break;
			}
		}
		if (impliedDataOnly)
		{
			ropt->dataOnly = impliedDataOnly;
199
			ahlog(AH, 1, "implied data-only restore\n");
200
		}
B
Bruce Momjian 已提交
201
	}
202

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

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

211 212 213
	if (AH->public.verbose)
		dumpTimestamp(AH, "Started on", AH->createDate);

214
	if (ropt->single_txn)
215 216 217 218 219 220
	{
		if (AH->connection)
			StartTransaction(AH);
		else
			ahprintf(AH, "BEGIN;\n\n");
	}
221

222 223 224 225 226
	/*
	 * Establish important parameter values right away.
	 */
	_doSetFixedOutputState(AH);

227 228
	AH->stage = STAGE_PROCESSING;

B
Bruce Momjian 已提交
229 230
	/*
	 * Drop the items at the start, in reverse order
231
	 */
B
Bruce Momjian 已提交
232 233
	if (ropt->dropSchema)
	{
234
		for (te = AH->toc->prev; te != AH->toc; te = te->prev)
B
Bruce Momjian 已提交
235
		{
236 237
			AH->currentTE = te;

B
Bruce Momjian 已提交
238
			reqs = _tocEntryRequired(te, ropt, false /* needn't drop ACLs */ );
239
			if (((reqs & REQ_SCHEMA) != 0) && te->dropStmt)
240 241
			{
				/* We want the schema */
242
				ahlog(AH, 1, "dropping %s %s\n", te->desc, te->tag);
243
				/* Select owner and schema as necessary */
244
				_becomeOwner(AH, te);
245
				_selectOutputSchema(AH, te->namespace);
246
				/* Drop it */
247 248 249
				ahprintf(AH, "%s", te->dropStmt);
			}
		}
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265

		/*
		 * _selectOutputSchema may have set currSchema to reflect the effect
		 * of a "SET search_path" command it emitted.  However, by now we may
		 * have dropped that schema; or it might not have existed in the first
		 * place.  In either case the effective value of search_path will not
		 * be what we think.  Forcibly reset currSchema so that we will
		 * re-establish the search_path setting when needed (after creating
		 * the schema).
		 *
		 * If we treated users as pg_dump'able objects then we'd need to reset
		 * currUser here too.
		 */
		if (AH->currSchema)
			free(AH->currSchema);
		AH->currSchema = strdup("");
B
Bruce Momjian 已提交
266
	}
B
Bruce Momjian 已提交
267

268
	/*
269
	 * Now process each non-ACL TOC entry
270
	 */
271
	for (te = AH->toc->next; te != AH->toc; te = te->next)
B
Bruce Momjian 已提交
272
	{
273 274
		AH->currentTE = te;

275
		/* Work out what, if anything, we want from this entry */
276
		reqs = _tocEntryRequired(te, ropt, false);
277

278 279 280
		/* Dump any relevant dump warnings to stderr */
		if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
		{
281
			if (!ropt->dataOnly && te->defn != NULL && strlen(te->defn) != 0)
282 283 284
				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);
285
		}
286

287 288
		defnDumped = false;

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

293
			_printTocEntry(AH, te, ropt, false, false);
294
			defnDumped = true;
295

B
Bruce Momjian 已提交
296
			/*
297 298
			 * If we could not create a table and --no-data-for-failed-tables
			 * was given, ignore the corresponding TABLE DATA
B
Bruce Momjian 已提交
299
			 */
300 301 302
			if (ropt->noDataForFailedTables &&
				AH->lastErrorTE == te &&
				strcmp(te->desc, "TABLE") == 0)
B
Bruce Momjian 已提交
303
			{
304
				TocEntry   *tes;
B
Bruce Momjian 已提交
305

306 307
				ahlog(AH, 1, "table \"%s\" could not be created, will not restore its data\n",
					  te->tag);
B
Bruce Momjian 已提交
308

309
				for (tes = te->next; tes != AH->toc; tes = tes->next)
B
Bruce Momjian 已提交
310
				{
311 312 313 314
					if (strcmp(tes->desc, "TABLE DATA") == 0 &&
						strcmp(tes->tag, te->tag) == 0 &&
						strcmp(tes->namespace ? tes->namespace : "",
							   te->namespace ? te->namespace : "") == 0)
B
Bruce Momjian 已提交
315
					{
316 317
						/* mark it unwanted */
						ropt->idWanted[tes->dumpId - 1] = false;
B
Bruce Momjian 已提交
318
						break;
319 320 321 322
					}
				}
			}

323
			/* If we created a DB, connect to it... */
B
Bruce Momjian 已提交
324
			if (strcmp(te->desc, "DATABASE") == 0)
325
			{
326 327
				ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag);
				_reconnectToDB(AH, te->tag);
328
			}
329
		}
B
Bruce Momjian 已提交
330

B
Bruce Momjian 已提交
331
		/*
332
		 * If we have a data component, then process it
333
		 */
334
		if ((reqs & REQ_DATA) != 0)
B
Bruce Momjian 已提交
335
		{
336
			/*
B
Bruce Momjian 已提交
337 338 339
			 * 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.
340
			 */
341
			if (te->hadDumper)
342 343
			{
				/*
344
				 * If we can output the data, then restore it.
345
				 */
B
Bruce Momjian 已提交
346
				if (AH->PrintTocDataPtr !=NULL && (reqs & REQ_DATA) != 0)
347 348 349
				{
#ifndef HAVE_LIBZ
					if (AH->compression != 0)
350
						die_horribly(AH, modulename, "cannot restore from compressed archive (compression not supported in this installation)\n");
351
#endif
352

353
					_printTocEntry(AH, te, ropt, true, false);
354

355 356
					if (strcmp(te->desc, "BLOBS") == 0 ||
						strcmp(te->desc, "BLOB COMMENTS") == 0)
357
					{
358
						ahlog(AH, 1, "restoring %s\n", te->desc);
359

360 361 362
						_selectOutputSchema(AH, "pg_catalog");

						(*AH->PrintTocDataPtr) (AH, te, ropt);
363 364 365 366 367
					}
					else
					{
						_disableTriggersIfNecessary(AH, te, ropt);

368 369
						/* Select owner and schema as necessary */
						_becomeOwner(AH, te);
370
						_selectOutputSchema(AH, te->namespace);
371

372 373
						ahlog(AH, 1, "restoring data for table \"%s\"\n",
							  te->tag);
374 375

						/*
B
Bruce Momjian 已提交
376 377 378 379
						 * 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.
380
						 *
381 382 383
						 * For V1.3+, the table data MUST have a copy
						 * statement so that we can go into appropriate mode
						 * with libpq.
384 385
						 */
						if (te->copyStmt && strlen(te->copyStmt) > 0)
386
						{
387
							ahprintf(AH, "%s", te->copyStmt);
388 389
							AH->writingCopyData = true;
						}
390 391 392

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

393 394
						AH->writingCopyData = false;

395 396 397
						_enableTriggersIfNecessary(AH, te, ropt);
					}
				}
398 399 400 401
			}
			else if (!defnDumped)
			{
				/* If we haven't already dumped the defn part, do so now */
402
				ahlog(AH, 1, "executing %s %s\n", te->desc, te->tag);
403
				_printTocEntry(AH, te, ropt, false, false);
404 405
			}
		}
B
Bruce Momjian 已提交
406
	}							/* end loop over TOC entries */
B
Bruce Momjian 已提交
407

408 409 410
	/*
	 * Scan TOC again to output ownership commands and ACLs
	 */
411
	for (te = AH->toc->next; te != AH->toc; te = te->next)
412
	{
413 414
		AH->currentTE = te;

415 416 417 418 419
		/* 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 已提交
420
			ahlog(AH, 1, "setting owner and privileges for %s %s\n",
421
				  te->desc, te->tag);
422 423 424 425
			_printTocEntry(AH, te, ropt, false, true);
		}
	}

426
	if (ropt->single_txn)
427 428 429 430 431 432
	{
		if (AH->connection)
			CommitTransaction(AH);
		else
			ahprintf(AH, "COMMIT;\n\n");
	}
B
Bruce Momjian 已提交
433

434 435 436
	if (AH->public.verbose)
		dumpTimestamp(AH, "Completed on", time(NULL));

437 438
	ahprintf(AH, "--\n-- PostgreSQL database dump complete\n--\n\n");

439
	/*
440
	 * Clean up & we're done.
441
	 */
442 443
	AH->stage = STAGE_FINALIZING;

444 445 446 447 448 449 450
	if (ropt->filename || ropt->compression)
		ResetOutput(AH, sav);

	if (ropt->useDB)
	{
		PQfinish(AH->connection);
		AH->connection = NULL;
451
	}
B
Bruce Momjian 已提交
452 453
}

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

B
Bruce Momjian 已提交
463
	opts = (RestoreOptions *) calloc(1, sizeof(RestoreOptions));
B
Bruce Momjian 已提交
464 465

	opts->format = archUnknown;
466
	opts->suppressDumpWarnings = false;
467
	opts->exit_on_error = false;
B
Bruce Momjian 已提交
468 469 470 471

	return opts;
}

B
Bruce Momjian 已提交
472 473
static void
_disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
B
Bruce Momjian 已提交
474
{
475 476
	/* This hack is only needed in a data-only restore */
	if (!ropt->dataOnly || !ropt->disable_triggers)
477 478
		return;

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

481
	/*
B
Bruce Momjian 已提交
482
	 * Become superuser if possible, since they are the only ones who can
483 484 485
	 * 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?)
486
	 */
487
	_becomeUser(AH, ropt->superuser);
488 489

	/*
490
	 * Disable them.
491
	 */
492
	_selectOutputSchema(AH, te->namespace);
493

494 495
	ahprintf(AH, "ALTER TABLE %s DISABLE TRIGGER ALL;\n\n",
			 fmtId(te->tag));
B
Bruce Momjian 已提交
496 497
}

B
Bruce Momjian 已提交
498 499
static void
_enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
B
Bruce Momjian 已提交
500
{
501 502
	/* This hack is only needed in a data-only restore */
	if (!ropt->dataOnly || !ropt->disable_triggers)
503 504
		return;

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

507
	/*
B
Bruce Momjian 已提交
508
	 * Become superuser if possible, since they are the only ones who can
509 510 511
	 * 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?)
512
	 */
513
	_becomeUser(AH, ropt->superuser);
514 515

	/*
516
	 * Enable them.
517
	 */
518
	_selectOutputSchema(AH, te->namespace);
519

520 521
	ahprintf(AH, "ALTER TABLE %s ENABLE TRIGGER ALL;\n\n",
			 fmtId(te->tag));
522
}
B
Bruce Momjian 已提交
523 524

/*
525
 * This is a routine that is part of the dumper interface, hence the 'Archive*' parameter.
B
Bruce Momjian 已提交
526 527 528
 */

/* Public */
P
Peter Eisentraut 已提交
529 530
size_t
WriteData(Archive *AHX, const void *data, size_t dLen)
B
Bruce Momjian 已提交
531
{
B
Bruce Momjian 已提交
532
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
B
Bruce Momjian 已提交
533

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

B
Bruce Momjian 已提交
537
	return (*AH->WriteDataPtr) (AH, data, dLen);
B
Bruce Momjian 已提交
538 539 540
}

/*
B
Bruce Momjian 已提交
541
 * Create a new TOC entry. The TOC was designed as a TOC, but is now the
B
Bruce Momjian 已提交
542 543 544 545
 * repository for all metadata. But the name has stuck.
 */

/* Public */
B
Bruce Momjian 已提交
546
void
547 548 549
ArchiveEntry(Archive *AHX,
			 CatalogId catalogId, DumpId dumpId,
			 const char *tag,
550
			 const char *namespace,
B
Bruce Momjian 已提交
551
			 const char *tablespace,
552
			 const char *owner, bool withOids,
553 554 555
			 const char *desc, const char *defn,
			 const char *dropStmt, const char *copyStmt,
			 const DumpId *deps, int nDeps,
B
Bruce Momjian 已提交
556
			 DataDumperPtr dumpFn, void *dumpArg)
B
Bruce Momjian 已提交
557
{
B
Bruce Momjian 已提交
558 559 560 561 562
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *newToc;

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

565 566 567 568
	AH->tocCount++;
	if (dumpId > AH->maxDumpId)
		AH->maxDumpId = dumpId;

B
Bruce Momjian 已提交
569 570 571 572 573
	newToc->prev = AH->toc->prev;
	newToc->next = AH->toc;
	AH->toc->prev->next = newToc;
	AH->toc->prev = newToc;

574 575
	newToc->catalogId = catalogId;
	newToc->dumpId = dumpId;
576

577
	newToc->tag = strdup(tag);
578
	newToc->namespace = namespace ? strdup(namespace) : NULL;
579
	newToc->tablespace = tablespace ? strdup(tablespace) : NULL;
580
	newToc->owner = strdup(owner);
581
	newToc->withOids = withOids;
B
Bruce Momjian 已提交
582
	newToc->desc = strdup(desc);
583 584 585
	newToc->defn = strdup(defn);
	newToc->dropStmt = strdup(dropStmt);
	newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
586

587 588 589 590 591 592 593 594 595 596 597
	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;
	}
598

599 600
	newToc->dataDumper = dumpFn;
	newToc->dataDumperArg = dumpArg;
601
	newToc->hadDumper = dumpFn ? true : false;
B
Bruce Momjian 已提交
602

603
	newToc->formatData = NULL;
B
Bruce Momjian 已提交
604

B
Bruce Momjian 已提交
605
	if (AH->ArchiveEntryPtr !=NULL)
B
Bruce Momjian 已提交
606
		(*AH->ArchiveEntryPtr) (AH, newToc);
B
Bruce Momjian 已提交
607 608 609
}

/* Public */
B
Bruce Momjian 已提交
610 611
void
PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
612
{
B
Bruce Momjian 已提交
613 614 615 616
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *te = AH->toc->next;
	OutputContext sav;
	char	   *fmtName;
B
Bruce Momjian 已提交
617

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

621 622
	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 已提交
623
			 AH->archdbname, AH->tocCount, AH->compression);
624

B
Bruce Momjian 已提交
625 626
	switch (AH->format)
	{
627 628 629 630 631 632 633 634 635 636 637 638
		case archFiles:
			fmtName = "FILES";
			break;
		case archCustom:
			fmtName = "CUSTOM";
			break;
		case archTar:
			fmtName = "TAR";
			break;
		default:
			fmtName = "UNKNOWN";
	}
639 640

	ahprintf(AH, ";     Dump Version: %d.%d-%d\n", AH->vmaj, AH->vmin, AH->vrev);
641
	ahprintf(AH, ";     Format: %s\n", fmtName);
T
Tom Lane 已提交
642 643
	ahprintf(AH, ";     Integer: %d bytes\n", (int) AH->intSize);
	ahprintf(AH, ";     Offset: %d bytes\n", (int) AH->offSize);
644 645 646 647 648 649
	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);
650

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

B
Bruce Momjian 已提交
653 654
	while (te != AH->toc)
	{
655
		if (_tocEntryRequired(te, ropt, true) != 0)
656
			ahprintf(AH, "%d; %u %u %s %s %s %s\n", te->dumpId,
657
					 te->catalogId.tableoid, te->catalogId.oid,
658 659
					 te->desc, te->namespace ? te->namespace : "-",
					 te->tag, te->owner);
B
Bruce Momjian 已提交
660
		te = te->next;
B
Bruce Momjian 已提交
661
	}
B
Bruce Momjian 已提交
662

B
Bruce Momjian 已提交
663 664
	if (ropt->filename)
		ResetOutput(AH, sav);
B
Bruce Momjian 已提交
665 666
}

667 668 669 670 671
/***********
 * BLOB Archival
 ***********/

/* Called by a dumper to signal start of a BLOB */
B
Bruce Momjian 已提交
672
int
673
StartBlob(Archive *AHX, Oid oid)
674
{
B
Bruce Momjian 已提交
675
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
676

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

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

B
Bruce Momjian 已提交
682
	return 1;
683 684 685
}

/* Called by a dumper to signal end of a BLOB */
B
Bruce Momjian 已提交
686
int
687
EndBlob(Archive *AHX, Oid oid)
688
{
B
Bruce Momjian 已提交
689
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
690

B
Bruce Momjian 已提交
691 692
	if (AH->EndBlobPtr)
		(*AH->EndBlobPtr) (AH, AH->currToc, oid);
693

B
Bruce Momjian 已提交
694
	return 1;
695 696 697 698 699 700
}

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

701
/*
B
Bruce Momjian 已提交
702
 * Called by a format handler before any blobs are restored
703
 */
B
Bruce Momjian 已提交
704 705
void
StartRestoreBlobs(ArchiveHandle *AH)
706
{
707 708 709 710 711 712 713
	if (!AH->ropt->single_txn)
	{
		if (AH->connection)
			StartTransaction(AH);
		else
			ahprintf(AH, "BEGIN;\n\n");
	}
714

715 716 717 718
	AH->blobCount = 0;
}

/*
B
Bruce Momjian 已提交
719
 * Called by a format handler after all blobs are restored
720
 */
B
Bruce Momjian 已提交
721 722
void
EndRestoreBlobs(ArchiveHandle *AH)
723
{
724 725 726 727 728 729 730
	if (!AH->ropt->single_txn)
	{
		if (AH->connection)
			CommitTransaction(AH);
		else
			ahprintf(AH, "COMMIT;\n\n");
	}
731

732
	ahlog(AH, 1, "restored %d large objects\n", AH->blobCount);
733 734 735
}


736 737 738
/*
 * Called by a format handler to initiate restoration of a blob
 */
B
Bruce Momjian 已提交
739
void
740
StartRestoreBlob(ArchiveHandle *AH, Oid oid)
741
{
742
	Oid			loOid;
743

744 745
	AH->blobCount++;

746 747 748
	/* Initialize the LO Buffer */
	AH->lo_buf_used = 0;

749 750 751
	ahlog(AH, 2, "restoring large object with OID %u\n", oid);

	if (AH->connection)
752
	{
753 754 755 756 757 758 759 760 761 762 763 764
		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);
765
	}
766

B
Bruce Momjian 已提交
767
	AH->writingBlob = 1;
768 769
}

B
Bruce Momjian 已提交
770
void
771
EndRestoreBlob(ArchiveHandle *AH, Oid oid)
772
{
773 774 775
	if (AH->lo_buf_used > 0)
	{
		/* Write remaining bytes from the LO buffer */
776
		dump_lo_buf(AH);
777
	}
778

B
Bruce Momjian 已提交
779
	AH->writingBlob = 0;
780

781
	if (AH->connection)
782
	{
783 784 785 786 787 788
		lo_close(AH->connection, AH->loFd);
		AH->loFd = -1;
	}
	else
	{
		ahprintf(AH, "SELECT lo_close(0);\n\n");
789
	}
790 791
}

B
Bruce Momjian 已提交
792 793 794 795
/***********
 * Sorting and Reordering
 ***********/

B
Bruce Momjian 已提交
796 797
void
SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
798
{
B
Bruce Momjian 已提交
799 800 801 802 803
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	FILE	   *fh;
	char		buf[1024];
	char	   *cmnt;
	char	   *endptr;
804
	DumpId		id;
B
Bruce Momjian 已提交
805 806 807 808
	TocEntry   *te;
	TocEntry   *tePrev;

	/* Allocate space for the 'wanted' array, and init it */
809 810
	ropt->idWanted = (bool *) malloc(sizeof(bool) * AH->maxDumpId);
	memset(ropt->idWanted, 0, sizeof(bool) * AH->maxDumpId);
B
Bruce Momjian 已提交
811

B
Bruce Momjian 已提交
812 813
	/* Set prev entry as head of list */
	tePrev = AH->toc;
B
Bruce Momjian 已提交
814

B
Bruce Momjian 已提交
815 816 817
	/* Setup the file */
	fh = fopen(ropt->tocFile, PG_BINARY_R);
	if (!fh)
818 819
		die_horribly(AH, modulename, "could not open TOC file \"%s\": %s\n",
					 ropt->tocFile, strerror(errno));
B
Bruce Momjian 已提交
820

821
	while (fgets(buf, sizeof(buf), fh) != NULL)
B
Bruce Momjian 已提交
822
	{
823
		/* Truncate line at comment, if any */
B
Bruce Momjian 已提交
824 825 826 827
		cmnt = strchr(buf, ';');
		if (cmnt != NULL)
			cmnt[0] = '\0';

828 829
		/* Ignore if all blank */
		if (strspn(buf, " \t\r") == strlen(buf))
B
Bruce Momjian 已提交
830 831
			continue;

832
		/* Get an ID, check it's valid and not already seen */
B
Bruce Momjian 已提交
833
		id = strtol(buf, &endptr, 10);
834 835
		if (endptr == buf || id <= 0 || id > AH->maxDumpId ||
			ropt->idWanted[id - 1])
B
Bruce Momjian 已提交
836
		{
837
			write_msg(modulename, "WARNING: line ignored: %s\n", buf);
B
Bruce Momjian 已提交
838 839
			continue;
		}
B
Bruce Momjian 已提交
840

B
Bruce Momjian 已提交
841
		/* Find TOC entry */
842
		te = getTocEntryByDumpId(AH, id);
B
Bruce Momjian 已提交
843
		if (!te)
844 845
			die_horribly(AH, modulename, "could not find entry for ID %d\n",
						 id);
B
Bruce Momjian 已提交
846

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

B
Bruce Momjian 已提交
849 850 851
		_moveAfter(AH, tePrev, te);
		tePrev = te;
	}
B
Bruce Momjian 已提交
852

B
Bruce Momjian 已提交
853
	if (fclose(fh) != 0)
854 855
		die_horribly(AH, modulename, "could not close TOC file: %s\n",
					 strerror(errno));
B
Bruce Momjian 已提交
856 857
}

858 859 860 861 862 863 864 865 866 867 868 869 870
/*
 * Set up a dummy ID filter that selects all dump IDs
 */
void
InitDummyWantedList(Archive *AHX, RestoreOptions *ropt)
{
	ArchiveHandle *AH = (ArchiveHandle *) AHX;

	/* Allocate space for the 'wanted' array, and init it to 1's */
	ropt->idWanted = (bool *) malloc(sizeof(bool) * AH->maxDumpId);
	memset(ropt->idWanted, 1, sizeof(bool) * AH->maxDumpId);
}

B
Bruce Momjian 已提交
871 872 873 874 875 876
/**********************
 * 'Convenience functions that look like standard IO functions
 * for writing data when in dump mode.
 **********************/

/* Public */
B
Bruce Momjian 已提交
877 878 879 880
int
archputs(const char *s, Archive *AH)
{
	return WriteData(AH, s, strlen(s));
B
Bruce Momjian 已提交
881 882 883
}

/* Public */
B
Bruce Momjian 已提交
884 885
int
archprintf(Archive *AH, const char *fmt,...)
B
Bruce Momjian 已提交
886
{
B
Bruce Momjian 已提交
887 888 889 890 891 892
	char	   *p = NULL;
	va_list		ap;
	int			bSize = strlen(fmt) + 256;
	int			cnt = -1;

	/*
B
Bruce Momjian 已提交
893 894 895
	 * 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 已提交
896 897
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
B
Bruce Momjian 已提交
898
	{
B
Bruce Momjian 已提交
899 900
		if (p != NULL)
			free(p);
901
		bSize *= 2;
B
Bruce Momjian 已提交
902
		p = (char *) malloc(bSize);
903
		if (p == NULL)
904
			exit_horribly(AH, modulename, "out of memory\n");
905 906 907
		va_start(ap, fmt);
		cnt = vsnprintf(p, bSize, fmt, ap);
		va_end(ap);
B
Bruce Momjian 已提交
908 909 910 911
	}
	WriteData(AH, p, cnt);
	free(p);
	return cnt;
B
Bruce Momjian 已提交
912 913 914 915 916 917 918
}


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

919
static OutputContext
B
Bruce Momjian 已提交
920
SetOutput(ArchiveHandle *AH, char *filename, int compression)
B
Bruce Momjian 已提交
921
{
B
Bruce Momjian 已提交
922
	OutputContext sav;
923
	int			fn;
B
Bruce Momjian 已提交
924 925 926 927 928 929

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

	if (filename)
930
		fn = -1;
B
Bruce Momjian 已提交
931 932 933 934
	else if (AH->FH)
		fn = fileno(AH->FH);
	else if (AH->fSpec)
	{
935
		fn = -1;
B
Bruce Momjian 已提交
936 937 938 939 940 941
		filename = AH->fSpec;
	}
	else
		fn = fileno(stdout);

	/* If compression explicitly requested, use gzopen */
942
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
943 944
	if (compression != 0)
	{
945 946 947
		char		fmode[10];

		/* Don't use PG_BINARY_x since this is zlib */
948
		sprintf(fmode, "wb%d", compression);
949 950
		if (fn >= 0)
			AH->OF = gzdopen(dup(fn), fmode);
B
Bruce Momjian 已提交
951 952
		else
			AH->OF = gzopen(filename, fmode);
953
		AH->gzOut = 1;
B
Bruce Momjian 已提交
954 955
	}
	else
B
Bruce Momjian 已提交
956
#endif
957
	{							/* Use fopen */
958 959 960 961 962 963 964
		if (AH->mode == archModeAppend)
		{
			if (fn >= 0)
				AH->OF = fdopen(dup(fn), PG_BINARY_A);
			else
				AH->OF = fopen(filename, PG_BINARY_A);
		}
B
Bruce Momjian 已提交
965
		else
966 967 968 969 970 971
		{
			if (fn >= 0)
				AH->OF = fdopen(dup(fn), PG_BINARY_W);
			else
				AH->OF = fopen(filename, PG_BINARY_W);
		}
972
		AH->gzOut = 0;
B
Bruce Momjian 已提交
973
	}
B
Bruce Momjian 已提交
974

975
	if (!AH->OF)
976 977 978 979 980 981 982 983
	{
		if (filename)
			die_horribly(AH, modulename, "could not open output file \"%s\": %s\n",
						 filename, strerror(errno));
		else
			die_horribly(AH, modulename, "could not open output file: %s\n",
						 strerror(errno));
	}
984

B
Bruce Momjian 已提交
985
	return sav;
B
Bruce Momjian 已提交
986 987
}

988
static void
B
Bruce Momjian 已提交
989
ResetOutput(ArchiveHandle *AH, OutputContext sav)
B
Bruce Momjian 已提交
990
{
B
Bruce Momjian 已提交
991
	int			res;
992

B
Bruce Momjian 已提交
993
	if (AH->gzOut)
994
		res = GZCLOSE(AH->OF);
B
Bruce Momjian 已提交
995
	else
996 997 998
		res = fclose(AH->OF);

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

B
Bruce Momjian 已提交
1002 1003
	AH->gzOut = sav.gzOut;
	AH->OF = sav.OF;
B
Bruce Momjian 已提交
1004 1005 1006 1007 1008
}



/*
B
Bruce Momjian 已提交
1009
 *	Print formatted text to the output file (usually stdout).
B
Bruce Momjian 已提交
1010
 */
B
Bruce Momjian 已提交
1011 1012
int
ahprintf(ArchiveHandle *AH, const char *fmt,...)
B
Bruce Momjian 已提交
1013
{
B
Bruce Momjian 已提交
1014 1015 1016 1017 1018 1019
	char	   *p = NULL;
	va_list		ap;
	int			bSize = strlen(fmt) + 256;		/* Should be enough */
	int			cnt = -1;

	/*
B
Bruce Momjian 已提交
1020 1021
	 * This is paranoid: deal with the possibility that vsnprintf is willing
	 * to ignore trailing null
B
Bruce Momjian 已提交
1022 1023 1024
	 */

	/*
B
Bruce Momjian 已提交
1025 1026
	 * or returns > 0 even if string does not fit. It may be the case that it
	 * returns cnt = bufsize
B
Bruce Momjian 已提交
1027 1028
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
1029
	{
B
Bruce Momjian 已提交
1030 1031
		if (p != NULL)
			free(p);
1032
		bSize *= 2;
B
Bruce Momjian 已提交
1033
		p = (char *) malloc(bSize);
1034
		if (p == NULL)
1035
			die_horribly(AH, modulename, "out of memory\n");
1036
		va_start(ap, fmt);
1037
		cnt = vsnprintf(p, bSize, fmt, ap);
1038
		va_end(ap);
B
Bruce Momjian 已提交
1039 1040 1041 1042
	}
	ahwrite(p, 1, cnt, AH);
	free(p);
	return cnt;
B
Bruce Momjian 已提交
1043 1044
}

B
Bruce Momjian 已提交
1045 1046
void
ahlog(ArchiveHandle *AH, int level, const char *fmt,...)
1047 1048 1049 1050 1051 1052 1053
{
	va_list		ap;

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

	va_start(ap, fmt);
1054
	_write_msg(NULL, fmt, ap);
1055 1056 1057
	va_end(ap);
}

1058 1059 1060
/*
 * Single place for logic which says 'We are restoring to a direct DB connection'.
 */
1061
static int
B
Bruce Momjian 已提交
1062
RestoringToDB(ArchiveHandle *AH)
1063 1064 1065 1066
{
	return (AH->ropt && AH->ropt->useDB && AH->connection);
}

1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
/*
 * 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 已提交
1082 1083
			"could not write to large object (result: %lu, expected: %lu)\n",
					   (unsigned long) res, (unsigned long) AH->lo_buf_used);
1084 1085 1086 1087
	}
	else
	{
		unsigned char *str;
B
Bruce Momjian 已提交
1088
		size_t		len;
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105

		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 已提交
1106
/*
B
Bruce Momjian 已提交
1107 1108 1109
 *	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
1110
 *	wants to generate a script (see TAR output).
B
Bruce Momjian 已提交
1111
 */
B
Bruce Momjian 已提交
1112 1113
int
ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
B
Bruce Momjian 已提交
1114
{
P
Peter Eisentraut 已提交
1115
	size_t		res;
1116

B
Bruce Momjian 已提交
1117
	if (AH->writingBlob)
1118
	{
B
Bruce Momjian 已提交
1119
		size_t		remaining = size * nmemb;
1120 1121

		while (AH->lo_buf_used + remaining > AH->lo_buf_size)
P
Peter Eisentraut 已提交
1122
		{
1123 1124 1125 1126 1127 1128 1129
			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 已提交
1130 1131
		}

1132 1133 1134
		memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining);
		AH->lo_buf_used += remaining;

P
Peter Eisentraut 已提交
1135
		return size * nmemb;
1136
	}
B
Bruce Momjian 已提交
1137
	else if (AH->gzOut)
1138
	{
B
Bruce Momjian 已提交
1139
		res = GZWRITE((void *) ptr, size, nmemb, AH->OF);
1140
		if (res != (nmemb * size))
1141
			die_horribly(AH, modulename, "could not write to output file: %s\n", strerror(errno));
1142 1143
		return res;
	}
B
Bruce Momjian 已提交
1144
	else if (AH->CustomOutPtr)
1145
	{
B
Bruce Momjian 已提交
1146 1147
		res = AH->CustomOutPtr (AH, ptr, size * nmemb);

1148
		if (res != (nmemb * size))
1149
			die_horribly(AH, modulename, "could not write to custom output routine\n");
1150 1151
		return res;
	}
1152 1153 1154
	else
	{
		/*
B
Bruce Momjian 已提交
1155 1156 1157
		 * If we're doing a restore, and it's direct to DB, and we're
		 * connected then send it to the DB.
		 */
1158
		if (RestoringToDB(AH))
B
Bruce Momjian 已提交
1159
			return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb);		/* Always 1, currently */
1160
		else
1161
		{
B
Bruce Momjian 已提交
1162
			res = fwrite((void *) ptr, size, nmemb, AH->OF);
1163
			if (res != nmemb)
1164 1165
				die_horribly(AH, modulename, "could not write to output file: %s\n",
							 strerror(errno));
1166 1167
			return res;
		}
1168
	}
B
Bruce Momjian 已提交
1169
}
1170 1171

/* Common exit code */
B
Bruce Momjian 已提交
1172
static void
1173
_write_msg(const char *modulename, const char *fmt, va_list ap)
1174
{
1175
	if (modulename)
1176
		fprintf(stderr, "%s: [%s] ", progname, _(modulename));
1177 1178
	else
		fprintf(stderr, "%s: ", progname);
1179
	vfprintf(stderr, _(fmt), ap);
1180 1181 1182
}

void
1183
write_msg(const char *modulename, const char *fmt,...)
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
{
	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);
1197

B
Bruce Momjian 已提交
1198 1199
	if (AH)
	{
1200 1201
		if (AH->public.verbose)
			write_msg(NULL, "*** aborted because of error\n");
B
Bruce Momjian 已提交
1202 1203
		if (AH->connection)
			PQfinish(AH->connection);
1204
	}
1205

B
Bruce Momjian 已提交
1206
	exit(1);
B
Bruce Momjian 已提交
1207 1208
}

1209
/* External use */
B
Bruce Momjian 已提交
1210
void
1211
exit_horribly(Archive *AH, const char *modulename, const char *fmt,...)
1212
{
B
Bruce Momjian 已提交
1213
	va_list		ap;
1214

B
Bruce Momjian 已提交
1215
	va_start(ap, fmt);
1216
	_die_horribly((ArchiveHandle *) AH, modulename, fmt, ap);
1217
	va_end(ap);
1218
}
B
Bruce Momjian 已提交
1219

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

B
Bruce Momjian 已提交
1226
	va_start(ap, fmt);
1227
	_die_horribly(AH, modulename, fmt, ap);
1228
	va_end(ap);
B
Bruce Momjian 已提交
1229 1230
}

1231 1232
/* on some error, we may decide to go on... */
void
B
Bruce Momjian 已提交
1233 1234
warn_or_die_horribly(ArchiveHandle *AH,
					 const char *modulename, const char *fmt,...)
1235
{
B
Bruce Momjian 已提交
1236
	va_list		ap;
1237

B
Bruce Momjian 已提交
1238 1239
	switch (AH->stage)
	{
1240 1241 1242 1243 1244 1245

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

		case STAGE_INITIALIZING:
B
Bruce Momjian 已提交
1246
			if (AH->stage != AH->lastErrorStage)
1247 1248 1249 1250
				write_msg(modulename, "Error while INITIALIZING:\n");
			break;

		case STAGE_PROCESSING:
B
Bruce Momjian 已提交
1251
			if (AH->stage != AH->lastErrorStage)
1252 1253 1254 1255
				write_msg(modulename, "Error while PROCESSING TOC:\n");
			break;

		case STAGE_FINALIZING:
B
Bruce Momjian 已提交
1256
			if (AH->stage != AH->lastErrorStage)
1257 1258 1259
				write_msg(modulename, "Error while FINALIZING:\n");
			break;
	}
B
Bruce Momjian 已提交
1260 1261
	if (AH->currentTE != NULL && AH->currentTE != AH->lastErrorTE)
	{
1262 1263
		write_msg(modulename, "Error from TOC entry %d; %u %u %s %s %s\n",
				  AH->currentTE->dumpId,
B
Bruce Momjian 已提交
1264 1265
			 AH->currentTE->catalogId.tableoid, AH->currentTE->catalogId.oid,
			  AH->currentTE->desc, AH->currentTE->tag, AH->currentTE->owner);
1266 1267 1268 1269
	}
	AH->lastErrorStage = AH->stage;
	AH->lastErrorTE = AH->currentTE;

1270
	va_start(ap, fmt);
1271
	if (AH->public.exit_on_error)
1272 1273 1274 1275 1276 1277 1278 1279
		_die_horribly(AH, modulename, fmt, ap);
	else
	{
		_write_msg(modulename, fmt, ap);
		AH->public.n_errors++;
	}
	va_end(ap);
}
1280

B
Bruce Momjian 已提交
1281 1282
static void
_moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
B
Bruce Momjian 已提交
1283
{
B
Bruce Momjian 已提交
1284 1285
	te->prev->next = te->next;
	te->next->prev = te->prev;
B
Bruce Momjian 已提交
1286

B
Bruce Momjian 已提交
1287 1288
	te->prev = pos;
	te->next = pos->next;
B
Bruce Momjian 已提交
1289

B
Bruce Momjian 已提交
1290 1291
	pos->next->prev = te;
	pos->next = te;
B
Bruce Momjian 已提交
1292 1293
}

1294 1295
#ifdef NOT_USED

B
Bruce Momjian 已提交
1296 1297
static void
_moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
B
Bruce Momjian 已提交
1298
{
B
Bruce Momjian 已提交
1299 1300
	te->prev->next = te->next;
	te->next->prev = te->prev;
B
Bruce Momjian 已提交
1301

B
Bruce Momjian 已提交
1302 1303 1304 1305
	te->prev = pos->prev;
	te->next = pos;
	pos->prev->next = te;
	pos->prev = te;
B
Bruce Momjian 已提交
1306
}
1307 1308
#endif

B
Bruce Momjian 已提交
1309
static TocEntry *
1310
getTocEntryByDumpId(ArchiveHandle *AH, DumpId id)
B
Bruce Momjian 已提交
1311
{
B
Bruce Momjian 已提交
1312 1313 1314 1315 1316
	TocEntry   *te;

	te = AH->toc->next;
	while (te != AH->toc)
	{
1317
		if (te->dumpId == id)
B
Bruce Momjian 已提交
1318 1319 1320 1321
			return te;
		te = te->next;
	}
	return NULL;
B
Bruce Momjian 已提交
1322 1323
}

1324
teReqs
1325
TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
B
Bruce Momjian 已提交
1326
{
1327
	TocEntry   *te = getTocEntryByDumpId(AH, id);
B
Bruce Momjian 已提交
1328

B
Bruce Momjian 已提交
1329 1330
	if (!te)
		return 0;
B
Bruce Momjian 已提交
1331

1332
	return _tocEntryRequired(te, ropt, true);
B
Bruce Momjian 已提交
1333 1334
}

1335
size_t
1336
WriteOffset(ArchiveHandle *AH, pgoff_t o, int wasSet)
1337
{
B
Bruce Momjian 已提交
1338
	int			off;
1339 1340 1341 1342

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

1343 1344
	/* Write out pgoff_t smallest byte first, prevents endian mismatch */
	for (off = 0; off < sizeof(pgoff_t); off++)
1345
	{
B
Bruce Momjian 已提交
1346
		(*AH->WriteBytePtr) (AH, o & 0xFF);
1347 1348
		o >>= 8;
	}
1349
	return sizeof(pgoff_t) + 1;
1350 1351 1352
}

int
B
Bruce Momjian 已提交
1353
ReadOffset(ArchiveHandle *AH, pgoff_t * o)
1354
{
B
Bruce Momjian 已提交
1355 1356 1357
	int			i;
	int			off;
	int			offsetFlg;
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368

	/* 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 已提交
1369
			return K_OFFSET_POS_NOT_SET;
1370
		else if (i == 0)
B
Bruce Momjian 已提交
1371
			return K_OFFSET_NO_DATA;
1372

1373 1374
		/* Cast to pgoff_t because it was written as an int. */
		*o = (pgoff_t) i;
1375 1376 1377 1378
		return K_OFFSET_POS_SET;
	}

	/*
B
Bruce Momjian 已提交
1379 1380
	 * Read the flag indicating the state of the data pointer. Check if valid
	 * and die if not.
1381
	 *
1382 1383
	 * This used to be handled by a negative or zero pointer, now we use an
	 * extra byte specifically for the state.
1384 1385 1386 1387 1388 1389 1390 1391 1392
	 */
	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 已提交
1393
			break;
1394 1395

		default:
1396
			die_horribly(AH, modulename, "unexpected data offset flag %d\n", offsetFlg);
1397 1398 1399 1400 1401 1402 1403
	}

	/*
	 * Read the bytes
	 */
	for (off = 0; off < AH->offSize; off++)
	{
1404 1405
		if (off < sizeof(pgoff_t))
			*o |= ((pgoff_t) ((*AH->ReadBytePtr) (AH))) << (off * 8);
1406 1407 1408
		else
		{
			if ((*AH->ReadBytePtr) (AH) != 0)
B
Bruce Momjian 已提交
1409
				die_horribly(AH, modulename, "file offset in dump file is too large\n");
1410 1411 1412 1413 1414 1415
		}
	}

	return offsetFlg;
}

P
Peter Eisentraut 已提交
1416
size_t
B
Bruce Momjian 已提交
1417
WriteInt(ArchiveHandle *AH, int i)
B
Bruce Momjian 已提交
1418
{
B
Bruce Momjian 已提交
1419 1420 1421
	int			b;

	/*
B
Bruce Momjian 已提交
1422 1423 1424 1425 1426
	 * 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 已提交
1427 1428 1429 1430 1431 1432
	 */

	/* SIGN byte */
	if (i < 0)
	{
		(*AH->WriteBytePtr) (AH, 1);
1433
		i = -i;
B
Bruce Momjian 已提交
1434 1435 1436 1437 1438 1439 1440
	}
	else
		(*AH->WriteBytePtr) (AH, 0);

	for (b = 0; b < AH->intSize; b++)
	{
		(*AH->WriteBytePtr) (AH, i & 0xFF);
1441
		i >>= 8;
B
Bruce Momjian 已提交
1442 1443 1444
	}

	return AH->intSize + 1;
B
Bruce Momjian 已提交
1445 1446
}

B
Bruce Momjian 已提交
1447 1448
int
ReadInt(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1449
{
B
Bruce Momjian 已提交
1450 1451 1452 1453 1454
	int			res = 0;
	int			bv,
				b;
	int			sign = 0;		/* Default positive */
	int			bitShift = 0;
B
Bruce Momjian 已提交
1455

B
Bruce Momjian 已提交
1456
	if (AH->version > K_VERS_1_0)
1457
		/* Read a sign byte */
B
Bruce Momjian 已提交
1458
		sign = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
1459

B
Bruce Momjian 已提交
1460 1461 1462
	for (b = 0; b < AH->intSize; b++)
	{
		bv = (*AH->ReadBytePtr) (AH) & 0xFF;
1463 1464 1465
		if (bv != 0)
			res = res + (bv << bitShift);
		bitShift += 8;
B
Bruce Momjian 已提交
1466
	}
B
Bruce Momjian 已提交
1467

B
Bruce Momjian 已提交
1468 1469
	if (sign)
		res = -res;
B
Bruce Momjian 已提交
1470

B
Bruce Momjian 已提交
1471
	return res;
B
Bruce Momjian 已提交
1472 1473
}

P
Peter Eisentraut 已提交
1474
size_t
1475
WriteStr(ArchiveHandle *AH, const char *c)
B
Bruce Momjian 已提交
1476
{
P
Peter Eisentraut 已提交
1477
	size_t		res;
1478 1479 1480 1481

	if (c)
	{
		res = WriteInt(AH, strlen(c));
B
Bruce Momjian 已提交
1482
		res += (*AH->WriteBufPtr) (AH, c, strlen(c));
1483 1484 1485 1486
	}
	else
		res = WriteInt(AH, -1);

B
Bruce Momjian 已提交
1487
	return res;
B
Bruce Momjian 已提交
1488 1489
}

B
Bruce Momjian 已提交
1490 1491
char *
ReadStr(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1492
{
B
Bruce Momjian 已提交
1493 1494
	char	   *buf;
	int			l;
B
Bruce Momjian 已提交
1495

B
Bruce Momjian 已提交
1496
	l = ReadInt(AH);
1497
	if (l < 0)
1498 1499 1500
		buf = NULL;
	else
	{
B
Bruce Momjian 已提交
1501
		buf = (char *) malloc(l + 1);
1502
		if (!buf)
1503
			die_horribly(AH, modulename, "out of memory\n");
1504

1505 1506 1507
		if ((*AH->ReadBufPtr) (AH, (void *) buf, l) != l)
			die_horribly(AH, modulename, "unexpected end of file\n");

1508 1509
		buf[l] = '\0';
	}
B
Bruce Momjian 已提交
1510

B
Bruce Momjian 已提交
1511
	return buf;
B
Bruce Momjian 已提交
1512 1513
}

T
Tom Lane 已提交
1514
static int
B
Bruce Momjian 已提交
1515
_discoverArchiveFormat(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1516
{
B
Bruce Momjian 已提交
1517 1518
	FILE	   *fh;
	char		sig[6];			/* More than enough */
P
Peter Eisentraut 已提交
1519
	size_t		cnt;
B
Bruce Momjian 已提交
1520
	int			wantClose = 0;
B
Bruce Momjian 已提交
1521

1522
#if 0
1523
	write_msg(modulename, "attempting to ascertain archive format\n");
1524
#endif
1525 1526 1527 1528 1529 1530 1531 1532

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

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

B
Bruce Momjian 已提交
1534 1535
	if (AH->fSpec)
	{
1536 1537
		wantClose = 1;
		fh = fopen(AH->fSpec, PG_BINARY_R);
1538 1539 1540
		if (!fh)
			die_horribly(AH, modulename, "could not open input file \"%s\": %s\n",
						 AH->fSpec, strerror(errno));
B
Bruce Momjian 已提交
1541 1542
	}
	else
1543
	{
1544
		fh = stdin;
1545 1546 1547 1548
		if (!fh)
			die_horribly(AH, modulename, "could not open input file: %s\n",
						 strerror(errno));
	}
B
Bruce Momjian 已提交
1549

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

B
Bruce Momjian 已提交
1552
	if (cnt != 5)
1553 1554 1555 1556
	{
		if (ferror(fh))
			die_horribly(AH, modulename, "could not read input file: %s\n", strerror(errno));
		else
P
Peter Eisentraut 已提交
1557 1558
			die_horribly(AH, modulename, "input file is too short (read %lu, expected 5)\n",
						 (unsigned long) cnt);
1559
	}
B
Bruce Momjian 已提交
1560

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

B
Bruce Momjian 已提交
1565
	if (strncmp(sig, "PGDMP", 5) == 0)
1566 1567 1568 1569 1570 1571 1572 1573 1574
	{
		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 已提交
1575 1576
		if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))		/* Version > 1.0 */
		{
1577 1578 1579 1580 1581 1582
			AH->vrev = fgetc(fh);
			AH->lookahead[AH->lookaheadLen++] = AH->vrev;
		}
		else
			AH->vrev = 0;

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

1586 1587 1588
		AH->intSize = fgetc(fh);
		AH->lookahead[AH->lookaheadLen++] = AH->intSize;

1589 1590 1591 1592 1593 1594 1595 1596
		if (AH->version >= K_VERS_1_7)
		{
			AH->offSize = fgetc(fh);
			AH->lookahead[AH->lookaheadLen++] = AH->offSize;
		}
		else
			AH->offSize = AH->intSize;

1597 1598
		AH->format = fgetc(fh);
		AH->lookahead[AH->lookaheadLen++] = AH->format;
B
Bruce Momjian 已提交
1599 1600 1601
	}
	else
	{
1602
		/*
B
Bruce Momjian 已提交
1603 1604
		 * *Maybe* we have a tar archive format file... So, read first 512
		 * byte header...
1605 1606 1607
		 */
		cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh);
		AH->lookaheadLen += cnt;
B
Bruce Momjian 已提交
1608

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

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

1615 1616
		AH->format = archTar;
	}
B
Bruce Momjian 已提交
1617

B
Bruce Momjian 已提交
1618
	/* If we can't seek, then mark the header as read */
P
Peter Eisentraut 已提交
1619
	if (fseeko(fh, 0, SEEK_SET) != 0)
1620 1621
	{
		/*
B
Bruce Momjian 已提交
1622 1623
		 * NOTE: Formats that use the lookahead buffer can unset this in their
		 * Init routine.
1624 1625 1626 1627
		 */
		AH->readHeader = 1;
	}
	else
B
Bruce Momjian 已提交
1628
		AH->lookaheadLen = 0;	/* Don't bother since we've reset the file */
1629

1630
#if 0
P
Peter Eisentraut 已提交
1631 1632
	write_msg(modulename, "read %lu bytes into lookahead buffer\n",
			  (unsigned long) AH->lookaheadLen);
1633
#endif
B
Bruce Momjian 已提交
1634

B
Bruce Momjian 已提交
1635 1636
	/* Close the file */
	if (wantClose)
1637
		if (fclose(fh) != 0)
1638
			die_horribly(AH, modulename, "could not close input file: %s\n",
1639
						 strerror(errno));
B
Bruce Momjian 已提交
1640

B
Bruce Momjian 已提交
1641
	return AH->format;
B
Bruce Momjian 已提交
1642 1643 1644 1645 1646 1647
}


/*
 * Allocate an archive handle
 */
B
Bruce Momjian 已提交
1648 1649 1650
static ArchiveHandle *
_allocAH(const char *FileSpec, const ArchiveFormat fmt,
		 const int compression, ArchiveMode mode)
1651
{
B
Bruce Momjian 已提交
1652
	ArchiveHandle *AH;
B
Bruce Momjian 已提交
1653

1654
#if 0
1655
	write_msg(modulename, "allocating AH for %s, format %d\n", FileSpec, fmt);
1656
#endif
1657

B
Bruce Momjian 已提交
1658 1659
	AH = (ArchiveHandle *) calloc(1, sizeof(ArchiveHandle));
	if (!AH)
1660
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
1661

1662 1663
	/* AH->debugLevel = 100; */

B
Bruce Momjian 已提交
1664 1665
	AH->vmaj = K_VERS_MAJOR;
	AH->vmin = K_VERS_MINOR;
1666
	AH->vrev = K_VERS_REV;
B
Bruce Momjian 已提交
1667

1668
	/* initialize for backwards compatible string processing */
1669
	AH->public.encoding = 0;	/* PG_SQL_ASCII */
1670 1671 1672 1673 1674 1675
	AH->public.std_strings = false;

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

1676 1677
	AH->createDate = time(NULL);

B
Bruce Momjian 已提交
1678
	AH->intSize = sizeof(int);
1679
	AH->offSize = sizeof(pgoff_t);
B
Bruce Momjian 已提交
1680 1681
	if (FileSpec)
	{
1682
		AH->fSpec = strdup(FileSpec);
B
Bruce Momjian 已提交
1683

1684 1685 1686
		/*
		 * Not used; maybe later....
		 *
1687 1688
		 * AH->workDir = strdup(FileSpec); for(i=strlen(FileSpec) ; i > 0 ;
		 * i--) if (AH->workDir[i-1] == '/')
1689
		 */
B
Bruce Momjian 已提交
1690 1691
	}
	else
1692
		AH->fSpec = NULL;
B
Bruce Momjian 已提交
1693

B
Bruce Momjian 已提交
1694 1695
	AH->currUser = strdup("");	/* So it's valid, but we can free() it later
								 * if necessary */
B
Bruce Momjian 已提交
1696
	AH->currSchema = strdup("");	/* ditto */
1697
	AH->currWithOids = -1;		/* force SET */
B
Bruce Momjian 已提交
1698

B
Bruce Momjian 已提交
1699 1700
	AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry));
	if (!AH->toc)
1701
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
1702

B
Bruce Momjian 已提交
1703 1704 1705 1706 1707
	AH->toc->next = AH->toc;
	AH->toc->prev = AH->toc;

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

1709 1710
	AH->pgCopyBuf = createPQExpBuffer();
	AH->sqlBuf = createPQExpBuffer();
B
Bruce Momjian 已提交
1711

B
Bruce Momjian 已提交
1712 1713 1714
	/* Open stdout with no compression for AH output handle */
	AH->gzOut = 0;
	AH->OF = stdout;
B
Bruce Momjian 已提交
1715

1716 1717
	/*
	 * On Windows, we need to use binary mode to read/write non-text archive
B
Bruce Momjian 已提交
1718 1719
	 * formats.  Force stdin/stdout into binary mode if that is what we are
	 * using.
1720 1721
	 */
#ifdef WIN32
1722 1723
	if (fmt != archNull &&
		(AH->fSpec == NULL || strcmp(AH->fSpec, "") == 0))
1724 1725 1726 1727 1728 1729 1730 1731
	{
		if (mode == archModeWrite)
			setmode(fileno(stdout), O_BINARY);
		else
			setmode(fileno(stdin), O_BINARY);
	}
#endif

1732
#if 0
1733
	write_msg(modulename, "archive format is %d\n", fmt);
1734
#endif
1735

B
Bruce Momjian 已提交
1736
	if (fmt == archUnknown)
1737 1738 1739
		AH->format = _discoverArchiveFormat(AH);
	else
		AH->format = fmt;
B
Bruce Momjian 已提交
1740

B
Bruce Momjian 已提交
1741 1742
	switch (AH->format)
	{
1743 1744 1745
		case archCustom:
			InitArchiveFmt_Custom(AH);
			break;
B
Bruce Momjian 已提交
1746

1747 1748 1749
		case archFiles:
			InitArchiveFmt_Files(AH);
			break;
B
Bruce Momjian 已提交
1750

1751 1752 1753
		case archNull:
			InitArchiveFmt_Null(AH);
			break;
B
Bruce Momjian 已提交
1754

1755 1756 1757 1758 1759
		case archTar:
			InitArchiveFmt_Tar(AH);
			break;

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

B
Bruce Momjian 已提交
1763
	return AH;
B
Bruce Momjian 已提交
1764 1765 1766
}


B
Bruce Momjian 已提交
1767 1768
void
WriteDataChunks(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1769
{
B
Bruce Momjian 已提交
1770 1771 1772
	TocEntry   *te = AH->toc->next;
	StartDataPtr startPtr;
	EndDataPtr	endPtr;
B
Bruce Momjian 已提交
1773

B
Bruce Momjian 已提交
1774 1775 1776
	while (te != AH->toc)
	{
		if (te->dataDumper != NULL)
1777
		{
B
Bruce Momjian 已提交
1778 1779
			AH->currToc = te;
			/* printf("Writing data for %d (%x)\n", te->id, te); */
1780

B
Bruce Momjian 已提交
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790
			if (strcmp(te->desc, "BLOBS") == 0)
			{
				startPtr = AH->StartBlobsPtr;
				endPtr = AH->EndBlobsPtr;
			}
			else
			{
				startPtr = AH->StartDataPtr;
				endPtr = AH->EndDataPtr;
			}
B
Bruce Momjian 已提交
1791

B
Bruce Momjian 已提交
1792 1793
			if (startPtr != NULL)
				(*startPtr) (AH, te);
B
Bruce Momjian 已提交
1794

B
Bruce Momjian 已提交
1795
			/*
B
Bruce Momjian 已提交
1796
			 * printf("Dumper arg for %d is %x\n", te->id, te->dataDumperArg);
B
Bruce Momjian 已提交
1797 1798 1799 1800 1801 1802
			 */

			/*
			 * The user-provided DataDumper routine needs to call
			 * AH->WriteData
			 */
1803
			(*te->dataDumper) ((Archive *) AH, te->dataDumperArg);
B
Bruce Momjian 已提交
1804 1805 1806 1807 1808

			if (endPtr != NULL)
				(*endPtr) (AH, te);
			AH->currToc = NULL;
		}
1809
		te = te->next;
B
Bruce Momjian 已提交
1810
	}
B
Bruce Momjian 已提交
1811 1812
}

B
Bruce Momjian 已提交
1813 1814
void
WriteToc(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1815
{
1816 1817
	TocEntry   *te;
	char		workbuf[32];
1818
	int			i;
B
Bruce Momjian 已提交
1819 1820 1821 1822

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

	WriteInt(AH, AH->tocCount);
1823 1824

	for (te = AH->toc->next; te != AH->toc; te = te->next)
B
Bruce Momjian 已提交
1825
	{
1826
		WriteInt(AH, te->dumpId);
B
Bruce Momjian 已提交
1827
		WriteInt(AH, te->dataDumper ? 1 : 0);
1828 1829 1830 1831 1832 1833

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

1835
		WriteStr(AH, te->tag);
B
Bruce Momjian 已提交
1836 1837 1838 1839
		WriteStr(AH, te->desc);
		WriteStr(AH, te->defn);
		WriteStr(AH, te->dropStmt);
		WriteStr(AH, te->copyStmt);
1840
		WriteStr(AH, te->namespace);
1841
		WriteStr(AH, te->tablespace);
B
Bruce Momjian 已提交
1842
		WriteStr(AH, te->owner);
1843
		WriteStr(AH, te->withOids ? "true" : "false");
1844 1845

		/* Dump list of dependencies */
1846
		for (i = 0; i < te->nDeps; i++)
1847
		{
1848 1849
			sprintf(workbuf, "%d", te->dependencies[i]);
			WriteStr(AH, workbuf);
1850
		}
1851
		WriteStr(AH, NULL);		/* Terminate List */
1852

B
Bruce Momjian 已提交
1853 1854 1855
		if (AH->WriteExtraTocPtr)
			(*AH->WriteExtraTocPtr) (AH, te);
	}
B
Bruce Momjian 已提交
1856 1857
}

B
Bruce Momjian 已提交
1858 1859
void
ReadToc(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1860
{
B
Bruce Momjian 已提交
1861
	int			i;
1862 1863
	char	   *tmp;
	DumpId	   *deps;
1864 1865
	int			depIdx;
	int			depSize;
B
Bruce Momjian 已提交
1866

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

B
Bruce Momjian 已提交
1869
	AH->tocCount = ReadInt(AH);
1870
	AH->maxDumpId = 0;
B
Bruce Momjian 已提交
1871

B
Bruce Momjian 已提交
1872 1873 1874
	for (i = 0; i < AH->tocCount; i++)
	{
		te = (TocEntry *) calloc(1, sizeof(TocEntry));
1875 1876 1877 1878
		te->dumpId = ReadInt(AH);

		if (te->dumpId > AH->maxDumpId)
			AH->maxDumpId = te->dumpId;
1879 1880

		/* Sanity check */
1881 1882
		if (te->dumpId <= 0)
			die_horribly(AH, modulename,
B
Bruce Momjian 已提交
1883
					   "entry ID %d out of range -- perhaps a corrupt TOC\n",
1884
						 te->dumpId);
1885 1886

		te->hadDumper = ReadInt(AH);
1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898

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

1900
		te->tag = ReadStr(AH);
1901 1902 1903 1904 1905 1906 1907
		te->desc = ReadStr(AH);
		te->defn = ReadStr(AH);
		te->dropStmt = ReadStr(AH);

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

1908 1909 1910
		if (AH->version >= K_VERS_1_6)
			te->namespace = ReadStr(AH);

1911 1912 1913
		if (AH->version >= K_VERS_1_10)
			te->tablespace = ReadStr(AH);

1914
		te->owner = ReadStr(AH);
1915 1916 1917 1918 1919 1920 1921 1922 1923
		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 已提交
1924

1925 1926 1927 1928
		/* Read TOC entry dependencies */
		if (AH->version >= K_VERS_1_5)
		{
			depSize = 100;
1929
			deps = (DumpId *) malloc(sizeof(DumpId) * depSize);
1930
			depIdx = 0;
1931
			for (;;)
1932
			{
1933 1934 1935
				tmp = ReadStr(AH);
				if (!tmp)
					break;		/* end of list */
1936
				if (depIdx >= depSize)
1937 1938
				{
					depSize *= 2;
1939
					deps = (DumpId *) realloc(deps, sizeof(DumpId) * depSize);
1940
				}
1941 1942 1943 1944
				sscanf(tmp, "%d", &deps[depIdx]);
				free(tmp);
				depIdx++;
			}
1945

1946 1947 1948 1949 1950 1951
			if (depIdx > 0)		/* We have a non-null entry */
			{
				deps = (DumpId *) realloc(deps, sizeof(DumpId) * depIdx);
				te->dependencies = deps;
				te->nDeps = depIdx;
			}
1952
			else
1953 1954
			{
				free(deps);
1955 1956
				te->dependencies = NULL;
				te->nDeps = 0;
1957
			}
1958
		}
1959
		else
1960 1961 1962 1963
		{
			te->dependencies = NULL;
			te->nDeps = 0;
		}
1964

B
Bruce Momjian 已提交
1965 1966
		if (AH->ReadExtraTocPtr)
			(*AH->ReadExtraTocPtr) (AH, te);
1967

1968 1969
		ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n",
			  i, te->dumpId, te->desc, te->tag);
1970

1971
		/* link completed entry into TOC circular list */
1972 1973 1974 1975
		te->prev = AH->toc->prev;
		AH->toc->prev->next = te;
		AH->toc->prev = te;
		te->next = AH->toc;
1976 1977 1978 1979 1980 1981

		/* special processing immediately upon read for some items */
		if (strcmp(te->desc, "ENCODING") == 0)
			processEncodingEntry(AH, te);
		else if (strcmp(te->desc, "STDSTRINGS") == 0)
			processStdStringsEntry(AH, te);
B
Bruce Momjian 已提交
1982
	}
B
Bruce Momjian 已提交
1983 1984
}

1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028
static void
processEncodingEntry(ArchiveHandle *AH, TocEntry *te)
{
	/* te->defn should have the form SET client_encoding = 'foo'; */
	char	   *defn = strdup(te->defn);
	char	   *ptr1;
	char	   *ptr2 = NULL;
	int			encoding;

	ptr1 = strchr(defn, '\'');
	if (ptr1)
		ptr2 = strchr(++ptr1, '\'');
	if (ptr2)
	{
		*ptr2 = '\0';
		encoding = pg_char_to_encoding(ptr1);
		if (encoding < 0)
			die_horribly(AH, modulename, "unrecognized encoding \"%s\"\n",
						 ptr1);
		AH->public.encoding = encoding;
	}
	else
		die_horribly(AH, modulename, "invalid ENCODING item: %s\n",
					 te->defn);

	free(defn);
}

static void
processStdStringsEntry(ArchiveHandle *AH, TocEntry *te)
{
	/* te->defn should have the form SET standard_conforming_strings = 'x'; */
	char	   *ptr1;

	ptr1 = strchr(te->defn, '\'');
	if (ptr1 && strncmp(ptr1, "'on'", 4) == 0)
		AH->public.std_strings = true;
	else if (ptr1 && strncmp(ptr1, "'off'", 5) == 0)
		AH->public.std_strings = false;
	else
		die_horribly(AH, modulename, "invalid STDSTRINGS item: %s\n",
					 te->defn);
}

2029
static teReqs
2030
_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
B
Bruce Momjian 已提交
2031
{
2032
	teReqs		res = REQ_ALL;
B
Bruce Momjian 已提交
2033

2034 2035 2036
	/* ENCODING and STDSTRINGS items are dumped specially, so always reject */
	if (strcmp(te->desc, "ENCODING") == 0 ||
		strcmp(te->desc, "STDSTRINGS") == 0)
2037
		return 0;
2038

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

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

2046 2047 2048 2049 2050 2051 2052 2053 2054 2055
	/* Check options for selective dump/restore */
	if (ropt->schemaNames)
	{
		/* If no namespace is specified, it means all. */
		if (!te->namespace)
			return 0;
		if (strcmp(ropt->schemaNames, te->namespace) != 0)
			return 0;
	}

B
Bruce Momjian 已提交
2056 2057
	if (ropt->selTypes)
	{
2058 2059
		if (strcmp(te->desc, "TABLE") == 0 ||
			strcmp(te->desc, "TABLE DATA") == 0)
2060 2061 2062
		{
			if (!ropt->selTable)
				return 0;
2063
			if (ropt->tableNames && strcmp(ropt->tableNames, te->tag) != 0)
2064
				return 0;
B
Bruce Momjian 已提交
2065 2066 2067
		}
		else if (strcmp(te->desc, "INDEX") == 0)
		{
2068 2069
			if (!ropt->selIndex)
				return 0;
2070
			if (ropt->indexNames && strcmp(ropt->indexNames, te->tag) != 0)
2071
				return 0;
B
Bruce Momjian 已提交
2072 2073 2074
		}
		else if (strcmp(te->desc, "FUNCTION") == 0)
		{
2075 2076
			if (!ropt->selFunction)
				return 0;
2077
			if (ropt->functionNames && strcmp(ropt->functionNames, te->tag) != 0)
2078
				return 0;
B
Bruce Momjian 已提交
2079 2080 2081
		}
		else if (strcmp(te->desc, "TRIGGER") == 0)
		{
2082 2083
			if (!ropt->selTrigger)
				return 0;
2084
			if (ropt->triggerNames && strcmp(ropt->triggerNames, te->tag) != 0)
2085 2086
				return 0;
		}
B
Bruce Momjian 已提交
2087 2088
		else
			return 0;
B
Bruce Momjian 已提交
2089 2090
	}

2091
	/*
B
Bruce Momjian 已提交
2092
	 * Check if we had a dataDumper. Indicates if the entry is schema or data
2093 2094 2095 2096
	 */
	if (!te->hadDumper)
	{
		/*
B
Bruce Momjian 已提交
2097
		 * Special Case: If 'SEQUENCE SET' then it is considered a data entry
2098 2099 2100 2101
		 */
		if (strcmp(te->desc, "SEQUENCE SET") == 0)
			res = res & REQ_DATA;
		else
2102 2103
			res = res & ~REQ_DATA;
	}
2104

2105
	/*
B
Bruce Momjian 已提交
2106 2107
	 * Special case: <Init> type with <Max OID> tag; this is obsolete and we
	 * always ignore it.
2108
	 */
2109
	if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
2110
		return 0;
2111

B
Bruce Momjian 已提交
2112 2113
	/* Mask it if we only want schema */
	if (ropt->schemaOnly)
2114
		res = res & REQ_SCHEMA;
B
Bruce Momjian 已提交
2115

B
Bruce Momjian 已提交
2116
	/* Mask it we only want data */
2117
	if (ropt->dataOnly)
2118
		res = res & REQ_DATA;
B
Bruce Momjian 已提交
2119

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

2124 2125
	/* Finally, if there's a per-ID filter, limit based on that as well */
	if (ropt->idWanted && !ropt->idWanted[te->dumpId - 1])
2126
		return 0;
B
Bruce Momjian 已提交
2127

B
Bruce Momjian 已提交
2128
	return res;
B
Bruce Momjian 已提交
2129 2130
}

2131 2132 2133 2134 2135 2136 2137
/*
 * 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)
{
2138 2139 2140
	/* Select the correct character set encoding */
	ahprintf(AH, "SET client_encoding = '%s';\n",
			 pg_encoding_to_char(AH->public.encoding));
2141

2142 2143 2144
	/* Select the correct string literal syntax */
	ahprintf(AH, "SET standard_conforming_strings = %s;\n",
			 AH->public.std_strings ? "on" : "off");
2145 2146 2147 2148

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

2149 2150
	/* Avoid annoying notices etc */
	ahprintf(AH, "SET client_min_messages = warning;\n");
2151 2152
	if (!AH->public.std_strings)
		ahprintf(AH, "SET escape_string_warning = off;\n");
2153

2154 2155 2156
	ahprintf(AH, "\n");
}

2157 2158
/*
 * Issue a SET SESSION AUTHORIZATION command.  Caller is responsible
2159 2160
 * for updating state if appropriate.  If user is NULL or an empty string,
 * the specification DEFAULT will be used.
2161 2162
 */
static void
2163
_doSetSessionAuth(ArchiveHandle *AH, const char *user)
2164
{
2165
	PQExpBuffer cmd = createPQExpBuffer();
B
Bruce Momjian 已提交
2166

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

2169 2170 2171 2172
	/*
	 * SQL requires a string literal here.	Might as well be correct.
	 */
	if (user && *user)
2173
		appendStringLiteralAHX(cmd, user, AH);
2174 2175 2176 2177
	else
		appendPQExpBuffer(cmd, "DEFAULT");
	appendPQExpBuffer(cmd, ";");

2178 2179 2180 2181
	if (RestoringToDB(AH))
	{
		PGresult   *res;

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2185
			/* NOT warn_or_die_horribly... use -O instead to skip this. */
2186
			die_horribly(AH, modulename, "could not set session user to \"%s\": %s",
2187
						 user, PQerrorMessage(AH->connection));
2188 2189 2190 2191

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

	destroyPQExpBuffer(cmd);
2195 2196
}

2197

2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
/*
 * 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 已提交
2208
					  "true" : "false");
2209 2210 2211 2212 2213 2214 2215 2216

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

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
2217
			warn_or_die_horribly(AH, modulename,
2218 2219
								 "could not set default_with_oids: %s",
								 PQerrorMessage(AH->connection));
2220 2221 2222 2223 2224 2225 2226 2227 2228 2229

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

	destroyPQExpBuffer(cmd);
}


2230
/*
2231
 * Issue the commands to connect to the specified database.
2232 2233
 *
 * If we're currently restoring right into a database, this will
B
Bruce Momjian 已提交
2234
 * actually establish a connection. Otherwise it puts a \connect into
2235
 * the script output.
2236 2237
 *
 * NULL dbname implies reconnecting to the current DB (pretty useless).
2238
 */
B
Bruce Momjian 已提交
2239
static void
2240
_reconnectToDB(ArchiveHandle *AH, const char *dbname)
2241
{
2242
	if (RestoringToDB(AH))
2243
		ReconnectToServer(AH, dbname, NULL);
2244
	else
2245 2246 2247
	{
		PQExpBuffer qry = createPQExpBuffer();

2248
		appendPQExpBuffer(qry, "\\connect %s\n\n",
2249
						  dbname ? fmtId(dbname) : "-");
2250
		ahprintf(AH, "%s", qry->data);
2251 2252
		destroyPQExpBuffer(qry);
	}
2253

2254
	/*
B
Bruce Momjian 已提交
2255 2256
	 * NOTE: currUser keeps track of what the imaginary session user in our
	 * script is.  It's now effectively reset to the original userID.
2257
	 */
2258 2259 2260
	if (AH->currUser)
		free(AH->currUser);

2261
	AH->currUser = strdup("");
2262 2263 2264 2265 2266

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

2269 2270
	/* re-establish fixed state */
	_doSetFixedOutputState(AH);
2271 2272
}

2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289
/*
 * 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 已提交
2290 2291
	 * NOTE: currUser keeps track of what the imaginary session user in our
	 * script is
2292 2293 2294 2295 2296 2297
	 */
	if (AH->currUser)
		free(AH->currUser);

	AH->currUser = strdup(user);
}
2298 2299

/*
B
Bruce Momjian 已提交
2300
 * Become the owner of the the given TOC entry object.	If
2301 2302
 * changes in ownership are not allowed, this doesn't do anything.
 */
B
Bruce Momjian 已提交
2303
static void
2304
_becomeOwner(ArchiveHandle *AH, TocEntry *te)
2305
{
2306
	if (AH->ropt && (AH->ropt->noOwner || !AH->ropt->use_setsessauth))
2307 2308
		return;

2309
	_becomeUser(AH, te->owner);
2310 2311
}

2312

2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326
/*
 * 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;
	}
}


2327 2328 2329 2330 2331 2332 2333
/*
 * Issue the commands to select the specified schema as the current schema
 * in the target database.
 */
static void
_selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
{
2334 2335
	PQExpBuffer qry;

2336
	if (!schemaName || *schemaName == '\0' ||
2337
		(AH->currSchema && strcmp(AH->currSchema, schemaName) == 0))
2338 2339
		return;					/* no need to do anything */

2340 2341 2342
	qry = createPQExpBuffer();

	appendPQExpBuffer(qry, "SET search_path = %s",
2343
					  fmtId(schemaName));
2344 2345 2346
	if (strcmp(schemaName, "pg_catalog") != 0)
		appendPQExpBuffer(qry, ", pg_catalog");

2347 2348 2349 2350 2351 2352 2353
	if (RestoringToDB(AH))
	{
		PGresult   *res;

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
2354
			warn_or_die_horribly(AH, modulename,
B
Bruce Momjian 已提交
2355 2356
								 "could not set search_path to \"%s\": %s",
								 schemaName, PQerrorMessage(AH->connection));
2357 2358 2359 2360

		PQclear(res);
	}
	else
2361
		ahprintf(AH, "%s;\n\n", qry->data);
2362 2363 2364 2365

	if (AH->currSchema)
		free(AH->currSchema);
	AH->currSchema = strdup(schemaName);
2366 2367

	destroyPQExpBuffer(qry);
2368 2369
}

2370 2371 2372 2373 2374 2375 2376 2377
/*
 * 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 已提交
2378 2379
	const char *want,
			   *have;
2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410

	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 已提交
2411
			warn_or_die_horribly(AH, modulename,
2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425
								 "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);
}
2426

2427 2428 2429 2430 2431 2432 2433 2434
/*
 * 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.
2435
 */
2436
static void
2437
_getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
2438
{
2439 2440 2441
	const char *type = te->desc;

	/* Use ALTER TABLE for views and sequences */
2442
	if (strcmp(type, "VIEW") == 0 || strcmp(type, "SEQUENCE") == 0)
2443 2444 2445 2446 2447 2448
		type = "TABLE";

	/* objects named by a schema and name */
	if (strcmp(type, "CONVERSION") == 0 ||
		strcmp(type, "DOMAIN") == 0 ||
		strcmp(type, "TABLE") == 0 ||
2449 2450 2451
		strcmp(type, "TYPE") == 0 ||
		strcmp(type, "TEXT SEARCH DICTIONARY") == 0 ||
		strcmp(type, "TEXT SEARCH CONFIGURATION") == 0)
2452
	{
2453
		appendPQExpBuffer(buf, "%s ", type);
B
Bruce Momjian 已提交
2454
		if (te->namespace && te->namespace[0])	/* is null pre-7.3 */
2455
			appendPQExpBuffer(buf, "%s.", fmtId(te->namespace));
B
Bruce Momjian 已提交
2456

2457
		/*
B
Bruce Momjian 已提交
2458 2459 2460
		 * 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.
2461 2462 2463
		 */
		if (AH->version < K_VERS_1_7 &&
			te->tag[0] == '"' &&
B
Bruce Momjian 已提交
2464
			te->tag[strlen(te->tag) - 1] == '"' &&
2465 2466 2467 2468
			strcmp(type, "INDEX") == 0)
			appendPQExpBuffer(buf, "%s", te->tag);
		else
			appendPQExpBuffer(buf, "%s", fmtId(te->tag));
2469 2470
		return;
	}
2471

2472 2473
	/* objects named by just a name */
	if (strcmp(type, "DATABASE") == 0 ||
2474
		strcmp(type, "PROCEDURAL LANGUAGE") == 0 ||
2475 2476 2477 2478 2479
		strcmp(type, "SCHEMA") == 0)
	{
		appendPQExpBuffer(buf, "%s %s", type, fmtId(te->tag));
		return;
	}
2480

B
Bruce Momjian 已提交
2481
	/*
B
Bruce Momjian 已提交
2482 2483
	 * These object types require additional decoration.  Fortunately, the
	 * information needed is exactly what's in the DROP command.
B
Bruce Momjian 已提交
2484
	 */
2485 2486 2487
	if (strcmp(type, "AGGREGATE") == 0 ||
		strcmp(type, "FUNCTION") == 0 ||
		strcmp(type, "OPERATOR") == 0 ||
2488 2489
		strcmp(type, "OPERATOR CLASS") == 0 ||
		strcmp(type, "OPERATOR FAMILY") == 0)
B
Bruce Momjian 已提交
2490
	{
2491 2492 2493
		/* Chop "DROP " off the front and make a modifiable copy */
		char	   *first = strdup(te->dropStmt + 5);
		char	   *last;
2494

2495 2496
		/* point to last character in string */
		last = first + strlen(first) - 1;
2497

2498 2499 2500 2501
		/* Strip off any ';' or '\n' at the end */
		while (last >= first && (*last == '\n' || *last == ';'))
			last--;
		*(last + 1) = '\0';
B
Bruce Momjian 已提交
2502

2503
		appendPQExpBufferStr(buf, first);
B
Bruce Momjian 已提交
2504 2505

		free(first);
2506
		return;
2507 2508
	}

2509 2510
	write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n",
			  type);
2511 2512 2513
}

static void
2514
_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass)
B
Bruce Momjian 已提交
2515
{
2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529
	/* 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 已提交
2530
	 * unless we are using --clean mode, in which case it's been deleted and
2531
	 * we'd better recreate it.  Likewise for its comment, if any.
2532
	 */
2533 2534 2535 2536 2537 2538 2539 2540 2541
	if (!ropt->dropSchema)
	{
		if (strcmp(te->desc, "SCHEMA") == 0 &&
			strcmp(te->tag, "public") == 0)
			return;
		if (strcmp(te->desc, "COMMENT") == 0 &&
			strcmp(te->tag, "SCHEMA public") == 0)
			return;
	}
2542

2543
	/* Select owner, schema, and tablespace as necessary */
2544 2545
	_becomeOwner(AH, te);
	_selectOutputSchema(AH, te->namespace);
2546
	_selectTablespace(AH, te->tablespace);
2547 2548 2549 2550 2551 2552

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

	/* Emit header comment for item */
2553
	if (!AH->noTocComments)
2554
	{
2555 2556 2557 2558 2559 2560 2561 2562 2563
		const char *pfx;

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

		ahprintf(AH, "--\n");
		if (AH->public.verbose)
2564
		{
2565 2566 2567 2568 2569
			ahprintf(AH, "-- TOC entry %d (class %u OID %u)\n",
					 te->dumpId, te->catalogId.tableoid, te->catalogId.oid);
			if (te->nDeps > 0)
			{
				int			i;
2570

2571 2572 2573 2574 2575
				ahprintf(AH, "-- Dependencies:");
				for (i = 0; i < te->nDeps; i++)
					ahprintf(AH, " %d", te->dependencies[i]);
				ahprintf(AH, "\n");
			}
2576
		}
2577
		ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s",
2578 2579
				 pfx, te->tag, te->desc,
				 te->namespace ? te->namespace : "-",
2580
				 ropt->noOwner ? "-" : te->owner);
B
Bruce Momjian 已提交
2581
		if (te->tablespace)
2582 2583 2584
			ahprintf(AH, "; Tablespace: %s", te->tablespace);
		ahprintf(AH, "\n");

B
Bruce Momjian 已提交
2585
		if (AH->PrintExtraTocPtr !=NULL)
2586 2587
			(*AH->PrintExtraTocPtr) (AH, te);
		ahprintf(AH, "--\n\n");
2588
	}
B
Bruce Momjian 已提交
2589

2590 2591 2592
	/*
	 * Actually print the definition.
	 *
B
Bruce Momjian 已提交
2593 2594 2595
	 * 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 ...
2596
	 */
2597
	if (ropt->noOwner && strcmp(te->desc, "SCHEMA") == 0)
2598
	{
2599
		ahprintf(AH, "CREATE SCHEMA %s;\n\n\n", fmtId(te->tag));
2600
	}
2601
	else
2602
	{
2603 2604
		if (strlen(te->defn) > 0)
			ahprintf(AH, "%s\n\n", te->defn);
2605
	}
2606 2607 2608

	/*
	 * If we aren't using SET SESSION AUTH to determine ownership, we must
2609 2610 2611
	 * 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.
2612 2613
	 */
	if (!ropt->noOwner && !ropt->use_setsessauth &&
2614 2615 2616 2617 2618 2619 2620 2621 2622
		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 ||
2623
			strcmp(te->desc, "OPERATOR FAMILY") == 0 ||
2624
			strcmp(te->desc, "PROCEDURAL LANGUAGE") == 0 ||
2625 2626 2627 2628
			strcmp(te->desc, "SCHEMA") == 0 ||
			strcmp(te->desc, "TABLE") == 0 ||
			strcmp(te->desc, "TYPE") == 0 ||
			strcmp(te->desc, "VIEW") == 0 ||
2629 2630 2631
			strcmp(te->desc, "SEQUENCE") == 0 ||
			strcmp(te->desc, "TEXT SEARCH DICTIONARY") == 0 ||
			strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0)
2632 2633 2634 2635
		{
			PQExpBuffer temp = createPQExpBuffer();

			appendPQExpBuffer(temp, "ALTER ");
2636
			_getObjectDescription(temp, te, AH);
2637 2638 2639 2640 2641 2642
			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 ||
2643
				 strcmp(te->desc, "CONSTRAINT") == 0 ||
2644 2645
				 strcmp(te->desc, "DEFAULT") == 0 ||
				 strcmp(te->desc, "FK CONSTRAINT") == 0 ||
2646
				 strcmp(te->desc, "INDEX") == 0 ||
2647 2648 2649 2650 2651 2652 2653 2654 2655 2656
				 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);
		}
2657
	}
B
Bruce Momjian 已提交
2658

2659 2660
	/*
	 * If it's an ACL entry, it might contain SET SESSION AUTHORIZATION
B
Bruce Momjian 已提交
2661
	 * commands, so we can no longer assume we know the current auth setting.
2662 2663 2664 2665 2666 2667 2668
	 */
	if (strncmp(te->desc, "ACL", 3) == 0)
	{
		if (AH->currUser)
			free(AH->currUser);
		AH->currUser = NULL;
	}
B
Bruce Momjian 已提交
2669 2670
}

B
Bruce Momjian 已提交
2671 2672
void
WriteHead(ArchiveHandle *AH)
B
Bruce Momjian 已提交
2673
{
B
Bruce Momjian 已提交
2674
	struct tm	crtm;
2675

B
Bruce Momjian 已提交
2676 2677 2678 2679 2680
	(*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);
2681
	(*AH->WriteBytePtr) (AH, AH->offSize);
B
Bruce Momjian 已提交
2682
	(*AH->WriteBytePtr) (AH, AH->format);
B
Bruce Momjian 已提交
2683

2684
#ifndef HAVE_LIBZ
B
Bruce Momjian 已提交
2685
	if (AH->compression != 0)
2686
		write_msg(modulename, "WARNING: requested compression not available in this "
2687
				  "installation -- archive will be uncompressed\n");
B
Bruce Momjian 已提交
2688

B
Bruce Momjian 已提交
2689
	AH->compression = 0;
2690
#endif
B
Bruce Momjian 已提交
2691

2692 2693 2694 2695 2696 2697 2698 2699 2700 2701
	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);
2702
	WriteStr(AH, PQdb(AH->connection));
2703 2704
	WriteStr(AH, AH->public.remoteVersionStr);
	WriteStr(AH, PG_VERSION);
B
Bruce Momjian 已提交
2705 2706
}

B
Bruce Momjian 已提交
2707 2708
void
ReadHead(ArchiveHandle *AH)
B
Bruce Momjian 已提交
2709
{
B
Bruce Momjian 已提交
2710 2711
	char		tmpMag[7];
	int			fmt;
2712
	struct tm	crtm;
B
Bruce Momjian 已提交
2713

2714
	/* If we haven't already read the header... */
B
Bruce Momjian 已提交
2715 2716
	if (!AH->readHeader)
	{
2717 2718
		if ((*AH->ReadBufPtr) (AH, tmpMag, 5) != 5)
			die_horribly(AH, modulename, "unexpected end of file\n");
B
Bruce Momjian 已提交
2719

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

B
Bruce Momjian 已提交
2723 2724
		AH->vmaj = (*AH->ReadBytePtr) (AH);
		AH->vmin = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
2725

B
Bruce Momjian 已提交
2726 2727 2728
		if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))		/* Version > 1.0 */
			AH->vrev = (*AH->ReadBytePtr) (AH);
		else
2729
			AH->vrev = 0;
B
Bruce Momjian 已提交
2730

B
Bruce Momjian 已提交
2731
		AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
B
Bruce Momjian 已提交
2732 2733


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

B
Bruce Momjian 已提交
2738
		AH->intSize = (*AH->ReadBytePtr) (AH);
2739
		if (AH->intSize > 32)
P
Peter Eisentraut 已提交
2740 2741
			die_horribly(AH, modulename, "sanity check on integer size (%lu) failed\n",
						 (unsigned long) AH->intSize);
B
Bruce Momjian 已提交
2742

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

2746
		if (AH->version >= K_VERS_1_7)
B
Bruce Momjian 已提交
2747
			AH->offSize = (*AH->ReadBytePtr) (AH);
2748
		else
B
Bruce Momjian 已提交
2749
			AH->offSize = AH->intSize;
2750

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

2753
		if (AH->format != fmt)
2754 2755
			die_horribly(AH, modulename, "expected format (%d) differs from format found in file (%d)\n",
						 AH->format, fmt);
B
Bruce Momjian 已提交
2756
	}
B
Bruce Momjian 已提交
2757

B
Bruce Momjian 已提交
2758 2759
	if (AH->version >= K_VERS_1_2)
	{
2760
		if (AH->version < K_VERS_1_4)
B
Bruce Momjian 已提交
2761
			AH->compression = (*AH->ReadBytePtr) (AH);
2762 2763
		else
			AH->compression = ReadInt(AH);
B
Bruce Momjian 已提交
2764 2765
	}
	else
2766
		AH->compression = Z_DEFAULT_COMPRESSION;
B
Bruce Momjian 已提交
2767

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

2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786
	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 已提交
2787
		if (AH->createDate == (time_t) -1)
2788
			write_msg(modulename, "WARNING: invalid creation date in header\n");
2789 2790
	}

2791 2792 2793 2794 2795 2796
	if (AH->version >= K_VERS_1_10)
	{
		AH->archiveRemoteVersion = ReadStr(AH);
		AH->archiveDumpVersion = ReadStr(AH);
	}

B
Bruce Momjian 已提交
2797 2798 2799
}


2800 2801 2802 2803 2804 2805 2806 2807 2808
/*
 * checkSeek
 *	  check to see if fseek can be performed.
 */

bool
checkSeek(FILE *fp)
{

B
Bruce Momjian 已提交
2809
	if (fseeko(fp, 0, SEEK_CUR) != 0)
2810
		return false;
2811
	else if (sizeof(pgoff_t) > sizeof(long))
B
Bruce Momjian 已提交
2812 2813

		/*
2814 2815
		 * At this point, pgoff_t is too large for long, so we return based on
		 * whether an pgoff_t version of fseek is available.
B
Bruce Momjian 已提交
2816
		 */
2817 2818 2819 2820 2821 2822 2823 2824
#ifdef HAVE_FSEEKO
		return true;
#else
		return false;
#endif
	else
		return true;
}
2825 2826 2827 2828 2829 2830 2831 2832 2833 2834


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

2835 2836 2837
	/*
	 * We don't print the timezone on Win32, because the names are long and
	 * localized, which means they may contain characters in various random
B
Bruce Momjian 已提交
2838 2839
	 * encodings; this has been seen to cause encoding errors when reading the
	 * dump script.
2840 2841 2842 2843 2844 2845 2846 2847
	 */
	if (strftime(buf, sizeof(buf),
#ifndef WIN32
				 "%Y-%m-%d %H:%M:%S %Z",
#else
				 "%Y-%m-%d %H:%M:%S",
#endif
				 localtime(&tim)) != 0)
2848 2849
		ahprintf(AH, "-- %s %s\n\n", msg, buf);
}