pg_backup_archiver.c 64.3 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.146 2007/08/21 01:11:20 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
#include "mb/pg_wchar.h"
36

37

38
const char *progname;
39

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


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

49

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

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

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

75

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


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

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

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

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

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

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

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

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

	if (res != 0)
123 124
		die_horribly(AH, modulename, "could not close output file: %s\n",
					 strerror(errno));
B
Bruce Momjian 已提交
125 126 127
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

228 229
	AH->stage = STAGE_PROCESSING;

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

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

253
	/*
254
	 * Now process each non-ACL TOC entry
255
	 */
256
	for (te = AH->toc->next; te != AH->toc; te = te->next)
B
Bruce Momjian 已提交
257
	{
258 259
		AH->currentTE = te;

260
		/* Work out what, if anything, we want from this entry */
261
		reqs = _tocEntryRequired(te, ropt, false);
262

263 264 265
		/* Dump any relevant dump warnings to stderr */
		if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
		{
266
			if (!ropt->dataOnly && te->defn != NULL && strlen(te->defn) != 0)
267 268 269
				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);
270
		}
271

272 273
		defnDumped = false;

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

278
			_printTocEntry(AH, te, ropt, false, false);
279
			defnDumped = true;
280

B
Bruce Momjian 已提交
281
			/*
282 283
			 * If we could not create a table and --no-data-for-failed-tables
			 * was given, ignore the corresponding TABLE DATA
B
Bruce Momjian 已提交
284
			 */
285 286 287
			if (ropt->noDataForFailedTables &&
				AH->lastErrorTE == te &&
				strcmp(te->desc, "TABLE") == 0)
B
Bruce Momjian 已提交
288
			{
289
				TocEntry   *tes;
B
Bruce Momjian 已提交
290

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

294
				for (tes = te->next; tes != AH->toc; tes = tes->next)
B
Bruce Momjian 已提交
295
				{
296 297 298 299
					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 已提交
300
					{
301 302
						/* mark it unwanted */
						ropt->idWanted[tes->dumpId - 1] = false;
B
Bruce Momjian 已提交
303
						break;
304 305 306 307
					}
				}
			}

308
			/* If we created a DB, connect to it... */
B
Bruce Momjian 已提交
309
			if (strcmp(te->desc, "DATABASE") == 0)
310
			{
311 312
				ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag);
				_reconnectToDB(AH, te->tag);
313
			}
314
		}
B
Bruce Momjian 已提交
315

B
Bruce Momjian 已提交
316
		/*
317
		 * If we have a data component, then process it
318
		 */
319
		if ((reqs & REQ_DATA) != 0)
B
Bruce Momjian 已提交
320
		{
321
			/*
B
Bruce Momjian 已提交
322 323 324
			 * 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.
325
			 */
326
			if (te->hadDumper)
327 328
			{
				/*
329
				 * If we can output the data, then restore it.
330
				 */
B
Bruce Momjian 已提交
331
				if (AH->PrintTocDataPtr !=NULL && (reqs & REQ_DATA) != 0)
332 333 334
				{
#ifndef HAVE_LIBZ
					if (AH->compression != 0)
335
						die_horribly(AH, modulename, "cannot restore from compressed archive (compression not supported in this installation)\n");
336
#endif
337

338
					_printTocEntry(AH, te, ropt, true, false);
339

340 341
					if (strcmp(te->desc, "BLOBS") == 0 ||
						strcmp(te->desc, "BLOB COMMENTS") == 0)
342
					{
343
						ahlog(AH, 1, "restoring %s\n", te->desc);
344

345 346 347
						_selectOutputSchema(AH, "pg_catalog");

						(*AH->PrintTocDataPtr) (AH, te, ropt);
348 349 350 351 352
					}
					else
					{
						_disableTriggersIfNecessary(AH, te, ropt);

353 354
						/* Select owner and schema as necessary */
						_becomeOwner(AH, te);
355
						_selectOutputSchema(AH, te->namespace);
356

357 358
						ahlog(AH, 1, "restoring data for table \"%s\"\n",
							  te->tag);
359 360

						/*
B
Bruce Momjian 已提交
361 362 363 364
						 * 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.
365
						 *
366 367 368
						 * For V1.3+, the table data MUST have a copy
						 * statement so that we can go into appropriate mode
						 * with libpq.
369 370
						 */
						if (te->copyStmt && strlen(te->copyStmt) > 0)
371
						{
372
							ahprintf(AH, "%s", te->copyStmt);
373 374
							AH->writingCopyData = true;
						}
375 376 377

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

378 379
						AH->writingCopyData = false;

380 381 382
						_enableTriggersIfNecessary(AH, te, ropt);
					}
				}
383 384 385 386
			}
			else if (!defnDumped)
			{
				/* If we haven't already dumped the defn part, do so now */
387
				ahlog(AH, 1, "executing %s %s\n", te->desc, te->tag);
388
				_printTocEntry(AH, te, ropt, false, false);
389 390
			}
		}
B
Bruce Momjian 已提交
391
	}							/* end loop over TOC entries */
B
Bruce Momjian 已提交
392

393 394 395
	/*
	 * Scan TOC again to output ownership commands and ACLs
	 */
396
	for (te = AH->toc->next; te != AH->toc; te = te->next)
397
	{
398 399
		AH->currentTE = te;

400 401 402 403 404
		/* 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 已提交
405
			ahlog(AH, 1, "setting owner and privileges for %s %s\n",
406
				  te->desc, te->tag);
407 408 409 410
			_printTocEntry(AH, te, ropt, false, true);
		}
	}

411
	if (ropt->single_txn)
412 413 414 415 416 417
	{
		if (AH->connection)
			CommitTransaction(AH);
		else
			ahprintf(AH, "COMMIT;\n\n");
	}
B
Bruce Momjian 已提交
418

419 420 421
	if (AH->public.verbose)
		dumpTimestamp(AH, "Completed on", time(NULL));

422 423
	ahprintf(AH, "--\n-- PostgreSQL database dump complete\n--\n\n");

424
	/*
425
	 * Clean up & we're done.
426
	 */
427 428
	AH->stage = STAGE_FINALIZING;

429 430 431 432 433 434 435
	if (ropt->filename || ropt->compression)
		ResetOutput(AH, sav);

	if (ropt->useDB)
	{
		PQfinish(AH->connection);
		AH->connection = NULL;
436
	}
B
Bruce Momjian 已提交
437 438
}

439 440 441 442
/*
 * Allocate a new RestoreOptions block.
 * This is mainly so we can initialize it, but also for future expansion,
 */
B
Bruce Momjian 已提交
443 444
RestoreOptions *
NewRestoreOptions(void)
B
Bruce Momjian 已提交
445
{
B
Bruce Momjian 已提交
446
	RestoreOptions *opts;
B
Bruce Momjian 已提交
447

B
Bruce Momjian 已提交
448
	opts = (RestoreOptions *) calloc(1, sizeof(RestoreOptions));
B
Bruce Momjian 已提交
449 450

	opts->format = archUnknown;
451
	opts->suppressDumpWarnings = false;
452
	opts->exit_on_error = false;
B
Bruce Momjian 已提交
453 454 455 456

	return opts;
}

B
Bruce Momjian 已提交
457 458
static void
_disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
B
Bruce Momjian 已提交
459
{
460 461
	/* This hack is only needed in a data-only restore */
	if (!ropt->dataOnly || !ropt->disable_triggers)
462 463
		return;

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

466
	/*
B
Bruce Momjian 已提交
467
	 * Become superuser if possible, since they are the only ones who can
468 469 470
	 * 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?)
471
	 */
472
	_becomeUser(AH, ropt->superuser);
473 474

	/*
475
	 * Disable them.
476
	 */
477
	_selectOutputSchema(AH, te->namespace);
478

479 480
	ahprintf(AH, "ALTER TABLE %s DISABLE TRIGGER ALL;\n\n",
			 fmtId(te->tag));
B
Bruce Momjian 已提交
481 482
}

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

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

492
	/*
B
Bruce Momjian 已提交
493
	 * Become superuser if possible, since they are the only ones who can
494 495 496
	 * 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?)
497
	 */
498
	_becomeUser(AH, ropt->superuser);
499 500

	/*
501
	 * Enable them.
502
	 */
503
	_selectOutputSchema(AH, te->namespace);
504

505 506
	ahprintf(AH, "ALTER TABLE %s ENABLE TRIGGER ALL;\n\n",
			 fmtId(te->tag));
507
}
B
Bruce Momjian 已提交
508 509

/*
510
 * This is a routine that is part of the dumper interface, hence the 'Archive*' parameter.
B
Bruce Momjian 已提交
511 512 513
 */

/* Public */
P
Peter Eisentraut 已提交
514 515
size_t
WriteData(Archive *AHX, const void *data, size_t dLen)
B
Bruce Momjian 已提交
516
{
B
Bruce Momjian 已提交
517
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
B
Bruce Momjian 已提交
518

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

B
Bruce Momjian 已提交
522
	return (*AH->WriteDataPtr) (AH, data, dLen);
B
Bruce Momjian 已提交
523 524 525
}

/*
B
Bruce Momjian 已提交
526
 * Create a new TOC entry. The TOC was designed as a TOC, but is now the
B
Bruce Momjian 已提交
527 528 529 530
 * repository for all metadata. But the name has stuck.
 */

/* Public */
B
Bruce Momjian 已提交
531
void
532 533 534
ArchiveEntry(Archive *AHX,
			 CatalogId catalogId, DumpId dumpId,
			 const char *tag,
535
			 const char *namespace,
B
Bruce Momjian 已提交
536
			 const char *tablespace,
537
			 const char *owner, bool withOids,
538 539 540
			 const char *desc, const char *defn,
			 const char *dropStmt, const char *copyStmt,
			 const DumpId *deps, int nDeps,
B
Bruce Momjian 已提交
541
			 DataDumperPtr dumpFn, void *dumpArg)
B
Bruce Momjian 已提交
542
{
B
Bruce Momjian 已提交
543 544 545 546 547
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *newToc;

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

550 551 552 553
	AH->tocCount++;
	if (dumpId > AH->maxDumpId)
		AH->maxDumpId = dumpId;

B
Bruce Momjian 已提交
554 555 556 557 558
	newToc->prev = AH->toc->prev;
	newToc->next = AH->toc;
	AH->toc->prev->next = newToc;
	AH->toc->prev = newToc;

559 560
	newToc->catalogId = catalogId;
	newToc->dumpId = dumpId;
561

562
	newToc->tag = strdup(tag);
563
	newToc->namespace = namespace ? strdup(namespace) : NULL;
564
	newToc->tablespace = tablespace ? strdup(tablespace) : NULL;
565
	newToc->owner = strdup(owner);
566
	newToc->withOids = withOids;
B
Bruce Momjian 已提交
567
	newToc->desc = strdup(desc);
568 569 570
	newToc->defn = strdup(defn);
	newToc->dropStmt = strdup(dropStmt);
	newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
571

572 573 574 575 576 577 578 579 580 581 582
	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;
	}
583

584 585
	newToc->dataDumper = dumpFn;
	newToc->dataDumperArg = dumpArg;
586
	newToc->hadDumper = dumpFn ? true : false;
B
Bruce Momjian 已提交
587

588
	newToc->formatData = NULL;
B
Bruce Momjian 已提交
589

B
Bruce Momjian 已提交
590
	if (AH->ArchiveEntryPtr !=NULL)
B
Bruce Momjian 已提交
591
		(*AH->ArchiveEntryPtr) (AH, newToc);
B
Bruce Momjian 已提交
592 593 594
}

/* Public */
B
Bruce Momjian 已提交
595 596
void
PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
597
{
B
Bruce Momjian 已提交
598 599 600 601
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *te = AH->toc->next;
	OutputContext sav;
	char	   *fmtName;
B
Bruce Momjian 已提交
602

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

606 607
	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 已提交
608
			 AH->archdbname, AH->tocCount, AH->compression);
609

B
Bruce Momjian 已提交
610 611
	switch (AH->format)
	{
612 613 614 615 616 617 618 619 620 621 622 623
		case archFiles:
			fmtName = "FILES";
			break;
		case archCustom:
			fmtName = "CUSTOM";
			break;
		case archTar:
			fmtName = "TAR";
			break;
		default:
			fmtName = "UNKNOWN";
	}
624 625

	ahprintf(AH, ";     Dump Version: %d.%d-%d\n", AH->vmaj, AH->vmin, AH->vrev);
626
	ahprintf(AH, ";     Format: %s\n", fmtName);
T
Tom Lane 已提交
627 628
	ahprintf(AH, ";     Integer: %d bytes\n", (int) AH->intSize);
	ahprintf(AH, ";     Offset: %d bytes\n", (int) AH->offSize);
629 630 631 632 633 634
	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);
635

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

B
Bruce Momjian 已提交
638 639
	while (te != AH->toc)
	{
640
		if (_tocEntryRequired(te, ropt, true) != 0)
641
			ahprintf(AH, "%d; %u %u %s %s %s %s\n", te->dumpId,
642
					 te->catalogId.tableoid, te->catalogId.oid,
643 644
					 te->desc, te->namespace ? te->namespace : "-",
					 te->tag, te->owner);
B
Bruce Momjian 已提交
645
		te = te->next;
B
Bruce Momjian 已提交
646
	}
B
Bruce Momjian 已提交
647

B
Bruce Momjian 已提交
648 649
	if (ropt->filename)
		ResetOutput(AH, sav);
B
Bruce Momjian 已提交
650 651
}

652 653 654 655 656
/***********
 * BLOB Archival
 ***********/

/* Called by a dumper to signal start of a BLOB */
B
Bruce Momjian 已提交
657
int
658
StartBlob(Archive *AHX, Oid oid)
659
{
B
Bruce Momjian 已提交
660
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
661

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

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

B
Bruce Momjian 已提交
667
	return 1;
668 669 670
}

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

B
Bruce Momjian 已提交
676 677
	if (AH->EndBlobPtr)
		(*AH->EndBlobPtr) (AH, AH->currToc, oid);
678

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

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

686
/*
B
Bruce Momjian 已提交
687
 * Called by a format handler before any blobs are restored
688
 */
B
Bruce Momjian 已提交
689 690
void
StartRestoreBlobs(ArchiveHandle *AH)
691
{
692 693 694 695 696 697 698
	if (!AH->ropt->single_txn)
	{
		if (AH->connection)
			StartTransaction(AH);
		else
			ahprintf(AH, "BEGIN;\n\n");
	}
699

700 701 702 703
	AH->blobCount = 0;
}

/*
B
Bruce Momjian 已提交
704
 * Called by a format handler after all blobs are restored
705
 */
B
Bruce Momjian 已提交
706 707
void
EndRestoreBlobs(ArchiveHandle *AH)
708
{
709 710 711 712 713 714 715
	if (!AH->ropt->single_txn)
	{
		if (AH->connection)
			CommitTransaction(AH);
		else
			ahprintf(AH, "COMMIT;\n\n");
	}
716

717
	ahlog(AH, 1, "restored %d large objects\n", AH->blobCount);
718 719 720
}


721 722 723
/*
 * Called by a format handler to initiate restoration of a blob
 */
B
Bruce Momjian 已提交
724
void
725
StartRestoreBlob(ArchiveHandle *AH, Oid oid)
726
{
727
	Oid			loOid;
728

729 730
	AH->blobCount++;

731 732 733
	/* Initialize the LO Buffer */
	AH->lo_buf_used = 0;

734 735 736
	ahlog(AH, 2, "restoring large object with OID %u\n", oid);

	if (AH->connection)
737
	{
738 739 740 741 742 743 744 745 746 747 748 749
		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);
750
	}
751

B
Bruce Momjian 已提交
752
	AH->writingBlob = 1;
753 754
}

B
Bruce Momjian 已提交
755
void
756
EndRestoreBlob(ArchiveHandle *AH, Oid oid)
757
{
758 759 760
	if (AH->lo_buf_used > 0)
	{
		/* Write remaining bytes from the LO buffer */
761
		dump_lo_buf(AH);
762
	}
763

B
Bruce Momjian 已提交
764
	AH->writingBlob = 0;
765

766
	if (AH->connection)
767
	{
768 769 770 771 772 773
		lo_close(AH->connection, AH->loFd);
		AH->loFd = -1;
	}
	else
	{
		ahprintf(AH, "SELECT lo_close(0);\n\n");
774
	}
775 776
}

B
Bruce Momjian 已提交
777 778 779 780
/***********
 * Sorting and Reordering
 ***********/

B
Bruce Momjian 已提交
781 782
void
SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
783
{
B
Bruce Momjian 已提交
784 785 786 787 788
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	FILE	   *fh;
	char		buf[1024];
	char	   *cmnt;
	char	   *endptr;
789
	DumpId		id;
B
Bruce Momjian 已提交
790 791 792 793
	TocEntry   *te;
	TocEntry   *tePrev;

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

B
Bruce Momjian 已提交
797 798
	/* Set prev entry as head of list */
	tePrev = AH->toc;
B
Bruce Momjian 已提交
799

B
Bruce Momjian 已提交
800 801 802
	/* Setup the file */
	fh = fopen(ropt->tocFile, PG_BINARY_R);
	if (!fh)
803 804
		die_horribly(AH, modulename, "could not open TOC file: %s\n",
					 strerror(errno));
B
Bruce Momjian 已提交
805

806
	while (fgets(buf, sizeof(buf), fh) != NULL)
B
Bruce Momjian 已提交
807
	{
808
		/* Truncate line at comment, if any */
B
Bruce Momjian 已提交
809 810 811 812
		cmnt = strchr(buf, ';');
		if (cmnt != NULL)
			cmnt[0] = '\0';

813 814
		/* Ignore if all blank */
		if (strspn(buf, " \t\r") == strlen(buf))
B
Bruce Momjian 已提交
815 816
			continue;

817
		/* Get an ID, check it's valid and not already seen */
B
Bruce Momjian 已提交
818
		id = strtol(buf, &endptr, 10);
819 820
		if (endptr == buf || id <= 0 || id > AH->maxDumpId ||
			ropt->idWanted[id - 1])
B
Bruce Momjian 已提交
821
		{
822
			write_msg(modulename, "WARNING: line ignored: %s\n", buf);
B
Bruce Momjian 已提交
823 824
			continue;
		}
B
Bruce Momjian 已提交
825

B
Bruce Momjian 已提交
826
		/* Find TOC entry */
827
		te = getTocEntryByDumpId(AH, id);
B
Bruce Momjian 已提交
828
		if (!te)
829 830
			die_horribly(AH, modulename, "could not find entry for ID %d\n",
						 id);
B
Bruce Momjian 已提交
831

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

B
Bruce Momjian 已提交
834 835 836
		_moveAfter(AH, tePrev, te);
		tePrev = te;
	}
B
Bruce Momjian 已提交
837

B
Bruce Momjian 已提交
838
	if (fclose(fh) != 0)
839 840
		die_horribly(AH, modulename, "could not close TOC file: %s\n",
					 strerror(errno));
B
Bruce Momjian 已提交
841 842
}

843 844 845 846 847 848 849 850 851 852 853 854 855
/*
 * 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 已提交
856 857 858 859 860 861
/**********************
 * 'Convenience functions that look like standard IO functions
 * for writing data when in dump mode.
 **********************/

/* Public */
B
Bruce Momjian 已提交
862 863 864 865
int
archputs(const char *s, Archive *AH)
{
	return WriteData(AH, s, strlen(s));
B
Bruce Momjian 已提交
866 867 868
}

/* Public */
B
Bruce Momjian 已提交
869 870
int
archprintf(Archive *AH, const char *fmt,...)
B
Bruce Momjian 已提交
871
{
B
Bruce Momjian 已提交
872 873 874 875 876 877
	char	   *p = NULL;
	va_list		ap;
	int			bSize = strlen(fmt) + 256;
	int			cnt = -1;

	/*
B
Bruce Momjian 已提交
878 879 880
	 * 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 已提交
881 882
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
B
Bruce Momjian 已提交
883
	{
B
Bruce Momjian 已提交
884 885
		if (p != NULL)
			free(p);
886
		bSize *= 2;
B
Bruce Momjian 已提交
887
		p = (char *) malloc(bSize);
888
		if (p == NULL)
889
			exit_horribly(AH, modulename, "out of memory\n");
890 891 892
		va_start(ap, fmt);
		cnt = vsnprintf(p, bSize, fmt, ap);
		va_end(ap);
B
Bruce Momjian 已提交
893 894 895 896
	}
	WriteData(AH, p, cnt);
	free(p);
	return cnt;
B
Bruce Momjian 已提交
897 898 899 900 901 902 903
}


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

904
static OutputContext
B
Bruce Momjian 已提交
905
SetOutput(ArchiveHandle *AH, char *filename, int compression)
B
Bruce Momjian 已提交
906
{
B
Bruce Momjian 已提交
907
	OutputContext sav;
908
	int			fn;
B
Bruce Momjian 已提交
909 910 911 912 913 914

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

	if (filename)
915
		fn = -1;
B
Bruce Momjian 已提交
916 917 918 919
	else if (AH->FH)
		fn = fileno(AH->FH);
	else if (AH->fSpec)
	{
920
		fn = -1;
B
Bruce Momjian 已提交
921 922 923 924 925 926
		filename = AH->fSpec;
	}
	else
		fn = fileno(stdout);

	/* If compression explicitly requested, use gzopen */
927
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
928 929
	if (compression != 0)
	{
930 931 932
		char		fmode[10];

		/* Don't use PG_BINARY_x since this is zlib */
933
		sprintf(fmode, "wb%d", compression);
934 935
		if (fn >= 0)
			AH->OF = gzdopen(dup(fn), fmode);
B
Bruce Momjian 已提交
936 937
		else
			AH->OF = gzopen(filename, fmode);
938
		AH->gzOut = 1;
B
Bruce Momjian 已提交
939 940
	}
	else
B
Bruce Momjian 已提交
941
#endif
942
	{							/* Use fopen */
943 944 945 946 947 948 949
		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 已提交
950
		else
951 952 953 954 955 956
		{
			if (fn >= 0)
				AH->OF = fdopen(dup(fn), PG_BINARY_W);
			else
				AH->OF = fopen(filename, PG_BINARY_W);
		}
957
		AH->gzOut = 0;
B
Bruce Momjian 已提交
958
	}
B
Bruce Momjian 已提交
959

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

B
Bruce Momjian 已提交
963
	return sav;
B
Bruce Momjian 已提交
964 965
}

966
static void
B
Bruce Momjian 已提交
967
ResetOutput(ArchiveHandle *AH, OutputContext sav)
B
Bruce Momjian 已提交
968
{
B
Bruce Momjian 已提交
969
	int			res;
970

B
Bruce Momjian 已提交
971
	if (AH->gzOut)
972
		res = GZCLOSE(AH->OF);
B
Bruce Momjian 已提交
973
	else
974 975 976
		res = fclose(AH->OF);

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

B
Bruce Momjian 已提交
980 981
	AH->gzOut = sav.gzOut;
	AH->OF = sav.OF;
B
Bruce Momjian 已提交
982 983 984 985 986
}



/*
B
Bruce Momjian 已提交
987
 *	Print formatted text to the output file (usually stdout).
B
Bruce Momjian 已提交
988
 */
B
Bruce Momjian 已提交
989 990
int
ahprintf(ArchiveHandle *AH, const char *fmt,...)
B
Bruce Momjian 已提交
991
{
B
Bruce Momjian 已提交
992 993 994 995 996 997
	char	   *p = NULL;
	va_list		ap;
	int			bSize = strlen(fmt) + 256;		/* Should be enough */
	int			cnt = -1;

	/*
B
Bruce Momjian 已提交
998 999
	 * This is paranoid: deal with the possibility that vsnprintf is willing
	 * to ignore trailing null
B
Bruce Momjian 已提交
1000 1001 1002
	 */

	/*
B
Bruce Momjian 已提交
1003 1004
	 * or returns > 0 even if string does not fit. It may be the case that it
	 * returns cnt = bufsize
B
Bruce Momjian 已提交
1005 1006
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
1007
	{
B
Bruce Momjian 已提交
1008 1009
		if (p != NULL)
			free(p);
1010
		bSize *= 2;
B
Bruce Momjian 已提交
1011
		p = (char *) malloc(bSize);
1012
		if (p == NULL)
1013
			die_horribly(AH, modulename, "out of memory\n");
1014
		va_start(ap, fmt);
1015
		cnt = vsnprintf(p, bSize, fmt, ap);
1016
		va_end(ap);
B
Bruce Momjian 已提交
1017 1018 1019 1020
	}
	ahwrite(p, 1, cnt, AH);
	free(p);
	return cnt;
B
Bruce Momjian 已提交
1021 1022
}

B
Bruce Momjian 已提交
1023 1024
void
ahlog(ArchiveHandle *AH, int level, const char *fmt,...)
1025 1026 1027 1028 1029 1030 1031
{
	va_list		ap;

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

	va_start(ap, fmt);
1032
	_write_msg(NULL, fmt, ap);
1033 1034 1035
	va_end(ap);
}

1036 1037 1038
/*
 * Single place for logic which says 'We are restoring to a direct DB connection'.
 */
1039
static int
B
Bruce Momjian 已提交
1040
RestoringToDB(ArchiveHandle *AH)
1041 1042 1043 1044
{
	return (AH->ropt && AH->ropt->useDB && AH->connection);
}

1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
/*
 * 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 已提交
1060 1061
			"could not write to large object (result: %lu, expected: %lu)\n",
					   (unsigned long) res, (unsigned long) AH->lo_buf_used);
1062 1063 1064 1065
	}
	else
	{
		unsigned char *str;
B
Bruce Momjian 已提交
1066
		size_t		len;
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083

		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 已提交
1084
/*
B
Bruce Momjian 已提交
1085 1086 1087
 *	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
1088
 *	wants to generate a script (see TAR output).
B
Bruce Momjian 已提交
1089
 */
B
Bruce Momjian 已提交
1090 1091
int
ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
B
Bruce Momjian 已提交
1092
{
P
Peter Eisentraut 已提交
1093
	size_t		res;
1094

B
Bruce Momjian 已提交
1095
	if (AH->writingBlob)
1096
	{
B
Bruce Momjian 已提交
1097
		size_t		remaining = size * nmemb;
1098 1099

		while (AH->lo_buf_used + remaining > AH->lo_buf_size)
P
Peter Eisentraut 已提交
1100
		{
1101 1102 1103 1104 1105 1106 1107
			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 已提交
1108 1109
		}

1110 1111 1112
		memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining);
		AH->lo_buf_used += remaining;

P
Peter Eisentraut 已提交
1113
		return size * nmemb;
1114
	}
B
Bruce Momjian 已提交
1115
	else if (AH->gzOut)
1116
	{
B
Bruce Momjian 已提交
1117
		res = GZWRITE((void *) ptr, size, nmemb, AH->OF);
1118
		if (res != (nmemb * size))
1119
			die_horribly(AH, modulename, "could not write to output file: %s\n", strerror(errno));
1120 1121
		return res;
	}
B
Bruce Momjian 已提交
1122
	else if (AH->CustomOutPtr)
1123
	{
B
Bruce Momjian 已提交
1124 1125
		res = AH->CustomOutPtr (AH, ptr, size * nmemb);

1126
		if (res != (nmemb * size))
1127
			die_horribly(AH, modulename, "could not write to custom output routine\n");
1128 1129
		return res;
	}
1130 1131 1132
	else
	{
		/*
B
Bruce Momjian 已提交
1133 1134 1135
		 * If we're doing a restore, and it's direct to DB, and we're
		 * connected then send it to the DB.
		 */
1136
		if (RestoringToDB(AH))
B
Bruce Momjian 已提交
1137
			return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb);		/* Always 1, currently */
1138
		else
1139
		{
B
Bruce Momjian 已提交
1140
			res = fwrite((void *) ptr, size, nmemb, AH->OF);
1141
			if (res != nmemb)
1142 1143
				die_horribly(AH, modulename, "could not write to output file: %s\n",
							 strerror(errno));
1144 1145
			return res;
		}
1146
	}
B
Bruce Momjian 已提交
1147
}
1148 1149

/* Common exit code */
B
Bruce Momjian 已提交
1150
static void
1151
_write_msg(const char *modulename, const char *fmt, va_list ap)
1152
{
1153
	if (modulename)
1154
		fprintf(stderr, "%s: [%s] ", progname, _(modulename));
1155 1156
	else
		fprintf(stderr, "%s: ", progname);
1157
	vfprintf(stderr, _(fmt), ap);
1158 1159 1160
}

void
1161
write_msg(const char *modulename, const char *fmt,...)
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174
{
	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);
1175

B
Bruce Momjian 已提交
1176 1177
	if (AH)
	{
1178 1179
		if (AH->public.verbose)
			write_msg(NULL, "*** aborted because of error\n");
B
Bruce Momjian 已提交
1180 1181
		if (AH->connection)
			PQfinish(AH->connection);
1182
	}
1183

B
Bruce Momjian 已提交
1184
	exit(1);
B
Bruce Momjian 已提交
1185 1186
}

1187
/* External use */
B
Bruce Momjian 已提交
1188
void
1189
exit_horribly(Archive *AH, const char *modulename, const char *fmt,...)
1190
{
B
Bruce Momjian 已提交
1191
	va_list		ap;
1192

B
Bruce Momjian 已提交
1193
	va_start(ap, fmt);
1194
	_die_horribly((ArchiveHandle *) AH, modulename, fmt, ap);
1195
	va_end(ap);
1196
}
B
Bruce Momjian 已提交
1197

1198
/* Archiver use (just different arg declaration) */
B
Bruce Momjian 已提交
1199
void
1200
die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...)
B
Bruce Momjian 已提交
1201
{
B
Bruce Momjian 已提交
1202
	va_list		ap;
B
Bruce Momjian 已提交
1203

B
Bruce Momjian 已提交
1204
	va_start(ap, fmt);
1205
	_die_horribly(AH, modulename, fmt, ap);
1206
	va_end(ap);
B
Bruce Momjian 已提交
1207 1208
}

1209 1210
/* on some error, we may decide to go on... */
void
B
Bruce Momjian 已提交
1211 1212
warn_or_die_horribly(ArchiveHandle *AH,
					 const char *modulename, const char *fmt,...)
1213
{
B
Bruce Momjian 已提交
1214
	va_list		ap;
1215

B
Bruce Momjian 已提交
1216 1217
	switch (AH->stage)
	{
1218 1219 1220 1221 1222 1223

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

		case STAGE_INITIALIZING:
B
Bruce Momjian 已提交
1224
			if (AH->stage != AH->lastErrorStage)
1225 1226 1227 1228
				write_msg(modulename, "Error while INITIALIZING:\n");
			break;

		case STAGE_PROCESSING:
B
Bruce Momjian 已提交
1229
			if (AH->stage != AH->lastErrorStage)
1230 1231 1232 1233
				write_msg(modulename, "Error while PROCESSING TOC:\n");
			break;

		case STAGE_FINALIZING:
B
Bruce Momjian 已提交
1234
			if (AH->stage != AH->lastErrorStage)
1235 1236 1237
				write_msg(modulename, "Error while FINALIZING:\n");
			break;
	}
B
Bruce Momjian 已提交
1238 1239
	if (AH->currentTE != NULL && AH->currentTE != AH->lastErrorTE)
	{
1240 1241
		write_msg(modulename, "Error from TOC entry %d; %u %u %s %s %s\n",
				  AH->currentTE->dumpId,
B
Bruce Momjian 已提交
1242 1243
			 AH->currentTE->catalogId.tableoid, AH->currentTE->catalogId.oid,
			  AH->currentTE->desc, AH->currentTE->tag, AH->currentTE->owner);
1244 1245 1246 1247
	}
	AH->lastErrorStage = AH->stage;
	AH->lastErrorTE = AH->currentTE;

1248
	va_start(ap, fmt);
1249
	if (AH->public.exit_on_error)
1250 1251 1252 1253 1254 1255 1256 1257
		_die_horribly(AH, modulename, fmt, ap);
	else
	{
		_write_msg(modulename, fmt, ap);
		AH->public.n_errors++;
	}
	va_end(ap);
}
1258

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

B
Bruce Momjian 已提交
1265 1266
	te->prev = pos;
	te->next = pos->next;
B
Bruce Momjian 已提交
1267

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

1272 1273
#ifdef NOT_USED

B
Bruce Momjian 已提交
1274 1275
static void
_moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
B
Bruce Momjian 已提交
1276
{
B
Bruce Momjian 已提交
1277 1278
	te->prev->next = te->next;
	te->next->prev = te->prev;
B
Bruce Momjian 已提交
1279

B
Bruce Momjian 已提交
1280 1281 1282 1283
	te->prev = pos->prev;
	te->next = pos;
	pos->prev->next = te;
	pos->prev = te;
B
Bruce Momjian 已提交
1284
}
1285 1286
#endif

B
Bruce Momjian 已提交
1287
static TocEntry *
1288
getTocEntryByDumpId(ArchiveHandle *AH, DumpId id)
B
Bruce Momjian 已提交
1289
{
B
Bruce Momjian 已提交
1290 1291 1292 1293 1294
	TocEntry   *te;

	te = AH->toc->next;
	while (te != AH->toc)
	{
1295
		if (te->dumpId == id)
B
Bruce Momjian 已提交
1296 1297 1298 1299
			return te;
		te = te->next;
	}
	return NULL;
B
Bruce Momjian 已提交
1300 1301
}

1302
teReqs
1303
TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
B
Bruce Momjian 已提交
1304
{
1305
	TocEntry   *te = getTocEntryByDumpId(AH, id);
B
Bruce Momjian 已提交
1306

B
Bruce Momjian 已提交
1307 1308
	if (!te)
		return 0;
B
Bruce Momjian 已提交
1309

1310
	return _tocEntryRequired(te, ropt, true);
B
Bruce Momjian 已提交
1311 1312
}

1313
size_t
1314
WriteOffset(ArchiveHandle *AH, pgoff_t o, int wasSet)
1315
{
B
Bruce Momjian 已提交
1316
	int			off;
1317 1318 1319 1320

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

1321 1322
	/* Write out pgoff_t smallest byte first, prevents endian mismatch */
	for (off = 0; off < sizeof(pgoff_t); off++)
1323
	{
B
Bruce Momjian 已提交
1324
		(*AH->WriteBytePtr) (AH, o & 0xFF);
1325 1326
		o >>= 8;
	}
1327
	return sizeof(pgoff_t) + 1;
1328 1329 1330
}

int
1331
ReadOffset(ArchiveHandle *AH, pgoff_t *o)
1332
{
B
Bruce Momjian 已提交
1333 1334 1335
	int			i;
	int			off;
	int			offsetFlg;
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346

	/* 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 已提交
1347
			return K_OFFSET_POS_NOT_SET;
1348
		else if (i == 0)
B
Bruce Momjian 已提交
1349
			return K_OFFSET_NO_DATA;
1350

1351 1352
		/* Cast to pgoff_t because it was written as an int. */
		*o = (pgoff_t) i;
1353 1354 1355 1356
		return K_OFFSET_POS_SET;
	}

	/*
B
Bruce Momjian 已提交
1357 1358
	 * Read the flag indicating the state of the data pointer. Check if valid
	 * and die if not.
1359
	 *
1360 1361
	 * This used to be handled by a negative or zero pointer, now we use an
	 * extra byte specifically for the state.
1362 1363 1364 1365 1366 1367 1368 1369 1370
	 */
	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 已提交
1371
			break;
1372 1373

		default:
1374
			die_horribly(AH, modulename, "unexpected data offset flag %d\n", offsetFlg);
1375 1376 1377 1378 1379 1380 1381
	}

	/*
	 * Read the bytes
	 */
	for (off = 0; off < AH->offSize; off++)
	{
1382 1383
		if (off < sizeof(pgoff_t))
			*o |= ((pgoff_t) ((*AH->ReadBytePtr) (AH))) << (off * 8);
1384 1385 1386
		else
		{
			if ((*AH->ReadBytePtr) (AH) != 0)
B
Bruce Momjian 已提交
1387
				die_horribly(AH, modulename, "file offset in dump file is too large\n");
1388 1389 1390 1391 1392 1393
		}
	}

	return offsetFlg;
}

P
Peter Eisentraut 已提交
1394
size_t
B
Bruce Momjian 已提交
1395
WriteInt(ArchiveHandle *AH, int i)
B
Bruce Momjian 已提交
1396
{
B
Bruce Momjian 已提交
1397 1398 1399
	int			b;

	/*
B
Bruce Momjian 已提交
1400 1401 1402 1403 1404
	 * 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 已提交
1405 1406 1407 1408 1409 1410
	 */

	/* SIGN byte */
	if (i < 0)
	{
		(*AH->WriteBytePtr) (AH, 1);
1411
		i = -i;
B
Bruce Momjian 已提交
1412 1413 1414 1415 1416 1417 1418
	}
	else
		(*AH->WriteBytePtr) (AH, 0);

	for (b = 0; b < AH->intSize; b++)
	{
		(*AH->WriteBytePtr) (AH, i & 0xFF);
1419
		i >>= 8;
B
Bruce Momjian 已提交
1420 1421 1422
	}

	return AH->intSize + 1;
B
Bruce Momjian 已提交
1423 1424
}

B
Bruce Momjian 已提交
1425 1426
int
ReadInt(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1427
{
B
Bruce Momjian 已提交
1428 1429 1430 1431 1432
	int			res = 0;
	int			bv,
				b;
	int			sign = 0;		/* Default positive */
	int			bitShift = 0;
B
Bruce Momjian 已提交
1433

B
Bruce Momjian 已提交
1434
	if (AH->version > K_VERS_1_0)
1435
		/* Read a sign byte */
B
Bruce Momjian 已提交
1436
		sign = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
1437

B
Bruce Momjian 已提交
1438 1439 1440
	for (b = 0; b < AH->intSize; b++)
	{
		bv = (*AH->ReadBytePtr) (AH) & 0xFF;
1441 1442 1443
		if (bv != 0)
			res = res + (bv << bitShift);
		bitShift += 8;
B
Bruce Momjian 已提交
1444
	}
B
Bruce Momjian 已提交
1445

B
Bruce Momjian 已提交
1446 1447
	if (sign)
		res = -res;
B
Bruce Momjian 已提交
1448

B
Bruce Momjian 已提交
1449
	return res;
B
Bruce Momjian 已提交
1450 1451
}

P
Peter Eisentraut 已提交
1452
size_t
1453
WriteStr(ArchiveHandle *AH, const char *c)
B
Bruce Momjian 已提交
1454
{
P
Peter Eisentraut 已提交
1455
	size_t		res;
1456 1457 1458 1459

	if (c)
	{
		res = WriteInt(AH, strlen(c));
B
Bruce Momjian 已提交
1460
		res += (*AH->WriteBufPtr) (AH, c, strlen(c));
1461 1462 1463 1464
	}
	else
		res = WriteInt(AH, -1);

B
Bruce Momjian 已提交
1465
	return res;
B
Bruce Momjian 已提交
1466 1467
}

B
Bruce Momjian 已提交
1468 1469
char *
ReadStr(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1470
{
B
Bruce Momjian 已提交
1471 1472
	char	   *buf;
	int			l;
B
Bruce Momjian 已提交
1473

B
Bruce Momjian 已提交
1474
	l = ReadInt(AH);
1475
	if (l < 0)
1476 1477 1478
		buf = NULL;
	else
	{
B
Bruce Momjian 已提交
1479
		buf = (char *) malloc(l + 1);
1480
		if (!buf)
1481
			die_horribly(AH, modulename, "out of memory\n");
1482

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

1486 1487
		buf[l] = '\0';
	}
B
Bruce Momjian 已提交
1488

B
Bruce Momjian 已提交
1489
	return buf;
B
Bruce Momjian 已提交
1490 1491
}

T
Tom Lane 已提交
1492
static int
B
Bruce Momjian 已提交
1493
_discoverArchiveFormat(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1494
{
B
Bruce Momjian 已提交
1495 1496
	FILE	   *fh;
	char		sig[6];			/* More than enough */
P
Peter Eisentraut 已提交
1497
	size_t		cnt;
B
Bruce Momjian 已提交
1498
	int			wantClose = 0;
B
Bruce Momjian 已提交
1499

1500
#if 0
1501
	write_msg(modulename, "attempting to ascertain archive format\n");
1502
#endif
1503 1504 1505 1506 1507 1508 1509 1510

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

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

B
Bruce Momjian 已提交
1512 1513
	if (AH->fSpec)
	{
1514 1515
		wantClose = 1;
		fh = fopen(AH->fSpec, PG_BINARY_R);
B
Bruce Momjian 已提交
1516 1517
	}
	else
1518
		fh = stdin;
B
Bruce Momjian 已提交
1519

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

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

B
Bruce Momjian 已提交
1525
	if (cnt != 5)
1526 1527 1528 1529
	{
		if (ferror(fh))
			die_horribly(AH, modulename, "could not read input file: %s\n", strerror(errno));
		else
P
Peter Eisentraut 已提交
1530 1531
			die_horribly(AH, modulename, "input file is too short (read %lu, expected 5)\n",
						 (unsigned long) cnt);
1532
	}
B
Bruce Momjian 已提交
1533

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

B
Bruce Momjian 已提交
1538
	if (strncmp(sig, "PGDMP", 5) == 0)
1539 1540 1541 1542 1543 1544 1545 1546 1547
	{
		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 已提交
1548 1549
		if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))		/* Version > 1.0 */
		{
1550 1551 1552 1553 1554 1555
			AH->vrev = fgetc(fh);
			AH->lookahead[AH->lookaheadLen++] = AH->vrev;
		}
		else
			AH->vrev = 0;

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

1559 1560 1561
		AH->intSize = fgetc(fh);
		AH->lookahead[AH->lookaheadLen++] = AH->intSize;

1562 1563 1564 1565 1566 1567 1568 1569
		if (AH->version >= K_VERS_1_7)
		{
			AH->offSize = fgetc(fh);
			AH->lookahead[AH->lookaheadLen++] = AH->offSize;
		}
		else
			AH->offSize = AH->intSize;

1570 1571
		AH->format = fgetc(fh);
		AH->lookahead[AH->lookaheadLen++] = AH->format;
B
Bruce Momjian 已提交
1572 1573 1574
	}
	else
	{
1575
		/*
B
Bruce Momjian 已提交
1576 1577
		 * *Maybe* we have a tar archive format file... So, read first 512
		 * byte header...
1578 1579 1580
		 */
		cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh);
		AH->lookaheadLen += cnt;
B
Bruce Momjian 已提交
1581

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

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

1588 1589
		AH->format = archTar;
	}
B
Bruce Momjian 已提交
1590

B
Bruce Momjian 已提交
1591
	/* If we can't seek, then mark the header as read */
P
Peter Eisentraut 已提交
1592
	if (fseeko(fh, 0, SEEK_SET) != 0)
1593 1594
	{
		/*
B
Bruce Momjian 已提交
1595 1596
		 * NOTE: Formats that use the lookahead buffer can unset this in their
		 * Init routine.
1597 1598 1599 1600
		 */
		AH->readHeader = 1;
	}
	else
B
Bruce Momjian 已提交
1601
		AH->lookaheadLen = 0;	/* Don't bother since we've reset the file */
1602

1603
#if 0
P
Peter Eisentraut 已提交
1604 1605
	write_msg(modulename, "read %lu bytes into lookahead buffer\n",
			  (unsigned long) AH->lookaheadLen);
1606
#endif
B
Bruce Momjian 已提交
1607

B
Bruce Momjian 已提交
1608 1609
	/* Close the file */
	if (wantClose)
1610
		if (fclose(fh) != 0)
1611
			die_horribly(AH, modulename, "could not close input file: %s\n",
1612
						 strerror(errno));
B
Bruce Momjian 已提交
1613

B
Bruce Momjian 已提交
1614
	return AH->format;
B
Bruce Momjian 已提交
1615 1616 1617 1618 1619 1620
}


/*
 * Allocate an archive handle
 */
B
Bruce Momjian 已提交
1621 1622 1623
static ArchiveHandle *
_allocAH(const char *FileSpec, const ArchiveFormat fmt,
		 const int compression, ArchiveMode mode)
1624
{
B
Bruce Momjian 已提交
1625
	ArchiveHandle *AH;
B
Bruce Momjian 已提交
1626

1627
#if 0
1628
	write_msg(modulename, "allocating AH for %s, format %d\n", FileSpec, fmt);
1629
#endif
1630

B
Bruce Momjian 已提交
1631 1632
	AH = (ArchiveHandle *) calloc(1, sizeof(ArchiveHandle));
	if (!AH)
1633
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
1634

1635 1636
	/* AH->debugLevel = 100; */

B
Bruce Momjian 已提交
1637 1638
	AH->vmaj = K_VERS_MAJOR;
	AH->vmin = K_VERS_MINOR;
1639
	AH->vrev = K_VERS_REV;
B
Bruce Momjian 已提交
1640

1641 1642 1643 1644 1645 1646 1647 1648
	/* initialize for backwards compatible string processing */
	AH->public.encoding = PG_SQL_ASCII;
	AH->public.std_strings = false;

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

1649 1650
	AH->createDate = time(NULL);

B
Bruce Momjian 已提交
1651
	AH->intSize = sizeof(int);
1652
	AH->offSize = sizeof(pgoff_t);
B
Bruce Momjian 已提交
1653 1654
	if (FileSpec)
	{
1655
		AH->fSpec = strdup(FileSpec);
B
Bruce Momjian 已提交
1656

1657 1658 1659
		/*
		 * Not used; maybe later....
		 *
1660 1661
		 * AH->workDir = strdup(FileSpec); for(i=strlen(FileSpec) ; i > 0 ;
		 * i--) if (AH->workDir[i-1] == '/')
1662
		 */
B
Bruce Momjian 已提交
1663 1664
	}
	else
1665
		AH->fSpec = NULL;
B
Bruce Momjian 已提交
1666

B
Bruce Momjian 已提交
1667 1668
	AH->currUser = strdup("");	/* So it's valid, but we can free() it later
								 * if necessary */
B
Bruce Momjian 已提交
1669
	AH->currSchema = strdup("");	/* ditto */
1670
	AH->currWithOids = -1;		/* force SET */
B
Bruce Momjian 已提交
1671

B
Bruce Momjian 已提交
1672 1673
	AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry));
	if (!AH->toc)
1674
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
1675

B
Bruce Momjian 已提交
1676 1677 1678 1679 1680
	AH->toc->next = AH->toc;
	AH->toc->prev = AH->toc;

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

1682 1683
	AH->pgCopyBuf = createPQExpBuffer();
	AH->sqlBuf = createPQExpBuffer();
B
Bruce Momjian 已提交
1684

B
Bruce Momjian 已提交
1685 1686 1687
	/* Open stdout with no compression for AH output handle */
	AH->gzOut = 0;
	AH->OF = stdout;
B
Bruce Momjian 已提交
1688

1689 1690
	/*
	 * On Windows, we need to use binary mode to read/write non-text archive
B
Bruce Momjian 已提交
1691 1692
	 * formats.  Force stdin/stdout into binary mode if that is what we are
	 * using.
1693 1694
	 */
#ifdef WIN32
1695 1696
	if (fmt != archNull &&
		(AH->fSpec == NULL || strcmp(AH->fSpec, "") == 0))
1697 1698 1699 1700 1701 1702 1703 1704
	{
		if (mode == archModeWrite)
			setmode(fileno(stdout), O_BINARY);
		else
			setmode(fileno(stdin), O_BINARY);
	}
#endif

1705
#if 0
1706
	write_msg(modulename, "archive format is %d\n", fmt);
1707
#endif
1708

B
Bruce Momjian 已提交
1709
	if (fmt == archUnknown)
1710 1711 1712
		AH->format = _discoverArchiveFormat(AH);
	else
		AH->format = fmt;
B
Bruce Momjian 已提交
1713

B
Bruce Momjian 已提交
1714 1715
	switch (AH->format)
	{
1716 1717 1718
		case archCustom:
			InitArchiveFmt_Custom(AH);
			break;
B
Bruce Momjian 已提交
1719

1720 1721 1722
		case archFiles:
			InitArchiveFmt_Files(AH);
			break;
B
Bruce Momjian 已提交
1723

1724 1725 1726
		case archNull:
			InitArchiveFmt_Null(AH);
			break;
B
Bruce Momjian 已提交
1727

1728 1729 1730 1731 1732
		case archTar:
			InitArchiveFmt_Tar(AH);
			break;

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

B
Bruce Momjian 已提交
1736
	return AH;
B
Bruce Momjian 已提交
1737 1738 1739
}


B
Bruce Momjian 已提交
1740 1741
void
WriteDataChunks(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1742
{
B
Bruce Momjian 已提交
1743 1744 1745
	TocEntry   *te = AH->toc->next;
	StartDataPtr startPtr;
	EndDataPtr	endPtr;
B
Bruce Momjian 已提交
1746

B
Bruce Momjian 已提交
1747 1748 1749
	while (te != AH->toc)
	{
		if (te->dataDumper != NULL)
1750
		{
B
Bruce Momjian 已提交
1751 1752
			AH->currToc = te;
			/* printf("Writing data for %d (%x)\n", te->id, te); */
1753

B
Bruce Momjian 已提交
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763
			if (strcmp(te->desc, "BLOBS") == 0)
			{
				startPtr = AH->StartBlobsPtr;
				endPtr = AH->EndBlobsPtr;
			}
			else
			{
				startPtr = AH->StartDataPtr;
				endPtr = AH->EndDataPtr;
			}
B
Bruce Momjian 已提交
1764

B
Bruce Momjian 已提交
1765 1766
			if (startPtr != NULL)
				(*startPtr) (AH, te);
B
Bruce Momjian 已提交
1767

B
Bruce Momjian 已提交
1768
			/*
B
Bruce Momjian 已提交
1769
			 * printf("Dumper arg for %d is %x\n", te->id, te->dataDumperArg);
B
Bruce Momjian 已提交
1770 1771 1772 1773 1774 1775
			 */

			/*
			 * The user-provided DataDumper routine needs to call
			 * AH->WriteData
			 */
1776
			(*te->dataDumper) ((Archive *) AH, te->dataDumperArg);
B
Bruce Momjian 已提交
1777 1778 1779 1780 1781

			if (endPtr != NULL)
				(*endPtr) (AH, te);
			AH->currToc = NULL;
		}
1782
		te = te->next;
B
Bruce Momjian 已提交
1783
	}
B
Bruce Momjian 已提交
1784 1785
}

B
Bruce Momjian 已提交
1786 1787
void
WriteToc(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1788
{
1789 1790
	TocEntry   *te;
	char		workbuf[32];
1791
	int			i;
B
Bruce Momjian 已提交
1792 1793 1794 1795

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

	WriteInt(AH, AH->tocCount);
1796 1797

	for (te = AH->toc->next; te != AH->toc; te = te->next)
B
Bruce Momjian 已提交
1798
	{
1799
		WriteInt(AH, te->dumpId);
B
Bruce Momjian 已提交
1800
		WriteInt(AH, te->dataDumper ? 1 : 0);
1801 1802 1803 1804 1805 1806

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

1808
		WriteStr(AH, te->tag);
B
Bruce Momjian 已提交
1809 1810 1811 1812
		WriteStr(AH, te->desc);
		WriteStr(AH, te->defn);
		WriteStr(AH, te->dropStmt);
		WriteStr(AH, te->copyStmt);
1813
		WriteStr(AH, te->namespace);
1814
		WriteStr(AH, te->tablespace);
B
Bruce Momjian 已提交
1815
		WriteStr(AH, te->owner);
1816
		WriteStr(AH, te->withOids ? "true" : "false");
1817 1818

		/* Dump list of dependencies */
1819
		for (i = 0; i < te->nDeps; i++)
1820
		{
1821 1822
			sprintf(workbuf, "%d", te->dependencies[i]);
			WriteStr(AH, workbuf);
1823
		}
1824
		WriteStr(AH, NULL);		/* Terminate List */
1825

B
Bruce Momjian 已提交
1826 1827 1828
		if (AH->WriteExtraTocPtr)
			(*AH->WriteExtraTocPtr) (AH, te);
	}
B
Bruce Momjian 已提交
1829 1830
}

B
Bruce Momjian 已提交
1831 1832
void
ReadToc(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1833
{
B
Bruce Momjian 已提交
1834
	int			i;
1835 1836
	char	   *tmp;
	DumpId	   *deps;
1837 1838
	int			depIdx;
	int			depSize;
B
Bruce Momjian 已提交
1839

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

B
Bruce Momjian 已提交
1842
	AH->tocCount = ReadInt(AH);
1843
	AH->maxDumpId = 0;
B
Bruce Momjian 已提交
1844

B
Bruce Momjian 已提交
1845 1846 1847
	for (i = 0; i < AH->tocCount; i++)
	{
		te = (TocEntry *) calloc(1, sizeof(TocEntry));
1848 1849 1850 1851
		te->dumpId = ReadInt(AH);

		if (te->dumpId > AH->maxDumpId)
			AH->maxDumpId = te->dumpId;
1852 1853

		/* Sanity check */
1854 1855
		if (te->dumpId <= 0)
			die_horribly(AH, modulename,
B
Bruce Momjian 已提交
1856
					   "entry ID %d out of range -- perhaps a corrupt TOC\n",
1857
						 te->dumpId);
1858 1859

		te->hadDumper = ReadInt(AH);
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871

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

1873
		te->tag = ReadStr(AH);
1874 1875 1876 1877 1878 1879 1880
		te->desc = ReadStr(AH);
		te->defn = ReadStr(AH);
		te->dropStmt = ReadStr(AH);

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

1881 1882 1883
		if (AH->version >= K_VERS_1_6)
			te->namespace = ReadStr(AH);

1884 1885 1886
		if (AH->version >= K_VERS_1_10)
			te->tablespace = ReadStr(AH);

1887
		te->owner = ReadStr(AH);
1888 1889 1890 1891 1892 1893 1894 1895 1896
		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 已提交
1897

1898 1899 1900 1901
		/* Read TOC entry dependencies */
		if (AH->version >= K_VERS_1_5)
		{
			depSize = 100;
1902
			deps = (DumpId *) malloc(sizeof(DumpId) * depSize);
1903
			depIdx = 0;
1904
			for (;;)
1905
			{
1906 1907 1908
				tmp = ReadStr(AH);
				if (!tmp)
					break;		/* end of list */
1909
				if (depIdx >= depSize)
1910 1911
				{
					depSize *= 2;
1912
					deps = (DumpId *) realloc(deps, sizeof(DumpId) * depSize);
1913
				}
1914 1915 1916 1917
				sscanf(tmp, "%d", &deps[depIdx]);
				free(tmp);
				depIdx++;
			}
1918

1919 1920 1921 1922 1923 1924
			if (depIdx > 0)		/* We have a non-null entry */
			{
				deps = (DumpId *) realloc(deps, sizeof(DumpId) * depIdx);
				te->dependencies = deps;
				te->nDeps = depIdx;
			}
1925
			else
1926 1927
			{
				free(deps);
1928 1929
				te->dependencies = NULL;
				te->nDeps = 0;
1930
			}
1931
		}
1932
		else
1933 1934 1935 1936
		{
			te->dependencies = NULL;
			te->nDeps = 0;
		}
1937

B
Bruce Momjian 已提交
1938 1939
		if (AH->ReadExtraTocPtr)
			(*AH->ReadExtraTocPtr) (AH, te);
1940

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

1944
		/* link completed entry into TOC circular list */
1945 1946 1947 1948
		te->prev = AH->toc->prev;
		AH->toc->prev->next = te;
		AH->toc->prev = te;
		te->next = AH->toc;
1949 1950 1951 1952 1953 1954

		/* 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 已提交
1955
	}
B
Bruce Momjian 已提交
1956 1957
}

1958 1959 1960 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 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001
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);
}

2002
static teReqs
2003
_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
B
Bruce Momjian 已提交
2004
{
2005
	teReqs		res = REQ_ALL;
B
Bruce Momjian 已提交
2006

2007 2008 2009
	/* ENCODING and STDSTRINGS items are dumped specially, so always reject */
	if (strcmp(te->desc, "ENCODING") == 0 ||
		strcmp(te->desc, "STDSTRINGS") == 0)
2010
		return 0;
2011

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

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

2019 2020 2021 2022 2023 2024 2025 2026 2027 2028
	/* 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 已提交
2029 2030
	if (ropt->selTypes)
	{
2031 2032
		if (strcmp(te->desc, "TABLE") == 0 ||
			strcmp(te->desc, "TABLE DATA") == 0)
2033 2034 2035
		{
			if (!ropt->selTable)
				return 0;
2036
			if (ropt->tableNames && strcmp(ropt->tableNames, te->tag) != 0)
2037
				return 0;
B
Bruce Momjian 已提交
2038 2039 2040
		}
		else if (strcmp(te->desc, "INDEX") == 0)
		{
2041 2042
			if (!ropt->selIndex)
				return 0;
2043
			if (ropt->indexNames && strcmp(ropt->indexNames, te->tag) != 0)
2044
				return 0;
B
Bruce Momjian 已提交
2045 2046 2047
		}
		else if (strcmp(te->desc, "FUNCTION") == 0)
		{
2048 2049
			if (!ropt->selFunction)
				return 0;
2050
			if (ropt->functionNames && strcmp(ropt->functionNames, te->tag) != 0)
2051
				return 0;
B
Bruce Momjian 已提交
2052 2053 2054
		}
		else if (strcmp(te->desc, "TRIGGER") == 0)
		{
2055 2056
			if (!ropt->selTrigger)
				return 0;
2057
			if (ropt->triggerNames && strcmp(ropt->triggerNames, te->tag) != 0)
2058 2059
				return 0;
		}
B
Bruce Momjian 已提交
2060 2061
		else
			return 0;
B
Bruce Momjian 已提交
2062 2063
	}

2064
	/*
B
Bruce Momjian 已提交
2065
	 * Check if we had a dataDumper. Indicates if the entry is schema or data
2066 2067 2068 2069
	 */
	if (!te->hadDumper)
	{
		/*
B
Bruce Momjian 已提交
2070
		 * Special Case: If 'SEQUENCE SET' then it is considered a data entry
2071 2072 2073 2074
		 */
		if (strcmp(te->desc, "SEQUENCE SET") == 0)
			res = res & REQ_DATA;
		else
2075 2076
			res = res & ~REQ_DATA;
	}
2077

2078
	/*
B
Bruce Momjian 已提交
2079 2080
	 * Special case: <Init> type with <Max OID> tag; this is obsolete and we
	 * always ignore it.
2081
	 */
2082
	if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
2083
		return 0;
2084

B
Bruce Momjian 已提交
2085 2086
	/* Mask it if we only want schema */
	if (ropt->schemaOnly)
2087
		res = res & REQ_SCHEMA;
B
Bruce Momjian 已提交
2088

B
Bruce Momjian 已提交
2089
	/* Mask it we only want data */
2090
	if (ropt->dataOnly)
2091
		res = res & REQ_DATA;
B
Bruce Momjian 已提交
2092

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

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

B
Bruce Momjian 已提交
2101
	return res;
B
Bruce Momjian 已提交
2102 2103
}

2104 2105 2106 2107 2108 2109 2110
/*
 * 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)
{
2111 2112 2113
	/* Select the correct character set encoding */
	ahprintf(AH, "SET client_encoding = '%s';\n",
			 pg_encoding_to_char(AH->public.encoding));
2114

2115 2116 2117
	/* Select the correct string literal syntax */
	ahprintf(AH, "SET standard_conforming_strings = %s;\n",
			 AH->public.std_strings ? "on" : "off");
2118 2119 2120 2121

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

2122 2123
	/* Avoid annoying notices etc */
	ahprintf(AH, "SET client_min_messages = warning;\n");
2124 2125
	if (!AH->public.std_strings)
		ahprintf(AH, "SET escape_string_warning = off;\n");
2126

2127 2128 2129
	ahprintf(AH, "\n");
}

2130 2131
/*
 * Issue a SET SESSION AUTHORIZATION command.  Caller is responsible
2132 2133
 * for updating state if appropriate.  If user is NULL or an empty string,
 * the specification DEFAULT will be used.
2134 2135
 */
static void
2136
_doSetSessionAuth(ArchiveHandle *AH, const char *user)
2137
{
2138
	PQExpBuffer cmd = createPQExpBuffer();
B
Bruce Momjian 已提交
2139

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

2142 2143 2144 2145
	/*
	 * SQL requires a string literal here.	Might as well be correct.
	 */
	if (user && *user)
2146
		appendStringLiteralAHX(cmd, user, AH);
2147 2148 2149 2150
	else
		appendPQExpBuffer(cmd, "DEFAULT");
	appendPQExpBuffer(cmd, ";");

2151 2152 2153 2154
	if (RestoringToDB(AH))
	{
		PGresult   *res;

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2158
			/* NOT warn_or_die_horribly... use -O instead to skip this. */
2159
			die_horribly(AH, modulename, "could not set session user to \"%s\": %s",
2160
						 user, PQerrorMessage(AH->connection));
2161 2162 2163 2164

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

	destroyPQExpBuffer(cmd);
2168 2169
}

2170

2171 2172 2173 2174 2175 2176 2177 2178 2179 2180
/*
 * 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 已提交
2181
					  "true" : "false");
2182 2183 2184 2185 2186 2187 2188 2189

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

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
2190
			warn_or_die_horribly(AH, modulename,
2191 2192
								 "could not set default_with_oids: %s",
								 PQerrorMessage(AH->connection));
2193 2194 2195 2196 2197 2198 2199 2200 2201 2202

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

	destroyPQExpBuffer(cmd);
}


2203
/*
2204
 * Issue the commands to connect to the specified database.
2205 2206
 *
 * If we're currently restoring right into a database, this will
B
Bruce Momjian 已提交
2207
 * actually establish a connection. Otherwise it puts a \connect into
2208
 * the script output.
2209 2210
 *
 * NULL dbname implies reconnecting to the current DB (pretty useless).
2211
 */
B
Bruce Momjian 已提交
2212
static void
2213
_reconnectToDB(ArchiveHandle *AH, const char *dbname)
2214
{
2215
	if (RestoringToDB(AH))
2216
		ReconnectToServer(AH, dbname, NULL);
2217
	else
2218 2219 2220
	{
		PQExpBuffer qry = createPQExpBuffer();

2221
		appendPQExpBuffer(qry, "\\connect %s\n\n",
2222
						  dbname ? fmtId(dbname) : "-");
2223
		ahprintf(AH, "%s", qry->data);
2224 2225
		destroyPQExpBuffer(qry);
	}
2226

2227
	/*
B
Bruce Momjian 已提交
2228 2229
	 * NOTE: currUser keeps track of what the imaginary session user in our
	 * script is.  It's now effectively reset to the original userID.
2230
	 */
2231 2232 2233
	if (AH->currUser)
		free(AH->currUser);

2234
	AH->currUser = strdup("");
2235 2236 2237 2238 2239

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

2242 2243
	/* re-establish fixed state */
	_doSetFixedOutputState(AH);
2244 2245
}

2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262
/*
 * 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 已提交
2263 2264
	 * NOTE: currUser keeps track of what the imaginary session user in our
	 * script is
2265 2266 2267 2268 2269 2270
	 */
	if (AH->currUser)
		free(AH->currUser);

	AH->currUser = strdup(user);
}
2271 2272

/*
B
Bruce Momjian 已提交
2273
 * Become the owner of the the given TOC entry object.	If
2274 2275
 * changes in ownership are not allowed, this doesn't do anything.
 */
B
Bruce Momjian 已提交
2276
static void
2277
_becomeOwner(ArchiveHandle *AH, TocEntry *te)
2278
{
2279
	if (AH->ropt && (AH->ropt->noOwner || !AH->ropt->use_setsessauth))
2280 2281
		return;

2282
	_becomeUser(AH, te->owner);
2283 2284
}

2285

2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299
/*
 * 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;
	}
}


2300 2301 2302 2303 2304 2305 2306
/*
 * Issue the commands to select the specified schema as the current schema
 * in the target database.
 */
static void
_selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
{
2307 2308
	PQExpBuffer qry;

2309
	if (!schemaName || *schemaName == '\0' ||
2310
		(AH->currSchema && strcmp(AH->currSchema, schemaName) == 0))
2311 2312
		return;					/* no need to do anything */

2313 2314 2315
	qry = createPQExpBuffer();

	appendPQExpBuffer(qry, "SET search_path = %s",
2316
					  fmtId(schemaName));
2317 2318 2319
	if (strcmp(schemaName, "pg_catalog") != 0)
		appendPQExpBuffer(qry, ", pg_catalog");

2320 2321 2322 2323 2324 2325 2326
	if (RestoringToDB(AH))
	{
		PGresult   *res;

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
2327
			warn_or_die_horribly(AH, modulename,
B
Bruce Momjian 已提交
2328 2329
								 "could not set search_path to \"%s\": %s",
								 schemaName, PQerrorMessage(AH->connection));
2330 2331 2332 2333

		PQclear(res);
	}
	else
2334
		ahprintf(AH, "%s;\n\n", qry->data);
2335 2336 2337 2338

	if (AH->currSchema)
		free(AH->currSchema);
	AH->currSchema = strdup(schemaName);
2339 2340

	destroyPQExpBuffer(qry);
2341 2342
}

2343 2344 2345 2346 2347 2348 2349 2350
/*
 * 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 已提交
2351 2352
	const char *want,
			   *have;
2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383

	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 已提交
2384
			warn_or_die_horribly(AH, modulename,
2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398
								 "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);
}
2399

2400 2401 2402 2403 2404 2405 2406 2407
/*
 * 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.
2408
 */
2409
static void
2410
_getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
2411
{
2412 2413 2414
	const char *type = te->desc;

	/* Use ALTER TABLE for views and sequences */
2415
	if (strcmp(type, "VIEW") == 0 || strcmp(type, "SEQUENCE") == 0)
2416 2417 2418 2419 2420 2421
		type = "TABLE";

	/* objects named by a schema and name */
	if (strcmp(type, "CONVERSION") == 0 ||
		strcmp(type, "DOMAIN") == 0 ||
		strcmp(type, "TABLE") == 0 ||
2422 2423 2424
		strcmp(type, "TYPE") == 0 ||
		strcmp(type, "TEXT SEARCH DICTIONARY") == 0 ||
		strcmp(type, "TEXT SEARCH CONFIGURATION") == 0)
2425
	{
2426
		appendPQExpBuffer(buf, "%s ", type);
B
Bruce Momjian 已提交
2427
		if (te->namespace && te->namespace[0])	/* is null pre-7.3 */
2428
			appendPQExpBuffer(buf, "%s.", fmtId(te->namespace));
B
Bruce Momjian 已提交
2429

2430
		/*
B
Bruce Momjian 已提交
2431 2432 2433
		 * 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.
2434 2435 2436
		 */
		if (AH->version < K_VERS_1_7 &&
			te->tag[0] == '"' &&
B
Bruce Momjian 已提交
2437
			te->tag[strlen(te->tag) - 1] == '"' &&
2438 2439 2440 2441
			strcmp(type, "INDEX") == 0)
			appendPQExpBuffer(buf, "%s", te->tag);
		else
			appendPQExpBuffer(buf, "%s", fmtId(te->tag));
2442 2443
		return;
	}
2444

2445 2446
	/* objects named by just a name */
	if (strcmp(type, "DATABASE") == 0 ||
2447
		strcmp(type, "PROCEDURAL LANGUAGE") == 0 ||
2448 2449 2450 2451 2452
		strcmp(type, "SCHEMA") == 0)
	{
		appendPQExpBuffer(buf, "%s %s", type, fmtId(te->tag));
		return;
	}
2453

B
Bruce Momjian 已提交
2454
	/*
B
Bruce Momjian 已提交
2455 2456
	 * These object types require additional decoration.  Fortunately, the
	 * information needed is exactly what's in the DROP command.
B
Bruce Momjian 已提交
2457
	 */
2458 2459 2460
	if (strcmp(type, "AGGREGATE") == 0 ||
		strcmp(type, "FUNCTION") == 0 ||
		strcmp(type, "OPERATOR") == 0 ||
2461 2462
		strcmp(type, "OPERATOR CLASS") == 0 ||
		strcmp(type, "OPERATOR FAMILY") == 0)
B
Bruce Momjian 已提交
2463
	{
2464 2465 2466
		/* Chop "DROP " off the front and make a modifiable copy */
		char	   *first = strdup(te->dropStmt + 5);
		char	   *last;
2467

2468 2469
		/* point to last character in string */
		last = first + strlen(first) - 1;
2470

2471 2472 2473 2474
		/* Strip off any ';' or '\n' at the end */
		while (last >= first && (*last == '\n' || *last == ';'))
			last--;
		*(last + 1) = '\0';
B
Bruce Momjian 已提交
2475

2476
		appendPQExpBufferStr(buf, first);
B
Bruce Momjian 已提交
2477 2478

		free(first);
2479
		return;
2480 2481
	}

2482 2483
	write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n",
			  type);
2484 2485 2486
}

static void
2487
_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass)
B
Bruce Momjian 已提交
2488
{
2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502
	/* 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 已提交
2503 2504
	 * unless we are using --clean mode, in which case it's been deleted and
	 * we'd better recreate it.
2505 2506 2507 2508 2509
	 */
	if (!ropt->dropSchema &&
		strcmp(te->desc, "SCHEMA") == 0 && strcmp(te->tag, "public") == 0)
		return;

2510
	/* Select owner, schema, and tablespace as necessary */
2511 2512
	_becomeOwner(AH, te);
	_selectOutputSchema(AH, te->namespace);
2513
	_selectTablespace(AH, te->tablespace);
2514 2515 2516 2517 2518 2519

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

	/* Emit header comment for item */
2520
	if (!AH->noTocComments)
2521
	{
2522 2523 2524 2525 2526 2527 2528 2529 2530
		const char *pfx;

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

		ahprintf(AH, "--\n");
		if (AH->public.verbose)
2531
		{
2532 2533 2534 2535 2536
			ahprintf(AH, "-- TOC entry %d (class %u OID %u)\n",
					 te->dumpId, te->catalogId.tableoid, te->catalogId.oid);
			if (te->nDeps > 0)
			{
				int			i;
2537

2538 2539 2540 2541 2542
				ahprintf(AH, "-- Dependencies:");
				for (i = 0; i < te->nDeps; i++)
					ahprintf(AH, " %d", te->dependencies[i]);
				ahprintf(AH, "\n");
			}
2543
		}
2544
		ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s",
2545 2546
				 pfx, te->tag, te->desc,
				 te->namespace ? te->namespace : "-",
2547
				 ropt->noOwner ? "-" : te->owner);
B
Bruce Momjian 已提交
2548
		if (te->tablespace)
2549 2550 2551
			ahprintf(AH, "; Tablespace: %s", te->tablespace);
		ahprintf(AH, "\n");

B
Bruce Momjian 已提交
2552
		if (AH->PrintExtraTocPtr !=NULL)
2553 2554
			(*AH->PrintExtraTocPtr) (AH, te);
		ahprintf(AH, "--\n\n");
2555
	}
B
Bruce Momjian 已提交
2556

2557 2558 2559
	/*
	 * Actually print the definition.
	 *
B
Bruce Momjian 已提交
2560 2561 2562
	 * 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 ...
2563
	 */
2564
	if (ropt->noOwner && strcmp(te->desc, "SCHEMA") == 0)
2565
	{
2566
		ahprintf(AH, "CREATE SCHEMA %s;\n\n\n", fmtId(te->tag));
2567
	}
2568
	else
2569
	{
2570 2571
		if (strlen(te->defn) > 0)
			ahprintf(AH, "%s\n\n", te->defn);
2572
	}
2573 2574 2575

	/*
	 * If we aren't using SET SESSION AUTH to determine ownership, we must
2576 2577 2578
	 * 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.
2579 2580
	 */
	if (!ropt->noOwner && !ropt->use_setsessauth &&
2581 2582 2583 2584 2585 2586 2587 2588 2589
		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 ||
2590
			strcmp(te->desc, "OPERATOR FAMILY") == 0 ||
2591
			strcmp(te->desc, "PROCEDURAL LANGUAGE") == 0 ||
2592 2593 2594 2595
			strcmp(te->desc, "SCHEMA") == 0 ||
			strcmp(te->desc, "TABLE") == 0 ||
			strcmp(te->desc, "TYPE") == 0 ||
			strcmp(te->desc, "VIEW") == 0 ||
2596 2597 2598
			strcmp(te->desc, "SEQUENCE") == 0 ||
			strcmp(te->desc, "TEXT SEARCH DICTIONARY") == 0 ||
			strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0)
2599 2600 2601 2602
		{
			PQExpBuffer temp = createPQExpBuffer();

			appendPQExpBuffer(temp, "ALTER ");
2603
			_getObjectDescription(temp, te, AH);
2604 2605 2606 2607 2608 2609
			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 ||
2610
				 strcmp(te->desc, "CONSTRAINT") == 0 ||
2611 2612
				 strcmp(te->desc, "DEFAULT") == 0 ||
				 strcmp(te->desc, "FK CONSTRAINT") == 0 ||
2613
				 strcmp(te->desc, "INDEX") == 0 ||
2614 2615 2616 2617 2618 2619 2620 2621 2622 2623
				 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);
		}
2624
	}
B
Bruce Momjian 已提交
2625

2626 2627
	/*
	 * If it's an ACL entry, it might contain SET SESSION AUTHORIZATION
B
Bruce Momjian 已提交
2628
	 * commands, so we can no longer assume we know the current auth setting.
2629 2630 2631 2632 2633 2634 2635
	 */
	if (strncmp(te->desc, "ACL", 3) == 0)
	{
		if (AH->currUser)
			free(AH->currUser);
		AH->currUser = NULL;
	}
B
Bruce Momjian 已提交
2636 2637
}

B
Bruce Momjian 已提交
2638 2639
void
WriteHead(ArchiveHandle *AH)
B
Bruce Momjian 已提交
2640
{
B
Bruce Momjian 已提交
2641
	struct tm	crtm;
2642

B
Bruce Momjian 已提交
2643 2644 2645 2646 2647
	(*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);
2648
	(*AH->WriteBytePtr) (AH, AH->offSize);
B
Bruce Momjian 已提交
2649
	(*AH->WriteBytePtr) (AH, AH->format);
B
Bruce Momjian 已提交
2650

2651
#ifndef HAVE_LIBZ
B
Bruce Momjian 已提交
2652
	if (AH->compression != 0)
2653
		write_msg(modulename, "WARNING: requested compression not available in this "
2654
				  "installation -- archive will be uncompressed\n");
B
Bruce Momjian 已提交
2655

B
Bruce Momjian 已提交
2656
	AH->compression = 0;
2657
#endif
B
Bruce Momjian 已提交
2658

2659 2660 2661 2662 2663 2664 2665 2666 2667 2668
	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);
2669
	WriteStr(AH, PQdb(AH->connection));
2670 2671
	WriteStr(AH, AH->public.remoteVersionStr);
	WriteStr(AH, PG_VERSION);
B
Bruce Momjian 已提交
2672 2673
}

B
Bruce Momjian 已提交
2674 2675
void
ReadHead(ArchiveHandle *AH)
B
Bruce Momjian 已提交
2676
{
B
Bruce Momjian 已提交
2677 2678
	char		tmpMag[7];
	int			fmt;
2679
	struct tm	crtm;
B
Bruce Momjian 已提交
2680

2681
	/* If we haven't already read the header... */
B
Bruce Momjian 已提交
2682 2683
	if (!AH->readHeader)
	{
2684 2685
		if ((*AH->ReadBufPtr) (AH, tmpMag, 5) != 5)
			die_horribly(AH, modulename, "unexpected end of file\n");
B
Bruce Momjian 已提交
2686

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

B
Bruce Momjian 已提交
2690 2691
		AH->vmaj = (*AH->ReadBytePtr) (AH);
		AH->vmin = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
2692

B
Bruce Momjian 已提交
2693 2694 2695
		if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))		/* Version > 1.0 */
			AH->vrev = (*AH->ReadBytePtr) (AH);
		else
2696
			AH->vrev = 0;
B
Bruce Momjian 已提交
2697

B
Bruce Momjian 已提交
2698
		AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
B
Bruce Momjian 已提交
2699 2700


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

B
Bruce Momjian 已提交
2705
		AH->intSize = (*AH->ReadBytePtr) (AH);
2706
		if (AH->intSize > 32)
P
Peter Eisentraut 已提交
2707 2708
			die_horribly(AH, modulename, "sanity check on integer size (%lu) failed\n",
						 (unsigned long) AH->intSize);
B
Bruce Momjian 已提交
2709

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

2713
		if (AH->version >= K_VERS_1_7)
B
Bruce Momjian 已提交
2714
			AH->offSize = (*AH->ReadBytePtr) (AH);
2715
		else
B
Bruce Momjian 已提交
2716
			AH->offSize = AH->intSize;
2717

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

2720
		if (AH->format != fmt)
2721 2722
			die_horribly(AH, modulename, "expected format (%d) differs from format found in file (%d)\n",
						 AH->format, fmt);
B
Bruce Momjian 已提交
2723
	}
B
Bruce Momjian 已提交
2724

B
Bruce Momjian 已提交
2725 2726
	if (AH->version >= K_VERS_1_2)
	{
2727
		if (AH->version < K_VERS_1_4)
B
Bruce Momjian 已提交
2728
			AH->compression = (*AH->ReadBytePtr) (AH);
2729 2730
		else
			AH->compression = ReadInt(AH);
B
Bruce Momjian 已提交
2731 2732
	}
	else
2733
		AH->compression = Z_DEFAULT_COMPRESSION;
B
Bruce Momjian 已提交
2734

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

2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753
	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 已提交
2754
		if (AH->createDate == (time_t) -1)
2755
			write_msg(modulename, "WARNING: invalid creation date in header\n");
2756 2757
	}

2758 2759 2760 2761 2762 2763
	if (AH->version >= K_VERS_1_10)
	{
		AH->archiveRemoteVersion = ReadStr(AH);
		AH->archiveDumpVersion = ReadStr(AH);
	}

B
Bruce Momjian 已提交
2764 2765 2766
}


2767 2768 2769 2770 2771 2772 2773 2774 2775
/*
 * checkSeek
 *	  check to see if fseek can be performed.
 */

bool
checkSeek(FILE *fp)
{

B
Bruce Momjian 已提交
2776
	if (fseeko(fp, 0, SEEK_CUR) != 0)
2777
		return false;
2778
	else if (sizeof(pgoff_t) > sizeof(long))
B
Bruce Momjian 已提交
2779 2780

		/*
2781 2782
		 * 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 已提交
2783
		 */
2784 2785 2786 2787 2788 2789 2790 2791
#ifdef HAVE_FSEEKO
		return true;
#else
		return false;
#endif
	else
		return true;
}
2792 2793 2794 2795 2796 2797 2798 2799 2800 2801


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

2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814
	/*
	 * We don't print the timezone on Win32, because the names are long and
	 * localized, which means they may contain characters in various random
	 * encodings; this has been seen to cause encoding errors when reading
	 * the dump script.
	 */
	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)
2815 2816
		ahprintf(AH, "-- %s %s\n\n", msg, buf);
}