pg_backup_archiver.c 63.5 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.106 2005/03/18 17:32:55 tgl Exp $
19
 *
B
Bruce Momjian 已提交
20 21 22 23
 *-------------------------------------------------------------------------
 */

#include "pg_backup.h"
24
#include "pg_dump.h"
B
Bruce Momjian 已提交
25
#include "pg_backup_archiver.h"
26
#include "pg_backup_db.h"
27
#include "dumputils.h"
28

29
#include <ctype.h>
30
#include <unistd.h>
B
Bruce Momjian 已提交
31

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

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

39

40
const char *progname;
41

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


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

51

52
static void fixPriorBlobRefs(ArchiveHandle *AH, TocEntry *blobte,
B
Bruce Momjian 已提交
53
				 RestoreOptions *ropt);
54
static void _doSetFixedOutputState(ArchiveHandle *AH);
55
static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
56
static void _doSetWithOids(ArchiveHandle *AH, const bool withOids);
57
static void _reconnectToDB(ArchiveHandle *AH, const char *dbname);
58 59
static void _becomeUser(ArchiveHandle *AH, const char *user);
static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
60
static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
61
static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
62

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

70 71
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);
72

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

76

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


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

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

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

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

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

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

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

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

	if (res != 0)
124
		die_horribly(AH, modulename, "could not close output archive file\n");
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 132
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *te = AH->toc->next;
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 144
	/*
	 * Check for nonsensical option combinations.
	 *
	 * NB: create+dropSchema is useless because if you're creating the DB,
	 * there's no need to drop individual items in it.  Moreover, if we
145 146 147
	 * 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...
148 149 150 151
	 */
	if (ropt->create && ropt->dropSchema)
		die_horribly(AH, modulename, "-C and -c are incompatible options\n");

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

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

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

		/*
		 * If we're talking to the DB directly, don't send comments since
		 * they obscure SQL when displaying errors
		 */
173
		AH->noTocComments = 1;
174 175
	}

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

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

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

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

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

218 219
	AH->stage = STAGE_PROCESSING;

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

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

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

253
		/* Work out what, if anything, we want from this entry */
254
		reqs = _tocEntryRequired(te, ropt, false);
255

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

265 266
		defnDumped = false;

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

271
			_printTocEntry(AH, te, ropt, false, false);
272
			defnDumped = true;
273 274

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

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

305
					_printTocEntry(AH, te, ropt, true, false);
306 307

					/*
308 309
					 * Maybe we can't do BLOBS, so check if this node is
					 * for BLOBS
310
					 */
311 312
					if ((strcmp(te->desc, "BLOBS") == 0) &&
						!_canRestoreBlobs(AH))
313 314 315 316
					{
						ahprintf(AH, "--\n-- SKIPPED \n--\n\n");

						/*
317 318 319
						 * This is a bit nasty - we assume, for the
						 * moment, that if a custom output is used, then
						 * we don't want warnings.
320 321
						 */
						if (!AH->CustomOutPtr)
322
							write_msg(modulename, "WARNING: skipping large-object restoration\n");
323 324 325 326 327
					}
					else
					{
						_disableTriggersIfNecessary(AH, te, ropt);

328 329
						/* Select owner and schema as necessary */
						_becomeOwner(AH, te);
330
						_selectOutputSchema(AH, te->namespace);
331

332
						ahlog(AH, 1, "restoring data for table \"%s\"\n", te->tag);
333 334

						/*
335 336 337 338 339
						 * 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.
340
						 *
341 342 343
						 * For V1.3+, the table data MUST have a copy
						 * statement so that we can go into appropriate
						 * mode with libpq.
344 345 346 347 348 349
						 */
						if (te->copyStmt && strlen(te->copyStmt) > 0)
							ahprintf(AH, te->copyStmt);

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

350 351 352 353
						/*
						 * If we just restored blobs, fix references in
						 * previously-loaded tables; otherwise, if we
						 * previously restored blobs, fix references in
B
Bruce Momjian 已提交
354 355 356 357
						 * this table.	Note that in standard cases the
						 * BLOBS entry comes after all TABLE DATA entries,
						 * but we should cope with other orders in case
						 * the user demands reordering.
358 359 360 361 362 363 364 365 366 367
						 */
						if (strcmp(te->desc, "BLOBS") == 0)
							fixPriorBlobRefs(AH, te, ropt);
						else if (AH->createdBlobXref &&
								 strcmp(te->desc, "TABLE DATA") == 0)
						{
							ahlog(AH, 1, "fixing up large-object cross-reference for \"%s\"\n", te->tag);
							FixupBlobRefs(AH, te);
						}

368 369 370
						_enableTriggersIfNecessary(AH, te, ropt);
					}
				}
371 372 373 374
			}
			else if (!defnDumped)
			{
				/* If we haven't already dumped the defn part, do so now */
375
				ahlog(AH, 1, "executing %s %s\n", te->desc, te->tag);
376
				_printTocEntry(AH, te, ropt, false, false);
377 378 379
			}
		}
		te = te->next;
B
Bruce Momjian 已提交
380
	}							/* end loop over TOC entries */
B
Bruce Momjian 已提交
381

382 383 384 385 386 387
	/*
	 * Scan TOC again to output ownership commands and ACLs
	 */
	te = AH->toc->next;
	while (te != AH->toc)
	{
388 389
		AH->currentTE = te;

390 391 392 393 394
		/* 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 已提交
395
			ahlog(AH, 1, "setting owner and privileges for %s %s\n",
396
				  te->desc, te->tag);
397 398 399 400 401 402
			_printTocEntry(AH, te, ropt, false, true);
		}

		te = te->next;
	}

403 404
	ahprintf(AH, "--\n-- PostgreSQL database dump complete\n--\n\n");

405
	/*
406
	 * Clean up & we're done.
407
	 */
408 409
	AH->stage = STAGE_FINALIZING;

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
	if (ropt->filename || ropt->compression)
		ResetOutput(AH, sav);

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

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

/*
 * After restoring BLOBS, fix all blob references in previously-restored
B
Bruce Momjian 已提交
428
 * tables.	(Normally, the BLOBS entry should appear after all TABLE DATA
429 430 431 432 433 434 435 436 437
 * entries, so this will in fact handle all blob references.)
 */
static void
fixPriorBlobRefs(ArchiveHandle *AH, TocEntry *blobte, RestoreOptions *ropt)
{
	TocEntry   *te;
	teReqs		reqs;

	if (AH->createdBlobXref)
438
	{
439
		/* NULL parameter means disable ALL user triggers */
440
		_disableTriggersIfNecessary(AH, NULL, ropt);
441

442
		for (te = AH->toc->next; te != blobte; te = te->next)
B
Bruce Momjian 已提交
443 444 445
		{
			if (strcmp(te->desc, "TABLE DATA") == 0)
			{
446
				reqs = _tocEntryRequired(te, ropt, false);
447

448
				if ((reqs & REQ_DATA) != 0)		/* We loaded the data */
449
				{
450
					ahlog(AH, 1, "fixing up large-object cross-reference for \"%s\"\n", te->tag);
451
					FixupBlobRefs(AH, te);
452 453 454
				}
			}
		}
455 456

		/* NULL parameter means enable ALL user triggers */
457
		_enableTriggersIfNecessary(AH, NULL, ropt);
458
	}
B
Bruce Momjian 已提交
459 460
}

461 462 463 464
/*
 * Allocate a new RestoreOptions block.
 * This is mainly so we can initialize it, but also for future expansion,
 */
B
Bruce Momjian 已提交
465 466
RestoreOptions *
NewRestoreOptions(void)
B
Bruce Momjian 已提交
467
{
B
Bruce Momjian 已提交
468
	RestoreOptions *opts;
B
Bruce Momjian 已提交
469

B
Bruce Momjian 已提交
470
	opts = (RestoreOptions *) calloc(1, sizeof(RestoreOptions));
B
Bruce Momjian 已提交
471 472

	opts->format = archUnknown;
473
	opts->suppressDumpWarnings = false;
474
	opts->exit_on_error = false;
B
Bruce Momjian 已提交
475 476 477 478

	return opts;
}

479 480 481 482
/*
 * Returns true if we're restoring directly to the database (and
 * aren't just making a psql script that can do the restoration).
 */
B
Bruce Momjian 已提交
483 484
static int
_restoringToDB(ArchiveHandle *AH)
485 486 487 488
{
	return (AH->ropt->useDB && AH->connection);
}

B
Bruce Momjian 已提交
489 490
static int
_canRestoreBlobs(ArchiveHandle *AH)
491 492 493 494
{
	return _restoringToDB(AH);
}

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

502 503 504 505
	/* Don't do it for the BLOBS TocEntry, either */
	if (te && strcmp(te->desc, "BLOBS") == 0)
		return;

506
	/*
B
Bruce Momjian 已提交
507
	 * Become superuser if possible, since they are the only ones who can
B
Bruce Momjian 已提交
508 509
	 * update pg_class.  If -S was not given, assume the initial user
	 * identity is a superuser.
510
	 */
511
	_becomeUser(AH, ropt->superuser);
512

513
	ahlog(AH, 1, "disabling triggers\n");
514 515

	/*
B
Bruce Momjian 已提交
516 517
	 * Disable them. This is a hack. Needs to be done via an appropriate
	 * 'SET' command when one is available.
518
	 */
B
Bruce Momjian 已提交
519
	ahprintf(AH, "-- Disable triggers\n");
520 521

	/*
522 523
	 * Just update the AFFECTED table, if known.  Otherwise update all
	 * non-system tables.
524
	 */
525
	if (te && te->tag && strlen(te->tag) > 0)
526 527
		ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = 0 "
				 "WHERE oid = '%s'::pg_catalog.regclass;\n\n",
528
				 fmtId(te->tag));
529
	else
530
		ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = 0 FROM pg_catalog.pg_namespace "
531
				 "WHERE relnamespace = pg_namespace.oid AND nspname !~ '^pg_';\n\n");
B
Bruce Momjian 已提交
532 533
}

B
Bruce Momjian 已提交
534 535
static void
_enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
B
Bruce Momjian 已提交
536
{
537 538
	/* This hack is only needed in a data-only restore */
	if (!ropt->dataOnly || !ropt->disable_triggers)
539 540
		return;

541 542 543 544
	/* Don't do it for the BLOBS TocEntry, either */
	if (te && strcmp(te->desc, "BLOBS") == 0)
		return;

545
	/*
B
Bruce Momjian 已提交
546
	 * Become superuser if possible, since they are the only ones who can
B
Bruce Momjian 已提交
547 548
	 * update pg_class.  If -S was not given, assume the initial user
	 * identity is a superuser.
549
	 */
550
	_becomeUser(AH, ropt->superuser);
551

552
	ahlog(AH, 1, "enabling triggers\n");
553 554

	/*
B
Bruce Momjian 已提交
555 556
	 * Enable them. This is a hack. Needs to be done via an appropriate
	 * 'SET' command when one is available.
557
	 */
B
Bruce Momjian 已提交
558
	ahprintf(AH, "-- Enable triggers\n");
559 560

	/*
561 562
	 * Just update the AFFECTED table, if known.  Otherwise update all
	 * non-system tables.
563
	 */
564
	if (te && te->tag && strlen(te->tag) > 0)
565
		ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = "
566
				 "(SELECT pg_catalog.count(*) FROM pg_catalog.pg_trigger where pg_class.oid = tgrelid) "
567
				 "WHERE oid = '%s'::pg_catalog.regclass;\n\n",
568
				 fmtId(te->tag));
B
Bruce Momjian 已提交
569
	else
570
		ahprintf(AH, "UPDATE pg_catalog.pg_class SET reltriggers = "
571
				 "(SELECT pg_catalog.count(*) FROM pg_catalog.pg_trigger where pg_class.oid = tgrelid) "
572
				 "FROM pg_catalog.pg_namespace "
573
				 "WHERE relnamespace = pg_namespace.oid AND nspname !~ '^pg_';\n\n");
574
}
B
Bruce Momjian 已提交
575 576

/*
577
 * This is a routine that is part of the dumper interface, hence the 'Archive*' parameter.
B
Bruce Momjian 已提交
578 579 580
 */

/* Public */
P
Peter Eisentraut 已提交
581 582
size_t
WriteData(Archive *AHX, const void *data, size_t dLen)
B
Bruce Momjian 已提交
583
{
B
Bruce Momjian 已提交
584
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
B
Bruce Momjian 已提交
585

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

B
Bruce Momjian 已提交
589
	return (*AH->WriteDataPtr) (AH, data, dLen);
B
Bruce Momjian 已提交
590 591 592
}

/*
B
Bruce Momjian 已提交
593
 * Create a new TOC entry. The TOC was designed as a TOC, but is now the
B
Bruce Momjian 已提交
594 595 596 597
 * repository for all metadata. But the name has stuck.
 */

/* Public */
B
Bruce Momjian 已提交
598
void
599 600 601
ArchiveEntry(Archive *AHX,
			 CatalogId catalogId, DumpId dumpId,
			 const char *tag,
602 603 604
			 const char *namespace,
			 const char *tablespace, 
			 const char *owner, bool withOids,
605 606 607
			 const char *desc, const char *defn,
			 const char *dropStmt, const char *copyStmt,
			 const DumpId *deps, int nDeps,
B
Bruce Momjian 已提交
608
			 DataDumperPtr dumpFn, void *dumpArg)
B
Bruce Momjian 已提交
609
{
B
Bruce Momjian 已提交
610 611 612 613 614
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *newToc;

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

617 618 619 620
	AH->tocCount++;
	if (dumpId > AH->maxDumpId)
		AH->maxDumpId = dumpId;

B
Bruce Momjian 已提交
621 622 623 624 625
	newToc->prev = AH->toc->prev;
	newToc->next = AH->toc;
	AH->toc->prev->next = newToc;
	AH->toc->prev = newToc;

626 627
	newToc->catalogId = catalogId;
	newToc->dumpId = dumpId;
628

629
	newToc->tag = strdup(tag);
630
	newToc->namespace = namespace ? strdup(namespace) : NULL;
631
	newToc->tablespace = tablespace ? strdup(tablespace) : NULL;
632
	newToc->owner = strdup(owner);
633
	newToc->withOids = withOids;
B
Bruce Momjian 已提交
634
	newToc->desc = strdup(desc);
635 636 637
	newToc->defn = strdup(defn);
	newToc->dropStmt = strdup(dropStmt);
	newToc->copyStmt = copyStmt ? strdup(copyStmt) : NULL;
638

639 640 641 642 643 644 645 646 647 648 649
	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;
	}
650

651 652
	newToc->dataDumper = dumpFn;
	newToc->dataDumperArg = dumpArg;
653
	newToc->hadDumper = dumpFn ? true : false;
B
Bruce Momjian 已提交
654

655
	newToc->formatData = NULL;
B
Bruce Momjian 已提交
656

B
Bruce Momjian 已提交
657
	if (AH->ArchiveEntryPtr !=NULL)
B
Bruce Momjian 已提交
658
		(*AH->ArchiveEntryPtr) (AH, newToc);
B
Bruce Momjian 已提交
659 660 661
}

/* Public */
B
Bruce Momjian 已提交
662 663
void
PrintTOCSummary(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
664
{
B
Bruce Momjian 已提交
665 666 667 668
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	TocEntry   *te = AH->toc->next;
	OutputContext sav;
	char	   *fmtName;
B
Bruce Momjian 已提交
669

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

673 674
	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 已提交
675
			 AH->archdbname, AH->tocCount, AH->compression);
676

B
Bruce Momjian 已提交
677 678
	switch (AH->format)
	{
679 680 681 682 683 684 685 686 687 688 689 690
		case archFiles:
			fmtName = "FILES";
			break;
		case archCustom:
			fmtName = "CUSTOM";
			break;
		case archTar:
			fmtName = "TAR";
			break;
		default:
			fmtName = "UNKNOWN";
	}
691 692

	ahprintf(AH, ";     Dump Version: %d.%d-%d\n", AH->vmaj, AH->vmin, AH->vrev);
693
	ahprintf(AH, ";     Format: %s\n", fmtName);
T
Tom Lane 已提交
694 695
	ahprintf(AH, ";     Integer: %d bytes\n", (int) AH->intSize);
	ahprintf(AH, ";     Offset: %d bytes\n", (int) AH->offSize);
696 697 698 699 700 701
	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);
702

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

B
Bruce Momjian 已提交
705 706
	while (te != AH->toc)
	{
707
		if (_tocEntryRequired(te, ropt, true) != 0)
708
			ahprintf(AH, "%d; %u %u %s %s %s %s\n", te->dumpId,
709
					 te->catalogId.tableoid, te->catalogId.oid,
710 711
					 te->desc, te->namespace ? te->namespace : "-",
					 te->tag, te->owner);
B
Bruce Momjian 已提交
712
		te = te->next;
B
Bruce Momjian 已提交
713
	}
B
Bruce Momjian 已提交
714

B
Bruce Momjian 已提交
715 716
	if (ropt->filename)
		ResetOutput(AH, sav);
B
Bruce Momjian 已提交
717 718
}

719 720 721 722 723
/***********
 * BLOB Archival
 ***********/

/* Called by a dumper to signal start of a BLOB */
B
Bruce Momjian 已提交
724
int
725
StartBlob(Archive *AHX, Oid oid)
726
{
B
Bruce Momjian 已提交
727
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
728

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

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

B
Bruce Momjian 已提交
734
	return 1;
735 736 737
}

/* Called by a dumper to signal end of a BLOB */
B
Bruce Momjian 已提交
738
int
739
EndBlob(Archive *AHX, Oid oid)
740
{
B
Bruce Momjian 已提交
741
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
742

B
Bruce Momjian 已提交
743 744
	if (AH->EndBlobPtr)
		(*AH->EndBlobPtr) (AH, AH->currToc, oid);
745

B
Bruce Momjian 已提交
746
	return 1;
747 748 749 750 751 752
}

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

753
/*
B
Bruce Momjian 已提交
754
 * Called by a format handler before any blobs are restored
755
 */
B
Bruce Momjian 已提交
756 757
void
StartRestoreBlobs(ArchiveHandle *AH)
758 759 760 761 762
{
	AH->blobCount = 0;
}

/*
B
Bruce Momjian 已提交
763
 * Called by a format handler after all blobs are restored
764
 */
B
Bruce Momjian 已提交
765 766
void
EndRestoreBlobs(ArchiveHandle *AH)
767 768 769
{
	if (AH->txActive)
	{
770
		ahlog(AH, 2, "committing large-object transactions\n");
771 772 773 774 775 776
		CommitTransaction(AH);
	}

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

777 778 779
	if (AH->createdBlobXref)
		CreateBlobXrefIndex(AH);

780
	ahlog(AH, 1, "restored %d large objects\n", AH->blobCount);
781 782 783
}


784 785 786
/*
 * Called by a format handler to initiate restoration of a blob
 */
B
Bruce Momjian 已提交
787
void
788
StartRestoreBlob(ArchiveHandle *AH, Oid oid)
789
{
790
	Oid			loOid;
791

792 793
	AH->blobCount++;

794 795 796
	if (!AH->createdBlobXref)
	{
		if (!AH->connection)
797
			die_horribly(AH, modulename, "cannot restore large objects without a database connection\n");
798 799 800 801 802

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

803 804 805
	/* Initialize the LO Buffer */
	AH->lo_buf_used = 0;

806 807 808 809 810
	/*
	 * Start long-running TXs if necessary
	 */
	if (!AH->txActive)
	{
811
		ahlog(AH, 2, "starting large-object transactions\n");
812 813 814 815
		StartTransaction(AH);
	}
	if (!AH->blobTxActive)
		StartTransactionXref(AH);
816

817 818
	loOid = lo_creat(AH->connection, INV_READ | INV_WRITE);
	if (loOid == 0)
819
		die_horribly(AH, modulename, "could not create large object\n");
820

821
	ahlog(AH, 2, "restoring large object with OID %u as %u\n", oid, loOid);
822 823 824 825 826

	InsertBlobXref(AH, oid, loOid);

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

B
Bruce Momjian 已提交
829
	AH->writingBlob = 1;
830 831
}

B
Bruce Momjian 已提交
832
void
833
EndRestoreBlob(ArchiveHandle *AH, Oid oid)
834
{
835 836 837
	if (AH->lo_buf_used > 0)
	{
		/* Write remaining bytes from the LO buffer */
B
Bruce Momjian 已提交
838
		size_t		res;
839 840 841

		res = lo_write(AH->connection, AH->loFd, (void *) AH->lo_buf, AH->lo_buf_used);

842
		ahlog(AH, 5, "wrote remaining %lu bytes of large-object data (result = %lu)\n",
P
Peter Eisentraut 已提交
843
			  (unsigned long) AH->lo_buf_used, (unsigned long) res);
844
		if (res != AH->lo_buf_used)
P
Peter Eisentraut 已提交
845
			die_horribly(AH, modulename, "could not write to large object (result: %lu, expected: %lu)\n",
B
Bruce Momjian 已提交
846
				   (unsigned long) res, (unsigned long) AH->lo_buf_used);
847 848
		AH->lo_buf_used = 0;
	}
849

B
Bruce Momjian 已提交
850 851
	lo_close(AH->connection, AH->loFd);
	AH->writingBlob = 0;
852

853 854 855
	/*
	 * Commit every BLOB_BATCH_SIZE blobs...
	 */
B
Bruce Momjian 已提交
856
	if (((AH->blobCount / BLOB_BATCH_SIZE) * BLOB_BATCH_SIZE) == AH->blobCount)
857
	{
858
		ahlog(AH, 2, "committing large-object transactions\n");
859 860 861
		CommitTransaction(AH);
		CommitTransactionXref(AH);
	}
862 863
}

B
Bruce Momjian 已提交
864 865 866 867
/***********
 * Sorting and Reordering
 ***********/

B
Bruce Momjian 已提交
868 869
void
SortTocFromFile(Archive *AHX, RestoreOptions *ropt)
B
Bruce Momjian 已提交
870
{
B
Bruce Momjian 已提交
871 872 873 874 875
	ArchiveHandle *AH = (ArchiveHandle *) AHX;
	FILE	   *fh;
	char		buf[1024];
	char	   *cmnt;
	char	   *endptr;
876
	DumpId		id;
B
Bruce Momjian 已提交
877 878 879 880
	TocEntry   *te;
	TocEntry   *tePrev;

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

B
Bruce Momjian 已提交
885 886
	/* Set prev entry as head of list */
	tePrev = AH->toc;
B
Bruce Momjian 已提交
887

B
Bruce Momjian 已提交
888 889 890
	/* Setup the file */
	fh = fopen(ropt->tocFile, PG_BINARY_R);
	if (!fh)
891
		die_horribly(AH, modulename, "could not open TOC file\n");
B
Bruce Momjian 已提交
892

B
Bruce Momjian 已提交
893
	while (fgets(buf, 1024, fh) != NULL)
B
Bruce Momjian 已提交
894
	{
B
Bruce Momjian 已提交
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
		/* Find a comment */
		cmnt = strchr(buf, ';');
		if (cmnt == buf)
			continue;

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

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

		/* Get an ID */
		id = strtol(buf, &endptr, 10);
910
		if (endptr == buf || id <= 0 || id > AH->maxDumpId)
B
Bruce Momjian 已提交
911
		{
912
			write_msg(modulename, "WARNING: line ignored: %s\n", buf);
B
Bruce Momjian 已提交
913 914
			continue;
		}
B
Bruce Momjian 已提交
915

B
Bruce Momjian 已提交
916
		/* Find TOC entry */
917
		te = getTocEntryByDumpId(AH, id);
B
Bruce Momjian 已提交
918
		if (!te)
919 920
			die_horribly(AH, modulename, "could not find entry for ID %d\n",
						 id);
B
Bruce Momjian 已提交
921

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

B
Bruce Momjian 已提交
924 925 926
		_moveAfter(AH, tePrev, te);
		tePrev = te;
	}
B
Bruce Momjian 已提交
927

B
Bruce Momjian 已提交
928
	if (fclose(fh) != 0)
929 930
		die_horribly(AH, modulename, "could not close TOC file: %s\n",
					 strerror(errno));
B
Bruce Momjian 已提交
931 932 933 934 935 936 937 938
}

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

/* Public */
B
Bruce Momjian 已提交
939 940 941 942
int
archputs(const char *s, Archive *AH)
{
	return WriteData(AH, s, strlen(s));
B
Bruce Momjian 已提交
943 944 945
}

/* Public */
B
Bruce Momjian 已提交
946 947
int
archprintf(Archive *AH, const char *fmt,...)
B
Bruce Momjian 已提交
948
{
B
Bruce Momjian 已提交
949 950 951 952 953 954 955
	char	   *p = NULL;
	va_list		ap;
	int			bSize = strlen(fmt) + 256;
	int			cnt = -1;

	/*
	 * This is paranoid: deal with the possibility that vsnprintf is
B
Bruce Momjian 已提交
956 957
	 * 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 已提交
958 959
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
B
Bruce Momjian 已提交
960
	{
B
Bruce Momjian 已提交
961 962
		if (p != NULL)
			free(p);
963
		bSize *= 2;
B
Bruce Momjian 已提交
964
		p = (char *) malloc(bSize);
965
		if (p == NULL)
966
			exit_horribly(AH, modulename, "out of memory\n");
967 968 969
		va_start(ap, fmt);
		cnt = vsnprintf(p, bSize, fmt, ap);
		va_end(ap);
B
Bruce Momjian 已提交
970 971 972 973
	}
	WriteData(AH, p, cnt);
	free(p);
	return cnt;
B
Bruce Momjian 已提交
974 975 976 977 978 979 980
}


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

B
Bruce Momjian 已提交
981 982
OutputContext
SetOutput(ArchiveHandle *AH, char *filename, int compression)
B
Bruce Momjian 已提交
983
{
B
Bruce Momjian 已提交
984
	OutputContext sav;
985
	int			fn;
B
Bruce Momjian 已提交
986 987 988 989 990 991

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

	if (filename)
992
		fn = -1;
B
Bruce Momjian 已提交
993 994 995 996
	else if (AH->FH)
		fn = fileno(AH->FH);
	else if (AH->fSpec)
	{
997
		fn = -1;
B
Bruce Momjian 已提交
998 999 1000 1001 1002 1003
		filename = AH->fSpec;
	}
	else
		fn = fileno(stdout);

	/* If compression explicitly requested, use gzopen */
1004
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
1005 1006
	if (compression != 0)
	{
1007 1008 1009
		char		fmode[10];

		/* Don't use PG_BINARY_x since this is zlib */
1010
		sprintf(fmode, "wb%d", compression);
1011 1012
		if (fn >= 0)
			AH->OF = gzdopen(dup(fn), fmode);
B
Bruce Momjian 已提交
1013 1014
		else
			AH->OF = gzopen(filename, fmode);
1015
		AH->gzOut = 1;
B
Bruce Momjian 已提交
1016 1017
	}
	else
B
Bruce Momjian 已提交
1018
#endif
1019 1020
	{							/* Use fopen */
		if (fn >= 0)
1021
			AH->OF = fdopen(dup(fn), PG_BINARY_W);
B
Bruce Momjian 已提交
1022
		else
1023 1024
			AH->OF = fopen(filename, PG_BINARY_W);
		AH->gzOut = 0;
B
Bruce Momjian 已提交
1025
	}
B
Bruce Momjian 已提交
1026

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

B
Bruce Momjian 已提交
1030
	return sav;
B
Bruce Momjian 已提交
1031 1032
}

B
Bruce Momjian 已提交
1033 1034
void
ResetOutput(ArchiveHandle *AH, OutputContext sav)
B
Bruce Momjian 已提交
1035
{
B
Bruce Momjian 已提交
1036
	int			res;
1037

B
Bruce Momjian 已提交
1038
	if (AH->gzOut)
1039
		res = GZCLOSE(AH->OF);
B
Bruce Momjian 已提交
1040
	else
1041 1042 1043
		res = fclose(AH->OF);

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

B
Bruce Momjian 已提交
1047 1048
	AH->gzOut = sav.gzOut;
	AH->OF = sav.OF;
B
Bruce Momjian 已提交
1049 1050 1051 1052 1053
}



/*
B
Bruce Momjian 已提交
1054
 *	Print formatted text to the output file (usually stdout).
B
Bruce Momjian 已提交
1055
 */
B
Bruce Momjian 已提交
1056 1057
int
ahprintf(ArchiveHandle *AH, const char *fmt,...)
B
Bruce Momjian 已提交
1058
{
B
Bruce Momjian 已提交
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
	char	   *p = NULL;
	va_list		ap;
	int			bSize = strlen(fmt) + 256;		/* Should be enough */
	int			cnt = -1;

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

	/*
	 * or returns > 0 even if string does not fit. It may be the case that
	 * it returns cnt = bufsize
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
1074
	{
B
Bruce Momjian 已提交
1075 1076
		if (p != NULL)
			free(p);
1077
		bSize *= 2;
B
Bruce Momjian 已提交
1078
		p = (char *) malloc(bSize);
1079
		if (p == NULL)
1080
			die_horribly(AH, modulename, "out of memory\n");
1081
		va_start(ap, fmt);
1082
		cnt = vsnprintf(p, bSize, fmt, ap);
1083
		va_end(ap);
B
Bruce Momjian 已提交
1084 1085 1086 1087
	}
	ahwrite(p, 1, cnt, AH);
	free(p);
	return cnt;
B
Bruce Momjian 已提交
1088 1089
}

B
Bruce Momjian 已提交
1090 1091
void
ahlog(ArchiveHandle *AH, int level, const char *fmt,...)
1092 1093 1094 1095 1096 1097 1098
{
	va_list		ap;

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

	va_start(ap, fmt);
1099
	_write_msg(NULL, fmt, ap);
1100 1101 1102
	va_end(ap);
}

1103 1104 1105
/*
 * Single place for logic which says 'We are restoring to a direct DB connection'.
 */
B
Bruce Momjian 已提交
1106 1107
int
RestoringToDB(ArchiveHandle *AH)
1108 1109 1110 1111
{
	return (AH->ropt && AH->ropt->useDB && AH->connection);
}

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

B
Bruce Momjian 已提交
1123
	if (AH->writingBlob)
1124
	{
P
Peter Eisentraut 已提交
1125 1126 1127
		if (AH->lo_buf_used + size * nmemb > AH->lo_buf_size)
		{
			/* Split LO buffer */
B
Bruce Momjian 已提交
1128 1129
			size_t		remaining = AH->lo_buf_size - AH->lo_buf_used;
			size_t		slack = nmemb * size - remaining;
P
Peter Eisentraut 已提交
1130

B
Bruce Momjian 已提交
1131
			memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining);
P
Peter Eisentraut 已提交
1132 1133 1134 1135 1136 1137
			res = lo_write(AH->connection, AH->loFd, AH->lo_buf, AH->lo_buf_size);
			ahlog(AH, 5, "wrote %lu bytes of large object data (result = %lu)\n",
				  (unsigned long) AH->lo_buf_size, (unsigned long) res);
			if (res != AH->lo_buf_size)
				die_horribly(AH, modulename,
							 "could not write to large object (result: %lu, expected: %lu)\n",
B
Bruce Momjian 已提交
1138 1139
				   (unsigned long) res, (unsigned long) AH->lo_buf_size);
			memcpy(AH->lo_buf, (char *) ptr + remaining, slack);
P
Peter Eisentraut 已提交
1140 1141 1142 1143 1144
			AH->lo_buf_used = slack;
		}
		else
		{
			/* LO Buffer is still large enough, buffer it */
B
Bruce Momjian 已提交
1145
			memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, size * nmemb);
P
Peter Eisentraut 已提交
1146 1147 1148 1149
			AH->lo_buf_used += size * nmemb;
		}

		return size * nmemb;
1150
	}
B
Bruce Momjian 已提交
1151
	else if (AH->gzOut)
1152
	{
B
Bruce Momjian 已提交
1153
		res = GZWRITE((void *) ptr, size, nmemb, AH->OF);
1154
		if (res != (nmemb * size))
1155
			die_horribly(AH, modulename, "could not write to compressed archive\n");
1156 1157
		return res;
	}
B
Bruce Momjian 已提交
1158
	else if (AH->CustomOutPtr)
1159
	{
B
Bruce Momjian 已提交
1160 1161
		res = AH->CustomOutPtr (AH, ptr, size * nmemb);

1162
		if (res != (nmemb * size))
1163
			die_horribly(AH, modulename, "could not write to custom output routine\n");
1164 1165
		return res;
	}
1166 1167 1168
	else
	{
		/*
B
Bruce Momjian 已提交
1169 1170 1171
		 * If we're doing a restore, and it's direct to DB, and we're
		 * connected then send it to the DB.
		 */
1172
		if (RestoringToDB(AH))
B
Bruce Momjian 已提交
1173
			return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb);		/* Always 1, currently */
1174
		else
1175
		{
B
Bruce Momjian 已提交
1176
			res = fwrite((void *) ptr, size, nmemb, AH->OF);
1177
			if (res != nmemb)
P
Peter Eisentraut 已提交
1178 1179
				die_horribly(AH, modulename, "could not write to output file (%lu != %lu)\n",
							 (unsigned long) res, (unsigned long) nmemb);
1180 1181
			return res;
		}
1182
	}
B
Bruce Momjian 已提交
1183
}
1184 1185

/* Common exit code */
B
Bruce Momjian 已提交
1186
static void
1187
_write_msg(const char *modulename, const char *fmt, va_list ap)
1188
{
1189
	if (modulename)
1190
		fprintf(stderr, "%s: [%s] ", progname, _(modulename));
1191 1192
	else
		fprintf(stderr, "%s: ", progname);
1193
	vfprintf(stderr, _(fmt), ap);
1194 1195 1196
}

void
1197
write_msg(const char *modulename, const char *fmt,...)
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
{
	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);
1211

B
Bruce Momjian 已提交
1212 1213
	if (AH)
	{
1214 1215
		if (AH->public.verbose)
			write_msg(NULL, "*** aborted because of error\n");
B
Bruce Momjian 已提交
1216 1217
		if (AH->connection)
			PQfinish(AH->connection);
1218 1219 1220
		if (AH->blobConnection)
			PQfinish(AH->blobConnection);
	}
1221

B
Bruce Momjian 已提交
1222
	exit(1);
B
Bruce Momjian 已提交
1223 1224
}

1225
/* External use */
B
Bruce Momjian 已提交
1226
void
1227
exit_horribly(Archive *AH, const char *modulename, const char *fmt,...)
1228
{
B
Bruce Momjian 已提交
1229
	va_list		ap;
1230

B
Bruce Momjian 已提交
1231
	va_start(ap, fmt);
1232
	_die_horribly((ArchiveHandle *) AH, modulename, fmt, ap);
1233
	va_end(ap);
1234
}
B
Bruce Momjian 已提交
1235

1236
/* Archiver use (just different arg declaration) */
B
Bruce Momjian 已提交
1237
void
1238
die_horribly(ArchiveHandle *AH, const char *modulename, const char *fmt,...)
B
Bruce Momjian 已提交
1239
{
B
Bruce Momjian 已提交
1240
	va_list		ap;
B
Bruce Momjian 已提交
1241

B
Bruce Momjian 已提交
1242
	va_start(ap, fmt);
1243
	_die_horribly(AH, modulename, fmt, ap);
1244
	va_end(ap);
B
Bruce Momjian 已提交
1245 1246
}

1247 1248
/* on some error, we may decide to go on... */
void
B
Bruce Momjian 已提交
1249 1250
warn_or_die_horribly(ArchiveHandle *AH,
					 const char *modulename, const char *fmt,...)
1251
{
B
Bruce Momjian 已提交
1252
	va_list		ap;
1253

B
Bruce Momjian 已提交
1254 1255
	switch (AH->stage)
	{
1256 1257 1258 1259 1260 1261

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

		case STAGE_INITIALIZING:
B
Bruce Momjian 已提交
1262
			if (AH->stage != AH->lastErrorStage)
1263 1264 1265 1266
				write_msg(modulename, "Error while INITIALIZING:\n");
			break;

		case STAGE_PROCESSING:
B
Bruce Momjian 已提交
1267
			if (AH->stage != AH->lastErrorStage)
1268 1269 1270 1271
				write_msg(modulename, "Error while PROCESSING TOC:\n");
			break;

		case STAGE_FINALIZING:
B
Bruce Momjian 已提交
1272
			if (AH->stage != AH->lastErrorStage)
1273 1274 1275
				write_msg(modulename, "Error while FINALIZING:\n");
			break;
	}
B
Bruce Momjian 已提交
1276 1277
	if (AH->currentTE != NULL && AH->currentTE != AH->lastErrorTE)
	{
P
Peter Eisentraut 已提交
1278
		write_msg(modulename, "Error from TOC entry %d; %u %u %s %s %s\n", AH->currentTE->dumpId,
B
Bruce Momjian 已提交
1279 1280
		 AH->currentTE->catalogId.tableoid, AH->currentTE->catalogId.oid,
		  AH->currentTE->desc, AH->currentTE->tag, AH->currentTE->owner);
1281 1282 1283 1284
	}
	AH->lastErrorStage = AH->stage;
	AH->lastErrorTE = AH->currentTE;

1285
	va_start(ap, fmt);
1286
	if (AH->public.exit_on_error)
1287 1288 1289 1290 1291 1292 1293 1294
		_die_horribly(AH, modulename, fmt, ap);
	else
	{
		_write_msg(modulename, fmt, ap);
		AH->public.n_errors++;
	}
	va_end(ap);
}
1295

B
Bruce Momjian 已提交
1296 1297
static void
_moveAfter(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
	te->prev = pos;
	te->next = pos->next;
B
Bruce Momjian 已提交
1304

B
Bruce Momjian 已提交
1305 1306
	pos->next->prev = te;
	pos->next = te;
B
Bruce Momjian 已提交
1307 1308
}

1309 1310
#ifdef NOT_USED

B
Bruce Momjian 已提交
1311 1312
static void
_moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te)
B
Bruce Momjian 已提交
1313
{
B
Bruce Momjian 已提交
1314 1315
	te->prev->next = te->next;
	te->next->prev = te->prev;
B
Bruce Momjian 已提交
1316

B
Bruce Momjian 已提交
1317 1318 1319 1320
	te->prev = pos->prev;
	te->next = pos;
	pos->prev->next = te;
	pos->prev = te;
B
Bruce Momjian 已提交
1321
}
1322 1323
#endif

B
Bruce Momjian 已提交
1324
static TocEntry *
1325
getTocEntryByDumpId(ArchiveHandle *AH, DumpId id)
B
Bruce Momjian 已提交
1326
{
B
Bruce Momjian 已提交
1327 1328 1329 1330 1331
	TocEntry   *te;

	te = AH->toc->next;
	while (te != AH->toc)
	{
1332
		if (te->dumpId == id)
B
Bruce Momjian 已提交
1333 1334 1335 1336
			return te;
		te = te->next;
	}
	return NULL;
B
Bruce Momjian 已提交
1337 1338
}

1339
teReqs
1340
TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt)
B
Bruce Momjian 已提交
1341
{
1342
	TocEntry   *te = getTocEntryByDumpId(AH, id);
B
Bruce Momjian 已提交
1343

B
Bruce Momjian 已提交
1344 1345
	if (!te)
		return 0;
B
Bruce Momjian 已提交
1346

1347
	return _tocEntryRequired(te, ropt, true);
B
Bruce Momjian 已提交
1348 1349
}

1350 1351 1352
size_t
WriteOffset(ArchiveHandle *AH, off_t o, int wasSet)
{
B
Bruce Momjian 已提交
1353
	int			off;
1354 1355 1356 1357 1358 1359 1360

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

	/* Write out off_t smallest byte first, prevents endian mismatch */
	for (off = 0; off < sizeof(off_t); off++)
	{
B
Bruce Momjian 已提交
1361
		(*AH->WriteBytePtr) (AH, o & 0xFF);
1362 1363 1364 1365 1366 1367 1368 1369
		o >>= 8;
	}
	return sizeof(off_t) + 1;
}

int
ReadOffset(ArchiveHandle *AH, off_t *o)
{
B
Bruce Momjian 已提交
1370 1371 1372
	int			i;
	int			off;
	int			offsetFlg;
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383

	/* 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 已提交
1384
			return K_OFFSET_POS_NOT_SET;
1385
		else if (i == 0)
B
Bruce Momjian 已提交
1386
			return K_OFFSET_NO_DATA;
1387 1388

		/* Cast to off_t because it was written as an int. */
B
Bruce Momjian 已提交
1389
		*o = (off_t) i;
1390 1391 1392 1393
		return K_OFFSET_POS_SET;
	}

	/*
B
Bruce Momjian 已提交
1394 1395
	 * Read the flag indicating the state of the data pointer. Check if
	 * valid and die if not.
1396
	 *
B
Bruce Momjian 已提交
1397 1398
	 * This used to be handled by a negative or zero pointer, now we use an
	 * extra byte specifically for the state.
1399 1400 1401 1402 1403 1404 1405 1406 1407
	 */
	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 已提交
1408
			break;
1409 1410

		default:
B
Bruce Momjian 已提交
1411
			die_horribly(AH, modulename, "Unexpected data offset flag %d\n", offsetFlg);
1412 1413 1414 1415 1416 1417 1418 1419
	}

	/*
	 * Read the bytes
	 */
	for (off = 0; off < AH->offSize; off++)
	{
		if (off < sizeof(off_t))
1420
			*o |= ((off_t) ((*AH->ReadBytePtr) (AH))) << (off * 8);
1421 1422 1423
		else
		{
			if ((*AH->ReadBytePtr) (AH) != 0)
B
Bruce Momjian 已提交
1424
				die_horribly(AH, modulename, "file offset in dump file is too large\n");
1425 1426 1427 1428 1429 1430
		}
	}

	return offsetFlg;
}

P
Peter Eisentraut 已提交
1431
size_t
B
Bruce Momjian 已提交
1432
WriteInt(ArchiveHandle *AH, int i)
B
Bruce Momjian 已提交
1433
{
B
Bruce Momjian 已提交
1434 1435 1436 1437
	int			b;

	/*
	 * This is a bit yucky, but I don't want to make the binary format
1438
	 * very dependent on representation, and not knowing much about it, I
B
Bruce Momjian 已提交
1439 1440 1441 1442 1443 1444 1445 1446 1447
	 * write out a sign byte. If you change this, don't forget to change
	 * the file version #, and modify readInt to read the new format AS
	 * WELL AS the old formats.
	 */

	/* SIGN byte */
	if (i < 0)
	{
		(*AH->WriteBytePtr) (AH, 1);
1448
		i = -i;
B
Bruce Momjian 已提交
1449 1450 1451 1452 1453 1454 1455
	}
	else
		(*AH->WriteBytePtr) (AH, 0);

	for (b = 0; b < AH->intSize; b++)
	{
		(*AH->WriteBytePtr) (AH, i & 0xFF);
1456
		i >>= 8;
B
Bruce Momjian 已提交
1457 1458 1459
	}

	return AH->intSize + 1;
B
Bruce Momjian 已提交
1460 1461
}

B
Bruce Momjian 已提交
1462 1463
int
ReadInt(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1464
{
B
Bruce Momjian 已提交
1465 1466 1467 1468 1469
	int			res = 0;
	int			bv,
				b;
	int			sign = 0;		/* Default positive */
	int			bitShift = 0;
B
Bruce Momjian 已提交
1470

B
Bruce Momjian 已提交
1471
	if (AH->version > K_VERS_1_0)
1472
		/* Read a sign byte */
B
Bruce Momjian 已提交
1473
		sign = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
1474

B
Bruce Momjian 已提交
1475 1476 1477
	for (b = 0; b < AH->intSize; b++)
	{
		bv = (*AH->ReadBytePtr) (AH) & 0xFF;
1478 1479 1480
		if (bv != 0)
			res = res + (bv << bitShift);
		bitShift += 8;
B
Bruce Momjian 已提交
1481
	}
B
Bruce Momjian 已提交
1482

B
Bruce Momjian 已提交
1483 1484
	if (sign)
		res = -res;
B
Bruce Momjian 已提交
1485

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

P
Peter Eisentraut 已提交
1489
size_t
1490
WriteStr(ArchiveHandle *AH, const char *c)
B
Bruce Momjian 已提交
1491
{
P
Peter Eisentraut 已提交
1492
	size_t		res;
1493 1494 1495 1496

	if (c)
	{
		res = WriteInt(AH, strlen(c));
B
Bruce Momjian 已提交
1497
		res += (*AH->WriteBufPtr) (AH, c, strlen(c));
1498 1499 1500 1501
	}
	else
		res = WriteInt(AH, -1);

B
Bruce Momjian 已提交
1502
	return res;
B
Bruce Momjian 已提交
1503 1504
}

B
Bruce Momjian 已提交
1505 1506
char *
ReadStr(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1507
{
B
Bruce Momjian 已提交
1508 1509
	char	   *buf;
	int			l;
B
Bruce Momjian 已提交
1510

B
Bruce Momjian 已提交
1511
	l = ReadInt(AH);
1512 1513 1514 1515
	if (l == -1)
		buf = NULL;
	else
	{
B
Bruce Momjian 已提交
1516
		buf = (char *) malloc(l + 1);
1517
		if (!buf)
1518
			die_horribly(AH, modulename, "out of memory\n");
1519

B
Bruce Momjian 已提交
1520
		(*AH->ReadBufPtr) (AH, (void *) buf, l);
1521 1522
		buf[l] = '\0';
	}
B
Bruce Momjian 已提交
1523

B
Bruce Momjian 已提交
1524
	return buf;
B
Bruce Momjian 已提交
1525 1526
}

T
Tom Lane 已提交
1527
static int
B
Bruce Momjian 已提交
1528
_discoverArchiveFormat(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1529
{
B
Bruce Momjian 已提交
1530 1531
	FILE	   *fh;
	char		sig[6];			/* More than enough */
P
Peter Eisentraut 已提交
1532
	size_t		cnt;
B
Bruce Momjian 已提交
1533
	int			wantClose = 0;
B
Bruce Momjian 已提交
1534

1535
#if 0
1536
	write_msg(modulename, "attempting to ascertain archive format\n");
1537
#endif
1538 1539 1540 1541 1542 1543 1544 1545

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

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

B
Bruce Momjian 已提交
1547 1548
	if (AH->fSpec)
	{
1549 1550
		wantClose = 1;
		fh = fopen(AH->fSpec, PG_BINARY_R);
B
Bruce Momjian 已提交
1551 1552
	}
	else
1553
		fh = stdin;
B
Bruce Momjian 已提交
1554

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

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

B
Bruce Momjian 已提交
1560
	if (cnt != 5)
1561 1562 1563 1564
	{
		if (ferror(fh))
			die_horribly(AH, modulename, "could not read input file: %s\n", strerror(errno));
		else
P
Peter Eisentraut 已提交
1565 1566
			die_horribly(AH, modulename, "input file is too short (read %lu, expected 5)\n",
						 (unsigned long) cnt);
1567
	}
B
Bruce Momjian 已提交
1568

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

B
Bruce Momjian 已提交
1573
	if (strncmp(sig, "PGDMP", 5) == 0)
1574 1575 1576 1577 1578 1579 1580 1581 1582
	{
		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 已提交
1583 1584
		if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))		/* Version > 1.0 */
		{
1585 1586 1587 1588 1589 1590
			AH->vrev = fgetc(fh);
			AH->lookahead[AH->lookaheadLen++] = AH->vrev;
		}
		else
			AH->vrev = 0;

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

1594 1595 1596
		AH->intSize = fgetc(fh);
		AH->lookahead[AH->lookaheadLen++] = AH->intSize;

1597 1598 1599 1600 1601 1602 1603 1604
		if (AH->version >= K_VERS_1_7)
		{
			AH->offSize = fgetc(fh);
			AH->lookahead[AH->lookaheadLen++] = AH->offSize;
		}
		else
			AH->offSize = AH->intSize;

1605 1606
		AH->format = fgetc(fh);
		AH->lookahead[AH->lookaheadLen++] = AH->format;
B
Bruce Momjian 已提交
1607 1608 1609
	}
	else
	{
1610
		/*
B
Bruce Momjian 已提交
1611 1612
		 * *Maybe* we have a tar archive format file... So, read first 512
		 * byte header...
1613 1614 1615
		 */
		cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh);
		AH->lookaheadLen += cnt;
B
Bruce Momjian 已提交
1616

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

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

1623 1624
		AH->format = archTar;
	}
B
Bruce Momjian 已提交
1625

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

1638
#if 0
P
Peter Eisentraut 已提交
1639 1640
	write_msg(modulename, "read %lu bytes into lookahead buffer\n",
			  (unsigned long) AH->lookaheadLen);
1641
#endif
B
Bruce Momjian 已提交
1642

B
Bruce Momjian 已提交
1643 1644
	/* Close the file */
	if (wantClose)
1645
		if (fclose(fh) != 0)
1646 1647
			die_horribly(AH, modulename, "could not close the input file after reading header: %s\n",
						 strerror(errno));
B
Bruce Momjian 已提交
1648

B
Bruce Momjian 已提交
1649
	return AH->format;
B
Bruce Momjian 已提交
1650 1651 1652 1653 1654 1655
}


/*
 * Allocate an archive handle
 */
B
Bruce Momjian 已提交
1656 1657 1658
static ArchiveHandle *
_allocAH(const char *FileSpec, const ArchiveFormat fmt,
		 const int compression, ArchiveMode mode)
1659
{
B
Bruce Momjian 已提交
1660
	ArchiveHandle *AH;
B
Bruce Momjian 已提交
1661

1662
#if 0
1663
	write_msg(modulename, "allocating AH for %s, format %d\n", FileSpec, fmt);
1664
#endif
1665

B
Bruce Momjian 已提交
1666 1667
	AH = (ArchiveHandle *) calloc(1, sizeof(ArchiveHandle));
	if (!AH)
1668
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
1669

1670 1671
	/* AH->debugLevel = 100; */

B
Bruce Momjian 已提交
1672 1673
	AH->vmaj = K_VERS_MAJOR;
	AH->vmin = K_VERS_MINOR;
1674
	AH->vrev = K_VERS_REV;
B
Bruce Momjian 已提交
1675

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

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

1684 1685 1686
		/*
		 * Not used; maybe later....
		 *
B
Bruce Momjian 已提交
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 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730
	/*
	 * On Windows, we need to use binary mode to read/write non-text archive
	 * formats.  Force stdin/stdout into binary mode in case that is what
	 * we are using.
	 */
#ifdef WIN32
	if (fmt != archNull)
	{
		if (mode == archModeWrite)
			setmode(fileno(stdout), O_BINARY);
		else
			setmode(fileno(stdin), O_BINARY);
	}
#endif

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

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

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

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

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

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

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

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

B
Bruce Momjian 已提交
1766
	return AH;
B
Bruce Momjian 已提交
1767 1768 1769
}


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

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

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

B
Bruce Momjian 已提交
1795 1796
			if (startPtr != NULL)
				(*startPtr) (AH, te);
B
Bruce Momjian 已提交
1797

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

			/*
			 * The user-provided DataDumper routine needs to call
			 * AH->WriteData
			 */
1807
			(*te->dataDumper) ((Archive *) AH, te->dataDumperArg);
B
Bruce Momjian 已提交
1808 1809 1810 1811 1812

			if (endPtr != NULL)
				(*endPtr) (AH, te);
			AH->currToc = NULL;
		}
1813
		te = te->next;
B
Bruce Momjian 已提交
1814
	}
B
Bruce Momjian 已提交
1815 1816
}

B
Bruce Momjian 已提交
1817 1818
void
WriteToc(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1819
{
1820 1821
	TocEntry   *te;
	char		workbuf[32];
1822
	int			i;
B
Bruce Momjian 已提交
1823 1824 1825 1826

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

	WriteInt(AH, AH->tocCount);
1827 1828

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

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

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

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

B
Bruce Momjian 已提交
1857 1858 1859
		if (AH->WriteExtraTocPtr)
			(*AH->WriteExtraTocPtr) (AH, te);
	}
B
Bruce Momjian 已提交
1860 1861
}

B
Bruce Momjian 已提交
1862 1863
void
ReadToc(ArchiveHandle *AH)
B
Bruce Momjian 已提交
1864
{
B
Bruce Momjian 已提交
1865
	int			i;
1866 1867
	char	   *tmp;
	DumpId	   *deps;
1868 1869
	int			depIdx;
	int			depSize;
B
Bruce Momjian 已提交
1870

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

B
Bruce Momjian 已提交
1873
	AH->tocCount = ReadInt(AH);
1874
	AH->maxDumpId = 0;
B
Bruce Momjian 已提交
1875

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

		if (te->dumpId > AH->maxDumpId)
			AH->maxDumpId = te->dumpId;
1883 1884

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

		te->hadDumper = ReadInt(AH);
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902

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

1904
		te->tag = ReadStr(AH);
1905 1906 1907 1908 1909 1910 1911
		te->desc = ReadStr(AH);
		te->defn = ReadStr(AH);
		te->dropStmt = ReadStr(AH);

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

1912 1913 1914
		if (AH->version >= K_VERS_1_6)
			te->namespace = ReadStr(AH);

1915 1916 1917
		if (AH->version >= K_VERS_1_10)
			te->tablespace = ReadStr(AH);

1918
		te->owner = ReadStr(AH);
1919 1920 1921 1922 1923 1924 1925 1926 1927
		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 已提交
1928

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

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

B
Bruce Momjian 已提交
1969 1970
		if (AH->ReadExtraTocPtr)
			(*AH->ReadExtraTocPtr) (AH, te);
1971

1972 1973
		ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n",
			  i, te->dumpId, te->desc, te->tag);
1974 1975 1976 1977 1978

		te->prev = AH->toc->prev;
		AH->toc->prev->next = te;
		AH->toc->prev = te;
		te->next = AH->toc;
B
Bruce Momjian 已提交
1979
	}
B
Bruce Momjian 已提交
1980 1981
}

1982
static teReqs
1983
_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
B
Bruce Momjian 已提交
1984
{
1985
	teReqs		res = REQ_ALL;
B
Bruce Momjian 已提交
1986

1987 1988 1989 1990
	/* ENCODING objects are dumped specially, so always reject here */
	if (strcmp(te->desc, "ENCODING") == 0)
		return 0;

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

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

B
Bruce Momjian 已提交
1998 1999 2000 2001
	/* Check if tablename only is wanted */
	if (ropt->selTypes)
	{
		if ((strcmp(te->desc, "TABLE") == 0) || (strcmp(te->desc, "TABLE DATA") == 0))
2002 2003 2004
		{
			if (!ropt->selTable)
				return 0;
2005
			if (ropt->tableNames && strcmp(ropt->tableNames, te->tag) != 0)
2006
				return 0;
B
Bruce Momjian 已提交
2007 2008 2009
		}
		else if (strcmp(te->desc, "INDEX") == 0)
		{
2010 2011
			if (!ropt->selIndex)
				return 0;
2012
			if (ropt->indexNames && strcmp(ropt->indexNames, te->tag) != 0)
2013
				return 0;
B
Bruce Momjian 已提交
2014 2015 2016
		}
		else if (strcmp(te->desc, "FUNCTION") == 0)
		{
2017 2018
			if (!ropt->selFunction)
				return 0;
2019
			if (ropt->functionNames && strcmp(ropt->functionNames, te->tag) != 0)
2020
				return 0;
B
Bruce Momjian 已提交
2021 2022 2023
		}
		else if (strcmp(te->desc, "TRIGGER") == 0)
		{
2024 2025
			if (!ropt->selTrigger)
				return 0;
2026
			if (ropt->triggerNames && strcmp(ropt->triggerNames, te->tag) != 0)
2027 2028
				return 0;
		}
B
Bruce Momjian 已提交
2029 2030
		else
			return 0;
B
Bruce Momjian 已提交
2031 2032
	}

2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045
	/*
	 * Check if we had a dataDumper. Indicates if the entry is schema or
	 * data
	 */
	if (!te->hadDumper)
	{
		/*
		 * Special Case: If 'SEQUENCE SET' then it is considered a data
		 * entry
		 */
		if (strcmp(te->desc, "SEQUENCE SET") == 0)
			res = res & REQ_DATA;
		else
2046 2047
			res = res & ~REQ_DATA;
	}
2048

2049
	/*
2050
	 * Special case: <Init> type with <Max OID> tag; this is part of a
2051 2052
	 * DATA restore even though it has SQL.
	 */
2053
	if ((strcmp(te->desc, "<Init>") == 0) && (strcmp(te->tag, "Max OID") == 0))
2054 2055
		res = REQ_DATA;

B
Bruce Momjian 已提交
2056 2057
	/* Mask it if we only want schema */
	if (ropt->schemaOnly)
2058
		res = res & REQ_SCHEMA;
B
Bruce Momjian 已提交
2059

B
Bruce Momjian 已提交
2060
	/* Mask it we only want data */
2061
	if (ropt->dataOnly)
2062
		res = res & REQ_DATA;
B
Bruce Momjian 已提交
2063

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

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

B
Bruce Momjian 已提交
2072
	return res;
B
Bruce Momjian 已提交
2073 2074
}

2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098
/*
 * Issue SET commands for parameters that we want to have set the same way
 * at all times during execution of a restore script.
 */
static void
_doSetFixedOutputState(ArchiveHandle *AH)
{
	TocEntry   *te;

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

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

2099 2100 2101
	/* Avoid annoying notices etc */
	ahprintf(AH, "SET client_min_messages = warning;\n");

2102 2103 2104
	ahprintf(AH, "\n");
}

2105 2106
/*
 * Issue a SET SESSION AUTHORIZATION command.  Caller is responsible
2107 2108
 * for updating state if appropriate.  If user is NULL or an empty string,
 * the specification DEFAULT will be used.
2109 2110
 */
static void
2111
_doSetSessionAuth(ArchiveHandle *AH, const char *user)
2112
{
2113
	PQExpBuffer cmd = createPQExpBuffer();
B
Bruce Momjian 已提交
2114

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

2117 2118 2119 2120
	/*
	 * SQL requires a string literal here.	Might as well be correct.
	 */
	if (user && *user)
2121 2122 2123 2124 2125
		appendStringLiteral(cmd, user, false);
	else
		appendPQExpBuffer(cmd, "DEFAULT");
	appendPQExpBuffer(cmd, ";");

2126 2127 2128 2129
	if (RestoringToDB(AH))
	{
		PGresult   *res;

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
2133
			/* NOT warn_or_die_horribly... use -O instead to skip this. */
2134
			die_horribly(AH, modulename, "could not set session user to \"%s\": %s",
2135
						 user, PQerrorMessage(AH->connection));
2136 2137 2138 2139

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

	destroyPQExpBuffer(cmd);
2143 2144
}

2145

2146 2147 2148 2149 2150 2151 2152 2153 2154 2155
/*
 * 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 已提交
2156
					  "true" : "false");
2157 2158 2159 2160 2161 2162 2163 2164

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

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
2165
			warn_or_die_horribly(AH, modulename,
2166 2167
								 "could not set default_with_oids: %s",
								 PQerrorMessage(AH->connection));
2168 2169 2170 2171 2172 2173 2174 2175 2176 2177

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

	destroyPQExpBuffer(cmd);
}


2178
/*
2179
 * Issue the commands to connect to the specified database.
2180 2181
 *
 * If we're currently restoring right into a database, this will
B
Bruce Momjian 已提交
2182
 * actually establish a connection. Otherwise it puts a \connect into
2183
 * the script output.
2184 2185
 *
 * NULL dbname implies reconnecting to the current DB (pretty useless).
2186
 */
B
Bruce Momjian 已提交
2187
static void
2188
_reconnectToDB(ArchiveHandle *AH, const char *dbname)
2189
{
2190
	if (RestoringToDB(AH))
2191
		ReconnectToServer(AH, dbname, NULL);
2192
	else
2193 2194 2195
	{
		PQExpBuffer qry = createPQExpBuffer();

2196
		appendPQExpBuffer(qry, "\\connect %s\n\n",
2197
						  dbname ? fmtId(dbname) : "-");
B
Bruce Momjian 已提交
2198

2199 2200 2201 2202
		ahprintf(AH, qry->data);

		destroyPQExpBuffer(qry);
	}
2203

2204 2205
	/*
	 * NOTE: currUser keeps track of what the imaginary session user in
2206
	 * our script is.  It's now effectively reset to the original userID.
2207
	 */
2208 2209 2210
	if (AH->currUser)
		free(AH->currUser);

2211
	AH->currUser = strdup("");
2212 2213 2214 2215 2216

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

2219 2220
	/* re-establish fixed state */
	_doSetFixedOutputState(AH);
2221 2222
}

2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247
/*
 * Become the specified user, and update state to avoid redundant commands
 *
 * NULL or empty argument is taken to mean restoring the session default
 */
static void
_becomeUser(ArchiveHandle *AH, const char *user)
{
	if (!user)
		user = "";				/* avoid null pointers */

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

	_doSetSessionAuth(AH, user);

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

	AH->currUser = strdup(user);
}
2248 2249

/*
B
Bruce Momjian 已提交
2250
 * Become the owner of the the given TOC entry object.	If
2251 2252
 * changes in ownership are not allowed, this doesn't do anything.
 */
B
Bruce Momjian 已提交
2253
static void
2254
_becomeOwner(ArchiveHandle *AH, TocEntry *te)
2255
{
2256
	if (AH->ropt && (AH->ropt->noOwner || !AH->ropt->use_setsessauth))
2257 2258
		return;

2259
	_becomeUser(AH, te->owner);
2260 2261
}

2262

2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276
/*
 * 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;
	}
}


2277 2278 2279 2280 2281 2282 2283
/*
 * Issue the commands to select the specified schema as the current schema
 * in the target database.
 */
static void
_selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
{
2284 2285
	PQExpBuffer qry;

2286 2287 2288 2289
	if (!schemaName || *schemaName == '\0' ||
		strcmp(AH->currSchema, schemaName) == 0)
		return;					/* no need to do anything */

2290 2291 2292
	qry = createPQExpBuffer();

	appendPQExpBuffer(qry, "SET search_path = %s",
2293
					  fmtId(schemaName));
2294 2295 2296
	if (strcmp(schemaName, "pg_catalog") != 0)
		appendPQExpBuffer(qry, ", pg_catalog");

2297 2298 2299 2300 2301 2302 2303
	if (RestoringToDB(AH))
	{
		PGresult   *res;

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

		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
2304 2305 2306
			warn_or_die_horribly(AH, modulename,
							   "could not set search_path to \"%s\": %s",
							 schemaName, PQerrorMessage(AH->connection));
2307 2308 2309 2310

		PQclear(res);
	}
	else
2311
		ahprintf(AH, "%s;\n\n", qry->data);
2312 2313 2314 2315

	if (AH->currSchema)
		free(AH->currSchema);
	AH->currSchema = strdup(schemaName);
2316 2317

	destroyPQExpBuffer(qry);
2318 2319
}

2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374
/*
 * 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;
	const char	*want, *have;

	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)
			warn_or_die_horribly(AH, modulename, 
								 "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);
}
2375

2376 2377 2378 2379 2380 2381 2382 2383
/*
 * 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.
2384
 */
2385
static void
2386
_getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
2387
{
2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405
	const char *type = te->desc;

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

	/* We assume CONSTRAINTs are always pkey/unique indexes */
	if (strcmp(type, "CONSTRAINT") == 0)
		type = "INDEX";

	/* objects named by a schema and name */
	if (strcmp(type, "CONVERSION") == 0 ||
		strcmp(type, "DOMAIN") == 0 ||
		strcmp(type, "INDEX") == 0 ||
		strcmp(type, "TABLE") == 0 ||
		strcmp(type, "TYPE") == 0)
	{
2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421
		appendPQExpBuffer(buf, "%s ", type);
		if (te->namespace && te->namespace[0])			/* is null pre-7.3 */
			appendPQExpBuffer(buf, "%s.", fmtId(te->namespace));
		/*
		 * 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.
		 */
		if (AH->version < K_VERS_1_7 &&
			te->tag[0] == '"' &&
			te->tag[strlen(te->tag)-1] == '"' &&
			strcmp(type, "INDEX") == 0)
			appendPQExpBuffer(buf, "%s", te->tag);
		else
			appendPQExpBuffer(buf, "%s", fmtId(te->tag));
2422 2423
		return;
	}
2424

2425 2426 2427 2428 2429 2430 2431
	/* objects named by just a name */
	if (strcmp(type, "DATABASE") == 0 ||
		strcmp(type, "SCHEMA") == 0)
	{
		appendPQExpBuffer(buf, "%s %s", type, fmtId(te->tag));
		return;
	}
2432

B
Bruce Momjian 已提交
2433
	/*
2434 2435
	 * These object types require additional decoration.  Fortunately,
	 * the information needed is exactly what's in the DROP command.
B
Bruce Momjian 已提交
2436
	 */
2437 2438 2439 2440
	if (strcmp(type, "AGGREGATE") == 0 ||
		strcmp(type, "FUNCTION") == 0 ||
		strcmp(type, "OPERATOR") == 0 ||
		strcmp(type, "OPERATOR CLASS") == 0)
B
Bruce Momjian 已提交
2441
	{
2442 2443 2444
		/* Chop "DROP " off the front and make a modifiable copy */
		char	   *first = strdup(te->dropStmt + 5);
		char	   *last;
2445

2446 2447
		/* point to last character in string */
		last = first + strlen(first) - 1;
2448

2449 2450 2451 2452
		/* Strip off any ';' or '\n' at the end */
		while (last >= first && (*last == '\n' || *last == ';'))
			last--;
		*(last + 1) = '\0';
B
Bruce Momjian 已提交
2453

2454
		appendPQExpBufferStr(buf, first);
B
Bruce Momjian 已提交
2455 2456

		free(first);
2457
		return;
2458 2459
	}

2460 2461
	write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n",
			  type);
2462 2463 2464
}

static void
2465
_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass)
B
Bruce Momjian 已提交
2466
{
2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487
	/* 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 ...
	 * unless we are using --clean mode, in which case it's been deleted
	 * and we'd better recreate it.
	 */
	if (!ropt->dropSchema &&
		strcmp(te->desc, "SCHEMA") == 0 && strcmp(te->tag, "public") == 0)
		return;

2488
	/* Select owner, schema, and tablespace as necessary */
2489 2490
	_becomeOwner(AH, te);
	_selectOutputSchema(AH, te->namespace);
2491
	_selectTablespace(AH, te->tablespace);
2492 2493 2494 2495 2496 2497

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

	/* Emit header comment for item */
2498
	if (!AH->noTocComments)
2499
	{
2500 2501 2502 2503 2504 2505 2506 2507 2508
		const char *pfx;

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

		ahprintf(AH, "--\n");
		if (AH->public.verbose)
2509
		{
2510 2511 2512 2513 2514
			ahprintf(AH, "-- TOC entry %d (class %u OID %u)\n",
					 te->dumpId, te->catalogId.tableoid, te->catalogId.oid);
			if (te->nDeps > 0)
			{
				int			i;
2515

2516 2517 2518 2519 2520
				ahprintf(AH, "-- Dependencies:");
				for (i = 0; i < te->nDeps; i++)
					ahprintf(AH, " %d", te->dependencies[i]);
				ahprintf(AH, "\n");
			}
2521
		}
2522
		ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s",
2523 2524 2525
				 pfx, te->tag, te->desc,
				 te->namespace ? te->namespace : "-",
				 te->owner);
2526 2527 2528 2529
		if (te->tablespace) 
			ahprintf(AH, "; Tablespace: %s", te->tablespace);
		ahprintf(AH, "\n");

2530 2531 2532
		if (AH->PrintExtraTocPtr != NULL)
			(*AH->PrintExtraTocPtr) (AH, te);
		ahprintf(AH, "--\n\n");
2533
	}
B
Bruce Momjian 已提交
2534

2535 2536 2537
	/*
	 * Actually print the definition.
	 *
2538 2539 2540
	 * 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
B
Bruce Momjian 已提交
2541
	 * no other good way ...
2542
	 */
2543
	if (ropt->noOwner && strcmp(te->desc, "SCHEMA") == 0)
2544
	{
2545
		ahprintf(AH, "CREATE SCHEMA %s;\n\n\n", fmtId(te->tag));
2546
	}
2547
	else
2548
	{
2549 2550
		if (strlen(te->defn) > 0)
			ahprintf(AH, "%s\n\n", te->defn);
2551
	}
2552 2553 2554

	/*
	 * If we aren't using SET SESSION AUTH to determine ownership, we must
2555 2556 2557
	 * 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.
2558 2559
	 */
	if (!ropt->noOwner && !ropt->use_setsessauth &&
2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579
		strlen(te->owner) > 0 && strlen(te->dropStmt) > 0)
	{
		if (strcmp(te->desc, "AGGREGATE") == 0 ||
			strcmp(te->desc, "CONSTRAINT") == 0 ||
			strcmp(te->desc, "CONVERSION") == 0 ||
			strcmp(te->desc, "DATABASE") == 0 ||
			strcmp(te->desc, "DOMAIN") == 0 ||
			strcmp(te->desc, "FUNCTION") == 0 ||
			strcmp(te->desc, "INDEX") == 0 ||
			strcmp(te->desc, "OPERATOR") == 0 ||
			strcmp(te->desc, "OPERATOR CLASS") == 0 ||
			strcmp(te->desc, "SCHEMA") == 0 ||
			strcmp(te->desc, "TABLE") == 0 ||
			strcmp(te->desc, "TYPE") == 0 ||
			strcmp(te->desc, "VIEW") == 0 ||
			strcmp(te->desc, "SEQUENCE") == 0)
		{
			PQExpBuffer temp = createPQExpBuffer();

			appendPQExpBuffer(temp, "ALTER ");
2580
			_getObjectDescription(temp, te, AH);
2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599
			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 ||
				 strcmp(te->desc, "DEFAULT") == 0 ||
				 strcmp(te->desc, "FK CONSTRAINT") == 0 ||
				 strcmp(te->desc, "PROCEDURAL LANGUAGE") == 0 ||
				 strcmp(te->desc, "RULE") == 0 ||
				 strcmp(te->desc, "TRIGGER") == 0)
		{
			/* these object types don't have separate owners */
		}
		else
		{
			write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n",
					  te->desc);
		}
2600
	}
B
Bruce Momjian 已提交
2601

2602 2603
	/*
	 * If it's an ACL entry, it might contain SET SESSION AUTHORIZATION
B
Bruce Momjian 已提交
2604 2605
	 * commands, so we can no longer assume we know the current auth
	 * setting.
2606 2607 2608 2609 2610 2611 2612
	 */
	if (strncmp(te->desc, "ACL", 3) == 0)
	{
		if (AH->currUser)
			free(AH->currUser);
		AH->currUser = NULL;
	}
B
Bruce Momjian 已提交
2613 2614
}

B
Bruce Momjian 已提交
2615 2616
void
WriteHead(ArchiveHandle *AH)
B
Bruce Momjian 已提交
2617
{
B
Bruce Momjian 已提交
2618
	struct tm	crtm;
2619

B
Bruce Momjian 已提交
2620 2621 2622 2623 2624
	(*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);
2625
	(*AH->WriteBytePtr) (AH, AH->offSize);
B
Bruce Momjian 已提交
2626
	(*AH->WriteBytePtr) (AH, AH->format);
B
Bruce Momjian 已提交
2627

2628
#ifndef HAVE_LIBZ
B
Bruce Momjian 已提交
2629
	if (AH->compression != 0)
2630
		write_msg(modulename, "WARNING: requested compression not available in this "
2631
				  "installation -- archive will be uncompressed\n");
B
Bruce Momjian 已提交
2632

B
Bruce Momjian 已提交
2633
	AH->compression = 0;
2634
#endif
B
Bruce Momjian 已提交
2635

2636 2637 2638 2639 2640 2641 2642 2643 2644 2645
	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);
2646
	WriteStr(AH, PQdb(AH->connection));
2647 2648
	WriteStr(AH, AH->public.remoteVersionStr);
	WriteStr(AH, PG_VERSION);
B
Bruce Momjian 已提交
2649 2650
}

B
Bruce Momjian 已提交
2651 2652
void
ReadHead(ArchiveHandle *AH)
B
Bruce Momjian 已提交
2653
{
B
Bruce Momjian 已提交
2654 2655
	char		tmpMag[7];
	int			fmt;
2656
	struct tm	crtm;
B
Bruce Momjian 已提交
2657

2658
	/* If we haven't already read the header... */
B
Bruce Momjian 已提交
2659 2660
	if (!AH->readHeader)
	{
B
Bruce Momjian 已提交
2661

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

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

B
Bruce Momjian 已提交
2667 2668
		AH->vmaj = (*AH->ReadBytePtr) (AH);
		AH->vmin = (*AH->ReadBytePtr) (AH);
B
Bruce Momjian 已提交
2669

B
Bruce Momjian 已提交
2670 2671 2672
		if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0)))		/* Version > 1.0 */
			AH->vrev = (*AH->ReadBytePtr) (AH);
		else
2673
			AH->vrev = 0;
B
Bruce Momjian 已提交
2674

B
Bruce Momjian 已提交
2675
		AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0;
B
Bruce Momjian 已提交
2676 2677


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

B
Bruce Momjian 已提交
2682
		AH->intSize = (*AH->ReadBytePtr) (AH);
2683
		if (AH->intSize > 32)
P
Peter Eisentraut 已提交
2684 2685
			die_horribly(AH, modulename, "sanity check on integer size (%lu) failed\n",
						 (unsigned long) AH->intSize);
B
Bruce Momjian 已提交
2686

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

2690
		if (AH->version >= K_VERS_1_7)
B
Bruce Momjian 已提交
2691
			AH->offSize = (*AH->ReadBytePtr) (AH);
2692
		else
B
Bruce Momjian 已提交
2693
			AH->offSize = AH->intSize;
2694

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

2697
		if (AH->format != fmt)
2698 2699
			die_horribly(AH, modulename, "expected format (%d) differs from format found in file (%d)\n",
						 AH->format, fmt);
B
Bruce Momjian 已提交
2700
	}
B
Bruce Momjian 已提交
2701

B
Bruce Momjian 已提交
2702 2703
	if (AH->version >= K_VERS_1_2)
	{
2704
		if (AH->version < K_VERS_1_4)
B
Bruce Momjian 已提交
2705
			AH->compression = (*AH->ReadBytePtr) (AH);
2706 2707
		else
			AH->compression = ReadInt(AH);
B
Bruce Momjian 已提交
2708 2709
	}
	else
2710
		AH->compression = Z_DEFAULT_COMPRESSION;
B
Bruce Momjian 已提交
2711

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

2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730
	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 已提交
2731
		if (AH->createDate == (time_t) -1)
2732
			write_msg(modulename, "WARNING: invalid creation date in header\n");
2733 2734
	}

2735 2736 2737 2738 2739 2740
	if (AH->version >= K_VERS_1_10)
	{
		AH->archiveRemoteVersion = ReadStr(AH);
		AH->archiveDumpVersion = ReadStr(AH);
	}

B
Bruce Momjian 已提交
2741 2742 2743
}


2744 2745 2746 2747 2748 2749 2750 2751 2752
/*
 * checkSeek
 *	  check to see if fseek can be performed.
 */

bool
checkSeek(FILE *fp)
{

B
Bruce Momjian 已提交
2753
	if (fseeko(fp, 0, SEEK_CUR) != 0)
2754 2755
		return false;
	else if (sizeof(off_t) > sizeof(long))
B
Bruce Momjian 已提交
2756 2757 2758 2759 2760

		/*
		 * At this point, off_t is too large for long, so we return based
		 * on whether an off_t version of fseek is available.
		 */
2761 2762 2763 2764 2765 2766 2767 2768
#ifdef HAVE_FSEEKO
		return true;
#else
		return false;
#endif
	else
		return true;
}