pg_dump.c 135.4 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * pg_dump.c
4
 *	  pg_dump is a utility for dumping out a postgres database
B
Bruce Momjian 已提交
5
 *	  into a script file.
6 7 8
 *
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
9
 *
10 11 12 13 14 15
 *	pg_dump will read the system catalogs in a database and
 *	dump out a script that reproduces
 *	the schema of the database in terms of
 *		  user-defined types
 *		  user-defined functions
 *		  tables
16
 *		  indexes
17 18
 *		  aggregates
 *		  operators
19
 *		  privileges
20
 *
21
 * the output script is SQL that is understood by PostgreSQL
22 23 24
 *
 *
 * IDENTIFICATION
25
 *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.246 2002/04/05 11:51:12 momjian Exp $
26
 *
27
 *-------------------------------------------------------------------------
28 29
 */

30 31 32 33 34 35 36
/*
 * Although this is not a backend module, we must include postgres.h anyway
 * so that we can include a bunch of backend include files.  pg_dump has
 * never pretended to be very independent of the backend anyhow ...
 */
#include "postgres.h"

37
#include <unistd.h>				/* for getopt() */
38
#include <ctype.h>
39 40 41
#ifdef ENABLE_NLS
#include <locale.h>
#endif
42 43 44 45 46 47 48
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif

49 50 51 52
#ifndef HAVE_STRDUP
#include "strdup.h"
#endif

53
#include "access/attnum.h"
54
#include "access/htup.h"
55
#include "catalog/pg_class.h"
56
#include "catalog/pg_proc.h"
V
Vadim B. Mikheev 已提交
57
#include "catalog/pg_trigger.h"
58
#include "catalog/pg_type.h"
59

60
#include "libpq-fe.h"
61
#include "libpq/libpq-fs.h"
62 63

#include "pg_dump.h"
B
Bruce Momjian 已提交
64
#include "pg_backup.h"
65
#include "pg_backup_archiver.h"
66

B
Bruce Momjian 已提交
67 68
typedef enum _formatLiteralOptions
{
69 70
	CONV_ALL = 0,
	PASS_LFTAB = 3				/* NOTE: 1 and 2 are reserved in case we
B
Bruce Momjian 已提交
71 72 73 74
								 * want to make a mask. */
	/* We could make this a bit mask for control chars, but I don't */
	/* see any value in making it more complex...the current code */
	/* only checks for 'opts == CONV_ALL' anyway. */
75 76
} formatLiteralOptions;

77
static void dumpComment(Archive *fout, const char *target, const char *oid,
78 79
			const char *classname, int subid,
			const char *((*deps)[]));
80
static void dumpOneDomain(Archive *fout, TypeInfo *tinfo);
81
static void dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool dataOnly);
B
Bruce Momjian 已提交
82 83
static void dumpACL(Archive *fout, TableInfo tbinfo);
static void dumpTriggers(Archive *fout, const char *tablename,
84
			 TableInfo *tblinfo, int numTables);
B
Bruce Momjian 已提交
85
static void dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
86
		  TableInfo *tblinfo, int numTables);
87
static void formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts);
88
static void clearTableInfo(TableInfo *, int);
B
Bruce Momjian 已提交
89
static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
90
			TypeInfo *tinfo, int numTypes);
91 92
static Oid	findLastBuiltinOid_V71(const char *);
static Oid	findLastBuiltinOid_V70(void);
B
Bruce Momjian 已提交
93
static void setMaxOid(Archive *fout);
94

95

96
static void AddAcl(char *aclbuf, const char *keyword);
97
static char *GetPrivileges(Archive *AH, const char *s);
V
Vadim B. Mikheev 已提交
98

B
Bruce Momjian 已提交
99 100
static int	dumpBlobs(Archive *AH, char *, void *);
static int	dumpDatabase(Archive *AH);
101
static PQExpBuffer getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo);
102
static const char *getAttrName(int attrnum, TableInfo *tblInfo);
103

B
Bruce Momjian 已提交
104
extern char *optarg;
105
extern int	optind,
B
Bruce Momjian 已提交
106
			opterr;
107 108

/* global decls */
109
bool		g_verbose;			/* User wants verbose narration of our
B
Bruce Momjian 已提交
110
								 * activities. */
111
Oid			g_last_builtin_oid; /* value of the last builtin oid */
B
Bruce Momjian 已提交
112
Archive    *g_fout;				/* the script file */
B
Bruce Momjian 已提交
113 114 115
PGconn	   *g_conn;				/* the database connection */

bool		force_quotes;		/* User wants to suppress double-quotes */
116 117 118 119
bool		dumpData;			/* dump data using proper insert strings */
bool		attrNames;			/* put attr names into insert strings */
bool		schemaOnly;
bool		dataOnly;
120
bool		aclsSkip;
121

B
Bruce Momjian 已提交
122
char		g_opaque_type[10];	/* name for the opaque type */
123 124

/* placeholders for the delimiters for comments */
125 126
char		g_comment_start[10];
char		g_comment_end[10];
127 128


B
Bruce Momjian 已提交
129 130 131 132
typedef struct _dumpContext
{
	TableInfo  *tblinfo;
	int			tblidx;
B
Bruce Momjian 已提交
133 134 135
	bool		oids;
} DumpContext;

136
static void
137
help(const char *progname)
138
{
139 140 141 142
	printf(gettext("%s dumps a database as a text file or to other formats.\n\n"), progname);
	puts(gettext("Usage:"));
	printf(gettext("  %s [options] dbname\n\n"), progname);
	puts(gettext("Options:"));
B
Hi,  
Bruce Momjian 已提交
143 144

#ifdef HAVE_GETOPT_LONG
145 146
	puts(gettext(
		"  -a, --data-only          dump only the data, not the schema\n"
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
		"  -b, --blobs              include large objects in dump\n"
		"  -c, --clean              clean (drop) schema prior to create\n"
		"  -C, --create             include commands to create database in dump\n"
		"  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"
		"  -D, --column-inserts     dump data as INSERT commands with column names\n"
		"  -f, --file=FILENAME      output file name\n"
		"  -F, --format {c|t|p}     output file format (custom, tar, plain text)\n"
		"  -h, --host=HOSTNAME      database server host name\n"
		"  -i, --ignore-version     proceed even when server version mismatches\n"
		"                           pg_dump version\n"
		"  -n, --no-quotes          suppress most quotes around identifiers\n"
		"  -N, --quotes             enable most quotes around identifiers\n"
		"  -o, --oids               include oids in dump\n"
		"  -O, --no-owner           do not output \\connect commands in plain\n"
		"                           text format\n"
		"  -p, --port=PORT          database server port number\n"
		"  -R, --no-reconnect       disable ALL reconnections to the database in\n"
		"                           plain text format\n"
		"  -s, --schema-only        dump only the schema, no data\n"
		"  -S, --superuser=NAME     specify the superuser user name to use in\n"
		"                           plain text format\n"
		"  -t, --table=TABLE        dump this table only (* for all)\n"
169
		"  -U, --username=NAME      connect as specified database user\n"
170 171 172 173 174 175 176 177
		"  -v, --verbose            verbose mode\n"
		"  -W, --password           force password prompt (should happen automatically)\n"
		"  -x, --no-privileges      do not dump privileges (grant/revoke)\n"
		"  -X use-set-session-authorization, --use-set-session-authorization\n"
		"                           output SET SESSION AUTHORIZATION commands rather\n"
		"                           than \\connect commands\n"
		"  -Z, --compress {0-9}     compression level for compressed formats\n"
	));
B
Hi,  
Bruce Momjian 已提交
178
#else
179 180
	puts(gettext(
		"  -a                       dump only the data, not the schema\n"
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
		"  -b                       include large objects in dump\n"
		"  -c                       clean (drop) schema prior to create\n"
		"  -C                       include commands to create database in dump\n"
		"  -d                       dump data as INSERT, rather than COPY, commands\n"
		"  -D                       dump data as INSERT commands with column names\n"
		"  -f FILENAME              output file name\n"
		"  -F {c|t|p}               output file format (custom, tar, plain text)\n"
		"  -h HOSTNAME              database server host name\n"
		"  -i                       proceed even when server version mismatches\n"
		"                           pg_dump version\n"
		"  -n                       suppress most quotes around identifiers\n"
		"  -N                       enable most quotes around identifiers\n"
		"  -o                       include oids in dump\n"
		"  -O                       do not output \\connect commands in plain\n"
		"                           text format\n"
		"  -p PORT                  database server port number\n"
		"  -R                       disable ALL reconnections to the database in\n"
		"                           plain text format\n"
		"  -s                       dump only the schema, no data\n"
		"  -S NAME                  specify the superuser user name to use in\n"
		"                           plain text format\n"
		"  -t TABLE                 dump this table only (* for all)\n"
203
		"  -U NAME                  connect as specified database user\n"
204 205 206 207 208 209 210 211
		"  -v                       verbose mode\n"
		"  -W                       force password prompt (should happen automatically)\n"
		"  -x                       do not dump privileges (grant/revoke)\n"
		"  -X use-set-session-authorization\n"
		"                           output SET SESSION AUTHORIZATION commands rather\n"
		"                           than \\connect commands\n"
		"  -Z {0-9}                 compression level for compressed formats\n"
	));
B
Hi,  
Bruce Momjian 已提交
212
#endif
213 214 215
	puts(gettext("If no database name is not supplied, then the PGDATABASE environment\n"
				 "variable value is used.\n\n"
				 "Report bugs to <pgsql-bugs@postgresql.org>."));
216 217
}

218

219 220
void
exit_nicely(void)
221
{
222 223 224
	PQfinish(g_conn);
	if (g_verbose)
		write_msg(NULL, "*** aborted because of error\n");
225
	exit(1);
226 227 228
}


229 230
#define COPYBUFSIZ		8192

B
Bruce Momjian 已提交
231 232 233 234 235
/*
 *	Dump a table's contents for loading using the COPY command
 *	- this routine is called by the Archiver when it wants the table
 *	  to be dumped.
 */
236

B
Bruce Momjian 已提交
237 238
static int
dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv)
239
{
B
Bruce Momjian 已提交
240 241
	const DumpContext *dctx = (DumpContext *) dctxv;
	const char *classname = dctx->tblinfo[dctx->tblidx].relname;
242
	const bool	hasoids = dctx->tblinfo[dctx->tblidx].hasoids;
B
Bruce Momjian 已提交
243
	const bool	oids = dctx->oids;
244

245 246 247 248 249
	PGresult   *res;
	char		query[255];
	int			ret;
	bool		copydone;
	char		copybuf[COPYBUFSIZ];
250

B
Bruce Momjian 已提交
251
	if (g_verbose)
252
		write_msg(NULL, "dumping out the contents of table %s\n", classname);
253

254
	if (oids && hasoids)
255
	{
B
Bruce Momjian 已提交
256
		/*
257
		 * archprintf(fout, "COPY %s WITH OIDS FROM stdin;\n",
B
Bruce Momjian 已提交
258
		 * fmtId(classname, force_quotes));
259
		 *
B
Bruce Momjian 已提交
260
		 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
261 262 263
		 *
		 */

264
		sprintf(query, "COPY %s WITH OIDS TO stdout;",
265
				fmtId(classname, force_quotes));
266 267 268
	}
	else
	{
B
Bruce Momjian 已提交
269 270 271
		/*
		 * archprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname,
		 * force_quotes));
272 273 274 275 276
		 *
		 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
		 *
		 */

277
		sprintf(query, "COPY %s TO stdout;", fmtId(classname, force_quotes));
278 279
	}
	res = PQexec(g_conn, query);
280 281
	if (!res ||
		PQresultStatus(res) == PGRES_FATAL_ERROR)
282
	{
283 284 285 286
		write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed\n",
				  classname);
		write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
		write_msg(NULL, "The command was: %s\n", query);
287
		exit_nicely();
288 289 290 291 292
	}
	else
	{
		if (PQresultStatus(res) != PGRES_COPY_OUT)
		{
293 294
			write_msg(NULL, "SQL command to dump the contents of table \"%s\" executed abnormally.\n",
					  classname);
295
			write_msg(NULL, "The server returned status %d when %d was expected.\n",
296 297
					  PQresultStatus(res), PGRES_COPY_OUT);
			write_msg(NULL, "The command was: %s\n", query);
298
			exit_nicely();
299 300 301 302
		}
		else
		{
			copydone = false;
303

304 305
			while (!copydone)
			{
306
				ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
307 308 309 310 311 312 313 314 315

				if (copybuf[0] == '\\' &&
					copybuf[1] == '.' &&
					copybuf[2] == '\0')
				{
					copydone = true;	/* don't print this... */
				}
				else
				{
B
Bruce Momjian 已提交
316
					archputs(copybuf, fout);
317 318
					switch (ret)
					{
319 320 321 322
						case EOF:
							copydone = true;
							/* FALLTHROUGH */
						case 0:
B
Bruce Momjian 已提交
323
							archputc('\n', fout);
324 325 326
							break;
						case 1:
							break;
327 328
					}
				}
329

B
Bruce Momjian 已提交
330
				/*
331 332
				 * THROTTLE:
				 *
B
Bruce Momjian 已提交
333 334 335 336 337
				 * There was considerable discussion in late July, 2000
				 * regarding slowing down pg_dump when backing up large
				 * tables. Users with both slow & fast (muti-processor)
				 * machines experienced performance degradation when doing
				 * a backup.
338
				 *
B
Bruce Momjian 已提交
339 340 341 342 343
				 * Initial attempts based on sleeping for a number of ms for
				 * each ms of work were deemed too complex, then a simple
				 * 'sleep in each loop' implementation was suggested. The
				 * latter failed because the loop was too tight. Finally,
				 * the following was implemented:
344
				 *
B
Bruce Momjian 已提交
345 346 347
				 * If throttle is non-zero, then See how long since the last
				 * sleep. Work out how long to sleep (based on ratio). If
				 * sleep is more than 100ms, then sleep reset timer EndIf
348 349
				 * EndIf
				 *
B
Bruce Momjian 已提交
350 351
				 * where the throttle value was the number of ms to sleep per
				 * ms of work. The calculation was done in each loop.
352
				 *
B
Bruce Momjian 已提交
353 354 355 356 357
				 * Most of the hard work is done in the backend, and this
				 * solution still did not work particularly well: on slow
				 * machines, the ratio was 50:1, and on medium paced
				 * machines, 1:1, and on fast multi-processor machines, it
				 * had little or no effect, for reasons that were unclear.
358 359 360
				 *
				 * Further discussion ensued, and the proposal was dropped.
				 *
B
Bruce Momjian 已提交
361 362 363 364 365 366
				 * For those people who want this feature, it can be
				 * implemented using gettimeofday in each loop,
				 * calculating the time since last sleep, multiplying that
				 * by the sleep ratio, then if the result is more than a
				 * preset 'minimum sleep time' (say 100ms), call the
				 * 'select' function to sleep for a subsecond period ie.
367
				 *
B
Bruce Momjian 已提交
368
				 * select(0, NULL, NULL, NULL, &tvi);
369
				 *
B
Bruce Momjian 已提交
370 371 372 373
				 * This will return after the interval specified in the
				 * structure tvi. Fianally, call gettimeofday again to
				 * save the 'last sleep time'.
				 */
374
			}
B
Bruce Momjian 已提交
375
			archprintf(fout, "\\.\n");
376
		}
377
		ret = PQendcopy(g_conn);
378 379
		if (ret != 0)
		{
380 381 382
			write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed: PQendcopy() failed.\n", classname);
			write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
			write_msg(NULL, "The command was: %s\n", query);
B
Bruce Momjian 已提交
383
			PQclear(res);
384
			exit_nicely();
385 386
		}
	}
387

B
Bruce Momjian 已提交
388
	return 1;
389 390
}

B
Bruce Momjian 已提交
391
static int
B
Bruce Momjian 已提交
392
dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
393
{
B
Bruce Momjian 已提交
394 395
	const DumpContext *dctx = (DumpContext *) dctxv;
	const char *classname = dctx->tblinfo[dctx->tblidx].relname;
B
Bruce Momjian 已提交
396

397 398
	PGresult   *res;
	PQExpBuffer q = createPQExpBuffer();
399 400
	int			tuple;
	int			field;
401

402
	if (fout->remoteVersion >= 70100)
403
		appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT * FROM ONLY %s", fmtId(classname, force_quotes));
404
	else
405
		appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT * FROM %s", fmtId(classname, force_quotes));
406

B
Hi, all  
Bruce Momjian 已提交
407
	res = PQexec(g_conn, q->data);
408
	if (!res ||
409
		PQresultStatus(res) != PGRES_COMMAND_OK)
410
	{
411 412 413
		write_msg(NULL, "dumpClasses(): SQL command failed\n");
		write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
		write_msg(NULL, "The command was: %s\n", q->data);
414
		exit_nicely();
415
	}
416 417 418

	do
	{
419 420 421 422 423
		PQclear(res);

		res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
424
		{
425 426 427 428
			write_msg(NULL, "dumpClasses(): SQL command failed\n");
			write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
			write_msg(NULL, "The command was: FETCH 100 FROM _pg_dump_cursor\n");
			exit_nicely();
429
		}
430 431

		for (tuple = 0; tuple < PQntuples(res); tuple++)
432
		{
433 434
			archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
			if (attrNames == true)
435
			{
436 437 438 439 440 441 442 443 444 445
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "(");
				for (field = 0; field < PQnfields(res); field++)
				{
					if (field > 0)
						appendPQExpBuffer(q, ",");
					appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
				}
				appendPQExpBuffer(q, ") ");
				archprintf(fout, "%s", q->data);
446
			}
447 448
			archprintf(fout, "VALUES (");
			for (field = 0; field < PQnfields(res); field++)
449
			{
450 451 452 453 454 455 456 457 458 459 460
				if (field > 0)
					archprintf(fout, ",");
				if (PQgetisnull(res, tuple, field))
				{
					archprintf(fout, "NULL");
					continue;
				}
				switch (PQftype(res, field))
				{
					case INT2OID:
					case INT4OID:
461
					case OIDOID:		/* int types */
462
					case FLOAT4OID:
463
					case FLOAT8OID:		/* float types */
464 465 466 467 468 469 470 471 472 473
						/* These types are printed without quotes */
						archprintf(fout, "%s",
								   PQgetvalue(res, tuple, field));
						break;
					case BITOID:
					case VARBITOID:
						archprintf(fout, "B'%s'",
								   PQgetvalue(res, tuple, field));
						break;
					default:
474

475 476
						/*
						 * All other types are printed as string literals,
477 478
						 * with appropriate escaping of special
						 * characters.
479 480 481 482 483 484
						 */
						resetPQExpBuffer(q);
						formatStringLiteral(q, PQgetvalue(res, tuple, field), CONV_ALL);
						archprintf(fout, "%s", q->data);
						break;
				}
485
			}
486
			archprintf(fout, ");\n");
487
		}
488

489
	} while (PQntuples(res) > 0);
490 491 492 493 494 495 496 497 498 499
	PQclear(res);

	res = PQexec(g_conn, "CLOSE _pg_dump_cursor");
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
		write_msg(NULL, "dumpClasses(): SQL command failed\n");
		write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
		write_msg(NULL, "The command was: CLOSE _pg_dump_cursor\n");
		exit_nicely();
500 501
	}
	PQclear(res);
502

503
	destroyPQExpBuffer(q);
B
Bruce Momjian 已提交
504
	return 1;
505 506
}

507 508 509 510 511 512 513 514
/*
 * Convert a string value to an SQL string literal,
 * with appropriate escaping of special characters.
 * Quote mark ' goes to '' per SQL standard, other
 * stuff goes to \ sequences.
 * The literal is appended to the given PQExpBuffer.
 */
static void
515
formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts)
516 517 518 519
{
	appendPQExpBufferChar(buf, '\'');
	while (*str)
	{
B
Bruce Momjian 已提交
520
		char		ch = *str++;
521 522 523

		if (ch == '\\' || ch == '\'')
		{
B
Bruce Momjian 已提交
524
			appendPQExpBufferChar(buf, ch);		/* double these */
525 526 527
			appendPQExpBufferChar(buf, ch);
		}
		else if ((unsigned char) ch < (unsigned char) ' ' &&
B
Bruce Momjian 已提交
528 529 530
				 (opts == CONV_ALL
				  || (ch != '\n' && ch != '\t')
				  ))
531
		{
B
Bruce Momjian 已提交
532 533 534 535
			/*
			 * generate octal escape for control chars other than
			 * whitespace
			 */
536 537 538 539 540 541 542 543 544 545 546
			appendPQExpBufferChar(buf, '\\');
			appendPQExpBufferChar(buf, ((ch >> 6) & 3) + '0');
			appendPQExpBufferChar(buf, ((ch >> 3) & 7) + '0');
			appendPQExpBufferChar(buf, (ch & 7) + '0');
		}
		else
			appendPQExpBufferChar(buf, ch);
	}
	appendPQExpBufferChar(buf, '\'');
}

547 548
/*
 * DumpClasses -
549
 *	  dump the contents of all the classes.
550 551
 */
static void
B
Bruce Momjian 已提交
552
dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
B
Bruce Momjian 已提交
553
		 const char *onlytable, const bool oids, const bool force_quotes)
554
{
B
Bruce Momjian 已提交
555 556 557 558 559 560
	int			i;
	DataDumperPtr dumpFn;
	DumpContext *dumpCtx;
	char		copyBuf[512];
	char	   *copyStmt;

561
	if (g_verbose)
562 563 564 565 566 567
	{
		if (onlytable == NULL || (strlen(onlytable) == 0))
			write_msg(NULL, "preparing to dump the contents of all %d tables/sequences\n", numTables);
		else
			write_msg(NULL, "preparing to dump the contents of only one table/sequence\n");
	}
568

569 570
	for (i = 0; i < numTables; i++)
	{
571
		const char *classname = tblinfo[i].relname;
572 573

		/* Skip VIEW relations */
574
		if (tblinfo[i].viewdef != NULL)
575
			continue;
576

577
		if (tblinfo[i].sequence)	/* already dumped */
V
Vadim B. Mikheev 已提交
578
			continue;
579

580
		if (!onlytable || (strcmp(classname, onlytable) == 0) || (strlen(onlytable) == 0))
581 582
		{
			if (g_verbose)
583
				write_msg(NULL, "preparing to dump the contents of table %s\n", classname);
584

585 586 587
#if 0
			becomeUser(fout, tblinfo[i].usename);
#endif
B
Bruce Momjian 已提交
588

B
Bruce Momjian 已提交
589 590
			dumpCtx = (DumpContext *) malloc(sizeof(DumpContext));
			dumpCtx->tblinfo = (TableInfo *) tblinfo;
B
Bruce Momjian 已提交
591 592
			dumpCtx->tblidx = i;
			dumpCtx->oids = oids;
593

594
			if (!dumpData)
595
			{
596
				/* Dump/restore using COPY */
B
Bruce Momjian 已提交
597
				dumpFn = dumpClasses_nodumpData;
598 599 600
				sprintf(copyBuf, "COPY %s %sFROM stdin;\n",
						fmtId(tblinfo[i].relname, force_quotes),
						(oids && tblinfo[i].hasoids) ? "WITH OIDS " : "");
601 602
				copyStmt = copyBuf;
			}
B
Bruce Momjian 已提交
603
			else
604
			{
605
				/* Restore using INSERT */
B
Bruce Momjian 已提交
606
				dumpFn = dumpClasses_dumpData;
607 608
				copyStmt = NULL;
			}
B
Bruce Momjian 已提交
609

P
Philip Warner 已提交
610
			ArchiveEntry(fout, tblinfo[i].oid, tblinfo[i].relname,
611 612
						 "TABLE DATA", NULL, "", "",
						 copyStmt, tblinfo[i].usename,
B
Bruce Momjian 已提交
613
						 dumpFn, dumpCtx);
614
		}
615
	}
616 617
}

618 619 620


static int
621
parse_version(const char *versionString)
622 623
{
	int			cnt;
624 625 626
	int			vmaj,
				vmin,
				vrev;
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643

	cnt = sscanf(versionString, "%d.%d.%d", &vmaj, &vmin, &vrev);

	if (cnt < 2)
	{
		write_msg(NULL, "unable to parse version string \"%s\"\n", versionString);
		exit(1);
	}

	if (cnt == 2)
		vrev = 0;

	return (100 * vmaj + vmin) * 100 + vrev;
}



644
int
645
main(int argc, char **argv)
646
{
B
Bruce Momjian 已提交
647 648
	int			c;
	const char *filename = NULL;
B
Bruce Momjian 已提交
649
	const char *format = "p";
B
Bruce Momjian 已提交
650 651 652
	const char *dbname = NULL;
	const char *pghost = NULL;
	const char *pgport = NULL;
653
	const char *username = NULL;
B
Bruce Momjian 已提交
654
	char	   *tablename = NULL;
655
	bool		oids = false;
B
Bruce Momjian 已提交
656 657
	TableInfo  *tblinfo;
	int			numTables;
658
	bool		force_password = false;
B
Bruce Momjian 已提交
659
	int			compressLevel = -1;
660
	bool		ignore_version = false;
661 662
	int			plainText = 0;
	int			outputClean = 0;
663
	int			outputCreate = 0;
664
	int			outputBlobs = 0;
665 666
	int			outputNoOwner = 0;
	int			outputNoReconnect = 0;
667
	static int	use_setsessauth = 0;
B
Bruce Momjian 已提交
668
	char	   *outputSuperuser = NULL;
669

B
Bruce Momjian 已提交
670
	RestoreOptions *ropt;
671

B
Hi,  
Bruce Momjian 已提交
672 673 674
#ifdef HAVE_GETOPT_LONG
	static struct option long_options[] = {
		{"data-only", no_argument, NULL, 'a'},
B
Bruce Momjian 已提交
675
		{"blobs", no_argument, NULL, 'b'},
B
Hi,  
Bruce Momjian 已提交
676
		{"clean", no_argument, NULL, 'c'},
677
		{"create", no_argument, NULL, 'C'},
B
Bruce Momjian 已提交
678 679
		{"file", required_argument, NULL, 'f'},
		{"format", required_argument, NULL, 'F'},
680
		{"inserts", no_argument, NULL, 'd'},
681
		{"attribute-inserts", no_argument, NULL, 'D'},
682
		{"column-inserts", no_argument, NULL, 'D'},
B
Hi,  
Bruce Momjian 已提交
683
		{"host", required_argument, NULL, 'h'},
684
		{"ignore-version", no_argument, NULL, 'i'},
685
		{"no-reconnect", no_argument, NULL, 'R'},
B
Hi,  
Bruce Momjian 已提交
686 687
		{"no-quotes", no_argument, NULL, 'n'},
		{"quotes", no_argument, NULL, 'N'},
688
		{"oids", no_argument, NULL, 'o'},
689
		{"no-owner", no_argument, NULL, 'O'},
B
Hi,  
Bruce Momjian 已提交
690 691
		{"port", required_argument, NULL, 'p'},
		{"schema-only", no_argument, NULL, 's'},
692
		{"superuser", required_argument, NULL, 'S'},
B
Hi,  
Bruce Momjian 已提交
693
		{"table", required_argument, NULL, 't'},
694 695
		{"password", no_argument, NULL, 'W'},
		{"username", required_argument, NULL, 'U'},
B
Hi,  
Bruce Momjian 已提交
696
		{"verbose", no_argument, NULL, 'v'},
697
		{"no-privileges", no_argument, NULL, 'x'},
B
Hi,  
Bruce Momjian 已提交
698
		{"no-acl", no_argument, NULL, 'x'},
B
Bruce Momjian 已提交
699
		{"compress", required_argument, NULL, 'Z'},
B
Hi,  
Bruce Momjian 已提交
700
		{"help", no_argument, NULL, '?'},
701 702
		{"version", no_argument, NULL, 'V'},

703 704 705 706
		/*
		 * the following options don't have an equivalent short option
		 * letter, but are available as '-X long-name'
		 */
707
		{"use-set-session-authorization", no_argument, &use_setsessauth, 1}
708
	};
709
	int			optindex;
B
Hi,  
Bruce Momjian 已提交
710 711
#endif

712 713 714 715 716 717
#ifdef ENABLE_NLS
	setlocale(LC_ALL, "");
	bindtextdomain("pg_dump", LOCALEDIR);
	textdomain("pg_dump");
#endif

718
	g_verbose = false;
719
	force_quotes = true;
720 721 722 723 724

	strcpy(g_comment_start, "-- ");
	g_comment_end[0] = '\0';
	strcpy(g_opaque_type, "opaque");

725
	dataOnly = schemaOnly = dumpData = attrNames = false;
726

727
	if (!strrchr(argv[0], '/'))
728 729
		progname = argv[0];
	else
730
		progname = strrchr(argv[0], '/') + 1;
731

732
	/* Set default options based on progname */
733 734 735
	if (strcmp(progname, "pg_backup") == 0)
	{
		format = "c";
P
Philip Warner 已提交
736
		outputBlobs = true;
737
	}
738

739 740
	if (argc > 1)
	{
B
Bruce Momjian 已提交
741
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
742 743 744 745
		{
			help(progname);
			exit(0);
		}
B
Bruce Momjian 已提交
746
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
747
		{
748
			puts("pg_dump (PostgreSQL) " PG_VERSION);
749 750 751 752
			exit(0);
		}
	}

B
Hi,  
Bruce Momjian 已提交
753
#ifdef HAVE_GETOPT_LONG
754
	while ((c = getopt_long(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uU:vWxX:zZ:V?", long_options, &optindex)) != -1)
B
Hi,  
Bruce Momjian 已提交
755
#else
756
	while ((c = getopt(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uU:vWxX:zZ:V?-")) != -1)
B
Hi,  
Bruce Momjian 已提交
757
#endif
758

759 760 761
	{
		switch (c)
		{
762
			case 'a':			/* Dump data only */
763
				dataOnly = true;
764
				break;
765

766 767 768 769
			case 'b':			/* Dump blobs */
				outputBlobs = true;
				break;

B
Bruce Momjian 已提交
770
			case 'c':			/* clean (i.e., drop) schema prior to
B
Bruce Momjian 已提交
771
								 * create */
B
Bruce Momjian 已提交
772
				outputClean = 1;
B
Bruce Momjian 已提交
773 774
				break;

775 776 777 778 779
			case 'C':			/* Create DB */

				outputCreate = 1;
				break;

780
			case 'd':			/* dump data as proper insert strings */
781
				dumpData = true;
782
				break;
783

784 785
			case 'D':			/* dump data as proper insert strings with
								 * attr names */
786 787
				dumpData = true;
				attrNames = true;
788
				break;
789

790
			case 'f':
791 792
				filename = optarg;
				break;
793

B
Bruce Momjian 已提交
794 795 796
			case 'F':
				format = optarg;
				break;
797

B
Bruce Momjian 已提交
798
			case 'h':			/* server host */
799 800
				pghost = optarg;
				break;
801

802 803 804
			case 'i':			/* ignore database version mismatch */
				ignore_version = true;
				break;
805

B
Bruce Momjian 已提交
806 807
			case 'n':			/* Do not force double-quotes on
								 * identifiers */
808
				force_quotes = false;
809
				break;
810

811
			case 'N':			/* Force double-quotes on identifiers */
812
				force_quotes = true;
813
				break;
814

815
			case 'o':			/* Dump oids */
816
				oids = true;
817
				break;
818 819


820 821 822
			case 'O':			/* Don't reconnect to match owner */
				outputNoOwner = 1;
				break;
823

824 825 826
			case 'p':			/* server port */
				pgport = optarg;
				break;
827

828 829 830
			case 'R':			/* No reconnect */
				outputNoReconnect = 1;
				break;
831

832
			case 's':			/* dump schema only */
833
				schemaOnly = true;
834
				break;
835

B
Bruce Momjian 已提交
836 837
			case 'S':			/* Username for superuser in plain text
								 * output */
838 839
				outputSuperuser = strdup(optarg);
				break;
840

841
			case 't':			/* Dump data for this table only */
842
				{
843
					int			i;
844 845

					tablename = strdup(optarg);
B
Bruce Momjian 已提交
846 847 848 849 850

					/*
					 * quoted string? Then strip quotes and preserve
					 * case...
					 */
851 852 853
					if (tablename[0] == '"')
					{
						strcpy(tablename, &tablename[1]);
B
Bruce Momjian 已提交
854 855
						if (*(tablename + strlen(tablename) - 1) == '"')
							*(tablename + strlen(tablename) - 1) = '\0';
856 857 858 859 860
					}
					/* otherwise, convert table name to lowercase... */
					else
					{
						for (i = 0; tablename[i]; i++)
861 862
							if (isupper((unsigned char) tablename[i]))
								tablename[i] = tolower((unsigned char) tablename[i]);
863

B
Bruce Momjian 已提交
864 865 866 867 868
						/*
						 * '*' is a special case meaning ALL tables, but
						 * only if unquoted
						 */
						if (strcmp(tablename, "*") == 0)
869 870
							tablename[0] = '\0';

871
					}
872
				}
873
				break;
874

875
			case 'u':
876
				force_password = true;
877
				username = simple_prompt("User name: ", 100, true);
878 879 880 881
				break;

			case 'U':
				username = optarg;
882
				break;
883

884 885
			case 'v':			/* verbose */
				g_verbose = true;
886
				break;
887

888 889 890 891
			case 'W':
				force_password = true;
				break;

892 893
			case 'x':			/* skip ACL dump */
				aclsSkip = true;
894
				break;
895

896
				/*
897
				 * Option letters were getting scarce, so I invented this
898 899 900 901
				 * new scheme: '-X feature' turns on some feature. Compare
				 * to the -f option in GCC.  You should also add an
				 * equivalent GNU-style option --feature.  Features that
				 * require arguments should use '-X feature=foo'.
902 903
				 */
			case 'X':
904
				if (strcmp(optarg, "use-set-session-authorization") == 0)
905 906 907 908 909 910 911 912 913 914
					use_setsessauth = 1;
				else
				{
					fprintf(stderr,
							gettext("%s: invalid -X option -- %s\n"),
							progname, optarg);
					fprintf(stderr, gettext("Try '%s --help' for more information.\n"), progname);
					exit(1);
				}
				break;
B
Bruce Momjian 已提交
915 916 917
			case 'Z':			/* Compression Level */
				compressLevel = atoi(optarg);
				break;
918

919 920
#ifndef HAVE_GETOPT_LONG
			case '-':
921 922
				fprintf(stderr,
						gettext("%s was compiled without support for long options.\n"
923
						 "Use --help for help on invocation options.\n"),
924
						progname);
925 926
				exit(1);
				break;
927 928 929 930
#else
				/* This covers the long options equivalent to -X xxx. */
			case 0:
				break;
931
#endif
932
			default:
933
				fprintf(stderr, gettext("Try '%s --help' for more information.\n"), progname);
934
				exit(1);
935 936 937
		}
	}

B
Bruce Momjian 已提交
938 939
	if (optind < (argc - 1))
	{
P
Philip Warner 已提交
940
		fprintf(stderr,
941 942
			gettext("%s: too many command line options (first is '%s')\n"
					"Try '%s --help' for more information.\n"),
943
				progname, argv[optind + 1], progname);
P
Philip Warner 已提交
944 945 946
		exit(1);
	}

947 948 949 950 951 952 953
	/* Get the target database name */
	if (optind < argc)
		dbname = argv[optind];
	else
		dbname = getenv("PGDATABASE");
	if (!dbname)
	{
954
		write_msg(NULL, "no database name specified\n");
955 956 957
		exit(1);
	}

B
Bruce Momjian 已提交
958 959
	if (dataOnly && schemaOnly)
	{
960
		write_msg(NULL, "The options \"schema only\" (-s) and \"data only\" (-a) cannot be used together.\n");
B
Bruce Momjian 已提交
961 962 963
		exit(1);
	}

B
Bruce Momjian 已提交
964
	if (outputBlobs && tablename != NULL && strlen(tablename) > 0)
965
	{
966
		write_msg(NULL, "Large object output is not supported for a single table.\n");
967
		write_msg(NULL, "Use all tables or a full dump instead.\n");
968 969 970
		exit(1);
	}

971 972
	if (dumpData == true && oids == true)
	{
973 974
		write_msg(NULL, "INSERT (-d, -D) and OID (-o) options cannot be used together.\n");
		write_msg(NULL, "(The INSERT command cannot set oids.)\n");
975
		exit(1);
976
	}
977

B
Bruce Momjian 已提交
978
	if (outputBlobs == true && (format[0] == 'p' || format[0] == 'P'))
P
Philip Warner 已提交
979
	{
980
		write_msg(NULL, "large object output is not supported for plain text dump files.\n");
981
		write_msg(NULL, "(Use a different output format.)\n");
P
Philip Warner 已提交
982 983 984
		exit(1);
	}

985
	/* open the output file */
B
Bruce Momjian 已提交
986 987
	switch (format[0])
	{
B
Bruce Momjian 已提交
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001

		case 'c':
		case 'C':
			g_fout = CreateArchive(filename, archCustom, compressLevel);
			break;

		case 'f':
		case 'F':
			g_fout = CreateArchive(filename, archFiles, compressLevel);
			break;

		case 'p':
		case 'P':
			plainText = 1;
1002 1003 1004 1005 1006 1007
			g_fout = CreateArchive(filename, archNull, 0);
			break;

		case 't':
		case 'T':
			g_fout = CreateArchive(filename, archTar, compressLevel);
B
Bruce Momjian 已提交
1008 1009 1010
			break;

		default:
1011
			write_msg(NULL, "invalid output format '%s' specified\n", format);
B
Bruce Momjian 已提交
1012
			exit(1);
B
Bruce Momjian 已提交
1013 1014 1015 1016
	}

	if (g_fout == NULL)
	{
1017
		write_msg(NULL, "could not open output file %s for writing\n", filename);
B
Bruce Momjian 已提交
1018
		exit(1);
1019 1020
	}

1021 1022
	/* Let the archiver know how noisy to be */
	g_fout->verbose = g_verbose;
1023

B
Bruce Momjian 已提交
1024 1025
	/*
	 * Open the database using the Archiver, so it knows about it. Errors
1026
	 * mean death.
B
Bruce Momjian 已提交
1027
	 */
1028
	g_fout->minRemoteVersion = 70000;	/* we can handle back to 7.0 */
1029
	g_fout->maxRemoteVersion = parse_version(PG_VERSION);
1030
	g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, username, force_password, ignore_version);
1031

1032 1033 1034 1035 1036 1037 1038 1039
	/*
	 * Start serializable transaction to dump consistent data
	 */
	{
		PGresult   *res;

		res = PQexec(g_conn, "begin");
		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
1040
			exit_horribly(g_fout, NULL, "BEGIN command failed: %s",
B
Bruce Momjian 已提交
1041
						  PQerrorMessage(g_conn));
1042

1043 1044 1045
		PQclear(res);
		res = PQexec(g_conn, "set transaction isolation level serializable");
		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
1046
			exit_horribly(g_fout, NULL, "could not set transaction isolation level to serializable: %s",
B
Bruce Momjian 已提交
1047
						  PQerrorMessage(g_conn));
1048

1049 1050 1051
		PQclear(res);
	}

1052 1053 1054 1055
	if (g_fout->remoteVersion >= 70100)
		g_last_builtin_oid = findLastBuiltinOid_V71(dbname);
	else
		g_last_builtin_oid = findLastBuiltinOid_V70();
1056

1057 1058 1059 1060
	/* Dump the database definition */
	if (!dataOnly)
		dumpDatabase(g_fout);

1061
	if (oids == true)
1062
		setMaxOid(g_fout);
B
Bruce Momjian 已提交
1063 1064

	if (g_verbose)
1065
		write_msg(NULL, "last built-in oid is %u\n", g_last_builtin_oid);
B
Bruce Momjian 已提交
1066
	tblinfo = dumpSchema(g_fout, &numTables, tablename, aclsSkip, oids, schemaOnly, dataOnly);
1067

1068
	if (!schemaOnly)
B
Bruce Momjian 已提交
1069
		dumpClasses(tblinfo, numTables, g_fout, tablename, oids, force_quotes);
1070 1071

	if (outputBlobs)
B
Bruce Momjian 已提交
1072
		ArchiveEntry(g_fout, "0", "BLOBS", "BLOBS", NULL, "", "", "", "", dumpBlobs, 0);
1073

1074 1075
	if (!dataOnly)				/* dump indexes and triggers at the end
								 * for performance */
V
Vadim B. Mikheev 已提交
1076 1077
	{
		dumpTriggers(g_fout, tablename, tblinfo, numTables);
1078
		dumpRules(g_fout, tablename, tblinfo, numTables);
V
Vadim B. Mikheev 已提交
1079
	}
1080

1081 1082
	/* Now sort the output nicely */
	SortTocByOID(g_fout);
1083
	MoveToStart(g_fout, "DATABASE");
1084 1085 1086
	MoveToEnd(g_fout, "TABLE DATA");
	MoveToEnd(g_fout, "BLOBS");
	MoveToEnd(g_fout, "INDEX");
1087
	MoveToEnd(g_fout, "CONSTRAINT");
1088 1089
	MoveToEnd(g_fout, "TRIGGER");
	MoveToEnd(g_fout, "RULE");
1090
	MoveToEnd(g_fout, "SEQUENCE SET");
1091

1092 1093 1094 1095 1096 1097
	/*
	 * Moving all comments to end is annoying, but must do it for comments
	 * on stuff we just moved, and we don't seem to have quite enough
	 * dependency structure to get it really right...
	 */
	MoveToEnd(g_fout, "COMMENT");
1098

B
Bruce Momjian 已提交
1099
	if (plainText)
B
Bruce Momjian 已提交
1100 1101
	{
		ropt = NewRestoreOptions();
B
Bruce Momjian 已提交
1102
		ropt->filename = (char *) filename;
B
Bruce Momjian 已提交
1103 1104
		ropt->dropSchema = outputClean;
		ropt->aclsSkip = aclsSkip;
1105 1106 1107 1108
		ropt->superuser = outputSuperuser;
		ropt->create = outputCreate;
		ropt->noOwner = outputNoOwner;
		ropt->noReconnect = outputNoReconnect;
1109
		ropt->use_setsessauth = use_setsessauth;
1110 1111 1112 1113 1114

		if (outputSuperuser)
			ropt->superuser = outputSuperuser;
		else
			ropt->superuser = PQuser(g_conn);
B
Bruce Momjian 已提交
1115 1116

		if (compressLevel == -1)
B
Bruce Momjian 已提交
1117
			ropt->compression = 0;
B
Bruce Momjian 已提交
1118
		else
B
Bruce Momjian 已提交
1119
			ropt->compression = compressLevel;
B
Bruce Momjian 已提交
1120

1121 1122
		ropt->suppressDumpWarnings = true;		/* We've already shown
												 * them */
1123

B
Bruce Momjian 已提交
1124 1125 1126 1127
		RestoreArchive(g_fout, ropt);
	}

	CloseArchive(g_fout);
1128

1129 1130 1131
	clearTableInfo(tblinfo, numTables);
	PQfinish(g_conn);
	exit(0);
1132 1133
}

1134 1135 1136 1137 1138
/*
 * dumpDatabase:
 *	dump the database definition
 *
 */
B
Bruce Momjian 已提交
1139
static int
1140 1141
dumpDatabase(Archive *AH)
{
B
Bruce Momjian 已提交
1142 1143 1144 1145 1146
	PQExpBuffer dbQry = createPQExpBuffer();
	PQExpBuffer delQry = createPQExpBuffer();
	PQExpBuffer creaQry = createPQExpBuffer();
	PGresult   *res;
	int			ntups;
1147 1148 1149 1150 1151 1152 1153 1154 1155
	int			i_dba,
				i_encoding,
				i_datpath;
	const char *datname,
			   *dba,
			   *encoding,
			   *datpath;

	datname = PQdb(g_conn);
1156 1157

	if (g_verbose)
1158
		write_msg(NULL, "saving database definition\n");
1159

1160 1161 1162
	/* Get the database owner and parameters from pg_database */
	appendPQExpBuffer(dbQry, "select (select usename from pg_user where usesysid = datdba) as dba,"
					  " encoding, datpath from pg_database"
B
Bruce Momjian 已提交
1163
					  " where datname = ");
1164
	formatStringLiteral(dbQry, datname, CONV_ALL);
1165 1166 1167 1168 1169

	res = PQexec(g_conn, dbQry->data);
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
1170 1171 1172
		write_msg(NULL, "SQL command failed\n");
		write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
		write_msg(NULL, "The command was: %s\n", dbQry->data);
1173
		exit_nicely();
1174 1175 1176 1177
	}

	ntups = PQntuples(res);

1178 1179
	if (ntups <= 0)
	{
1180 1181
		write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
				  datname);
1182
		exit_nicely();
1183 1184
	}

1185 1186
	if (ntups != 1)
	{
1187
		write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1188
				  ntups, datname);
1189
		exit_nicely();
1190 1191 1192
	}

	i_dba = PQfnumber(res, "dba");
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
	i_encoding = PQfnumber(res, "encoding");
	i_datpath = PQfnumber(res, "datpath");
	dba = PQgetvalue(res, 0, i_dba);
	encoding = PQgetvalue(res, 0, i_encoding);
	datpath = PQgetvalue(res, 0, i_datpath);

	appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
					  fmtId(datname, force_quotes));
	if (strlen(encoding) > 0)
		appendPQExpBuffer(creaQry, " ENCODING = %s", encoding);
	if (strlen(datpath) > 0)
		appendPQExpBuffer(creaQry, " LOCATION = '%s'", datpath);
	appendPQExpBuffer(creaQry, ";\n");

	appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
					  fmtId(datname, force_quotes));

	ArchiveEntry(AH, "0" /* OID */ , datname /* Name */ , "DATABASE", NULL,
B
Bruce Momjian 已提交
1211
				 creaQry->data /* Create */ , delQry->data /* Del */ ,
1212
				 "" /* Copy */ , dba /* Owner */ ,
B
Bruce Momjian 已提交
1213
				 NULL /* Dumper */ , NULL /* Dumper Arg */ );
1214 1215 1216

	PQclear(res);

1217 1218 1219 1220
	destroyPQExpBuffer(dbQry);
	destroyPQExpBuffer(delQry);
	destroyPQExpBuffer(creaQry);

1221 1222 1223 1224
	return 1;
}


1225 1226 1227 1228 1229 1230
/*
 * dumpBlobs:
 *	dump all blobs
 *
 */

B
Bruce Momjian 已提交
1231
#define loBufSize 16384
1232 1233
#define loFetchSize 1000

B
Bruce Momjian 已提交
1234 1235
static int
dumpBlobs(Archive *AH, char *junkOid, void *junkVal)
1236
{
B
Bruce Momjian 已提交
1237 1238 1239 1240 1241 1242 1243
	PQExpBuffer oidQry = createPQExpBuffer();
	PQExpBuffer oidFetchQry = createPQExpBuffer();
	PGresult   *res;
	int			i;
	int			loFd;
	char		buf[loBufSize];
	int			cnt;
1244
	Oid			blobOid;
1245 1246

	if (g_verbose)
1247
		write_msg(NULL, "saving large objects\n");
1248 1249

	/* Cursor to get all BLOB tables */
1250 1251
	if (AH->remoteVersion >= 70100)
		appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject");
1252
	else
1253
		appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT oid from pg_class where relkind = 'l'");
1254 1255 1256 1257

	res = PQexec(g_conn, oidQry->data);
	if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
	{
1258
		write_msg(NULL, "dumpBlobs(): cursor declaration failed: %s", PQerrorMessage(g_conn));
1259
		exit_nicely();
1260 1261 1262 1263 1264
	}

	/* Fetch for cursor */
	appendPQExpBuffer(oidFetchQry, "Fetch %d in blobOid", loFetchSize);

B
Bruce Momjian 已提交
1265 1266
	do
	{
1267 1268 1269 1270 1271 1272
		/* Do a fetch */
		PQclear(res);
		res = PQexec(g_conn, oidFetchQry->data);

		if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
		{
1273 1274
			write_msg(NULL, "dumpBlobs(): fetch from cursor failed: %s",
					  PQerrorMessage(g_conn));
1275
			exit_nicely();
1276 1277 1278 1279 1280
		}

		/* Process the tuples, if any */
		for (i = 0; i < PQntuples(res); i++)
		{
1281
			blobOid = atooid(PQgetvalue(res, i, 0));
1282 1283 1284 1285
			/* Open the BLOB */
			loFd = lo_open(g_conn, blobOid, INV_READ);
			if (loFd == -1)
			{
1286 1287
				write_msg(NULL, "dumpBlobs(): could not open large object: %s",
						  PQerrorMessage(g_conn));
1288
				exit_nicely();
1289 1290 1291 1292 1293
			}

			StartBlob(AH, blobOid);

			/* Now read it in chunks, sending data to archive */
B
Bruce Momjian 已提交
1294 1295
			do
			{
1296
				cnt = lo_read(g_conn, loFd, buf, loBufSize);
B
Bruce Momjian 已提交
1297 1298
				if (cnt < 0)
				{
1299 1300
					write_msg(NULL, "dumpBlobs(): error reading large object: %s",
							  PQerrorMessage(g_conn));
1301
					exit_nicely();
1302 1303
				}

B
Bruce Momjian 已提交
1304
				WriteData(AH, buf, cnt);
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314

			} while (cnt > 0);

			lo_close(g_conn, loFd);

			EndBlob(AH, blobOid);

		}
	} while (PQntuples(res) > 0);

1315 1316 1317
	destroyPQExpBuffer(oidQry);
	destroyPQExpBuffer(oidFetchQry);

1318 1319 1320
	return 1;
}

1321
/*
1322 1323
 * getTypes:
 *	  read all base types in the system catalogs and return them in the
1324 1325
 * TypeInfo* structure
 *
1326
 *	numTypes is set to the number of types read in
1327 1328
 *
 */
1329
TypeInfo *
1330 1331
getTypes(int *numTypes)
{
B
Bruce Momjian 已提交
1332
	PGresult   *res;
1333 1334
	int			ntups;
	int			i;
1335
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1336
	TypeInfo   *tinfo;
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350

	int			i_oid;
	int			i_typowner;
	int			i_typname;
	int			i_typlen;
	int			i_typprtlen;
	int			i_typinput;
	int			i_typoutput;
	int			i_typreceive;
	int			i_typsend;
	int			i_typelem;
	int			i_typdelim;
	int			i_typdefault;
	int			i_typrelid;
1351 1352
	int			i_typalign;
	int			i_typstorage;
1353
	int			i_typbyval;
1354
	int			i_typisdefined;
1355
	int			i_usename;
1356
	int			i_typedefn;
1357
	int			i_typtype;
1358 1359 1360 1361 1362 1363

	/* find all base types */

	/*
	 * we include even the built-in types because those may be used as
	 * array elements by user-defined types
1364
	 *
1365 1366 1367
	 * we filter out the built-in types when we dump out the types
	 */

1368 1369 1370
	if (g_fout->remoteVersion < 70100)
	{
		appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
1371 1372 1373
		  "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
						  "typdefault, typrelid, typalign, 'p'::char as typstorage, typbyval, typisdefined, "
						  "(select usename from pg_user where typowner = usesysid) as usename, "
1374
						  "typname as typedefn, typtype "
1375 1376 1377 1378
						  "from pg_type");
	}
	else
	{
1379
		appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
1380 1381 1382
		  "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
						  "typdefault, typrelid, typalign, typstorage, typbyval, typisdefined, "
						  "(select usename from pg_user where typowner = usesysid) as usename, "
1383
						  "format_type(pg_type.oid, NULL) as typedefn, typtype "
1384
						  "from pg_type");
1385
	}
1386

B
Hi, all  
Bruce Momjian 已提交
1387
	res = PQexec(g_conn, query->data);
1388 1389 1390
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
1391
		write_msg(NULL, "query to obtain list of data types failed: %s", PQerrorMessage(g_conn));
1392
		exit_nicely();
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
	}

	ntups = PQntuples(res);

	tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));

	i_oid = PQfnumber(res, "oid");
	i_typowner = PQfnumber(res, "typowner");
	i_typname = PQfnumber(res, "typname");
	i_typlen = PQfnumber(res, "typlen");
	i_typprtlen = PQfnumber(res, "typprtlen");
	i_typinput = PQfnumber(res, "typinput");
	i_typoutput = PQfnumber(res, "typoutput");
	i_typreceive = PQfnumber(res, "typreceive");
	i_typsend = PQfnumber(res, "typsend");
	i_typelem = PQfnumber(res, "typelem");
	i_typdelim = PQfnumber(res, "typdelim");
	i_typdefault = PQfnumber(res, "typdefault");
	i_typrelid = PQfnumber(res, "typrelid");
1412 1413
	i_typalign = PQfnumber(res, "typalign");
	i_typstorage = PQfnumber(res, "typstorage");
1414
	i_typbyval = PQfnumber(res, "typbyval");
1415
	i_typisdefined = PQfnumber(res, "typisdefined");
1416
	i_usename = PQfnumber(res, "usename");
1417
	i_typedefn = PQfnumber(res, "typedefn");
1418
	i_typtype = PQfnumber(res, "typtype");
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432

	for (i = 0; i < ntups; i++)
	{
		tinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
		tinfo[i].typowner = strdup(PQgetvalue(res, i, i_typowner));
		tinfo[i].typname = strdup(PQgetvalue(res, i, i_typname));
		tinfo[i].typlen = strdup(PQgetvalue(res, i, i_typlen));
		tinfo[i].typprtlen = strdup(PQgetvalue(res, i, i_typprtlen));
		tinfo[i].typinput = strdup(PQgetvalue(res, i, i_typinput));
		tinfo[i].typoutput = strdup(PQgetvalue(res, i, i_typoutput));
		tinfo[i].typreceive = strdup(PQgetvalue(res, i, i_typreceive));
		tinfo[i].typsend = strdup(PQgetvalue(res, i, i_typsend));
		tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
		tinfo[i].typdelim = strdup(PQgetvalue(res, i, i_typdelim));
1433 1434 1435 1436
		if (PQgetisnull(res, i, i_typdefault))
			tinfo[i].typdefault = NULL;
		else
			tinfo[i].typdefault = strdup(PQgetvalue(res, i, i_typdefault));
1437
		tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
1438 1439
		tinfo[i].typalign = strdup(PQgetvalue(res, i, i_typalign));
		tinfo[i].typstorage = strdup(PQgetvalue(res, i, i_typstorage));
1440
		tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1441
		tinfo[i].typedefn = strdup(PQgetvalue(res, i, i_typedefn));
1442
		tinfo[i].typtype = strdup(PQgetvalue(res, i, i_typtype));
1443

1444
		if (strlen(tinfo[i].usename) == 0)
1445 1446
			write_msg(NULL, "WARNING: owner of data type %s appears to be invalid\n",
					  tinfo[i].typname);
1447

1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460
		if (strcmp(PQgetvalue(res, i, i_typbyval), "f") == 0)
			tinfo[i].passedbyvalue = 0;
		else
			tinfo[i].passedbyvalue = 1;

		/*
		 * check for user-defined array types, omit system generated ones
		 */
		if ((strcmp(tinfo[i].typelem, "0") != 0) &&
			tinfo[i].typname[0] != '_')
			tinfo[i].isArray = 1;
		else
			tinfo[i].isArray = 0;
1461 1462 1463 1464 1465

		if (strcmp(PQgetvalue(res, i, i_typisdefined), "f") == 0)
			tinfo[i].isDefined = 0;
		else
			tinfo[i].isDefined = 1;
1466 1467 1468 1469 1470 1471
	}

	*numTypes = ntups;

	PQclear(res);

1472 1473
	destroyPQExpBuffer(query);

1474
	return tinfo;
1475 1476 1477 1478
}

/*
 * getOperators:
1479
 *	  read all operators in the system catalogs and return them in the
1480 1481
 * OprInfo* structure
 *
1482
 *	numOprs is set to the number of operators read in
1483
 */
1484
OprInfo *
1485 1486
getOperators(int *numOprs)
{
1487
	PGresult   *res;
1488 1489
	int			ntups;
	int			i;
1490
	PQExpBuffer query = createPQExpBuffer();
1491

B
Bruce Momjian 已提交
1492
	OprInfo    *oprinfo;
1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507

	int			i_oid;
	int			i_oprname;
	int			i_oprkind;
	int			i_oprcode;
	int			i_oprleft;
	int			i_oprright;
	int			i_oprcom;
	int			i_oprnegate;
	int			i_oprrest;
	int			i_oprjoin;
	int			i_oprcanhash;
	int			i_oprlsortop;
	int			i_oprrsortop;
	int			i_usename;
1508 1509 1510 1511 1512 1513

	/*
	 * find all operators, including builtin operators, filter out
	 * system-defined operators at dump-out time
	 */

B
Hi, all  
Bruce Momjian 已提交
1514
	appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
1515
			   "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
B
Bruce Momjian 已提交
1516 1517 1518
					  "oprcanhash, oprlsortop, oprrsortop, "
	"(select usename from pg_user where oprowner = usesysid) as usename "
					  "from pg_operator");
1519

B
Hi, all  
Bruce Momjian 已提交
1520
	res = PQexec(g_conn, query->data);
1521 1522 1523
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
1524
		write_msg(NULL, "query to obtain list of operators failed: %s", PQerrorMessage(g_conn));
1525
		exit_nicely();
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
	}

	ntups = PQntuples(res);
	*numOprs = ntups;

	oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));

	i_oid = PQfnumber(res, "oid");
	i_oprname = PQfnumber(res, "oprname");
	i_oprkind = PQfnumber(res, "oprkind");
	i_oprcode = PQfnumber(res, "oprcode");
	i_oprleft = PQfnumber(res, "oprleft");
	i_oprright = PQfnumber(res, "oprright");
	i_oprcom = PQfnumber(res, "oprcom");
	i_oprnegate = PQfnumber(res, "oprnegate");
	i_oprrest = PQfnumber(res, "oprrest");
	i_oprjoin = PQfnumber(res, "oprjoin");
	i_oprcanhash = PQfnumber(res, "oprcanhash");
	i_oprlsortop = PQfnumber(res, "oprlsortop");
	i_oprrsortop = PQfnumber(res, "oprrsortop");
	i_usename = PQfnumber(res, "usename");

	for (i = 0; i < ntups; i++)
	{
		oprinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
		oprinfo[i].oprname = strdup(PQgetvalue(res, i, i_oprname));
		oprinfo[i].oprkind = strdup(PQgetvalue(res, i, i_oprkind));
		oprinfo[i].oprcode = strdup(PQgetvalue(res, i, i_oprcode));
		oprinfo[i].oprleft = strdup(PQgetvalue(res, i, i_oprleft));
		oprinfo[i].oprright = strdup(PQgetvalue(res, i, i_oprright));
		oprinfo[i].oprcom = strdup(PQgetvalue(res, i, i_oprcom));
		oprinfo[i].oprnegate = strdup(PQgetvalue(res, i, i_oprnegate));
		oprinfo[i].oprrest = strdup(PQgetvalue(res, i, i_oprrest));
		oprinfo[i].oprjoin = strdup(PQgetvalue(res, i, i_oprjoin));
		oprinfo[i].oprcanhash = strdup(PQgetvalue(res, i, i_oprcanhash));
		oprinfo[i].oprlsortop = strdup(PQgetvalue(res, i, i_oprlsortop));
		oprinfo[i].oprrsortop = strdup(PQgetvalue(res, i, i_oprrsortop));
		oprinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1564 1565

		if (strlen(oprinfo[i].usename) == 0)
1566 1567
			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
					  oprinfo[i].oprname);
1568

1569 1570 1571 1572
	}

	PQclear(res);

1573 1574
	destroyPQExpBuffer(query);

1575
	return oprinfo;
1576 1577
}

1578
void
1579
clearTypeInfo(TypeInfo *tp, int numTypes)
1580
{
1581
	int			i;
1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610

	for (i = 0; i < numTypes; ++i)
	{
		if (tp[i].oid)
			free(tp[i].oid);
		if (tp[i].typowner)
			free(tp[i].typowner);
		if (tp[i].typname)
			free(tp[i].typname);
		if (tp[i].typlen)
			free(tp[i].typlen);
		if (tp[i].typprtlen)
			free(tp[i].typprtlen);
		if (tp[i].typinput)
			free(tp[i].typinput);
		if (tp[i].typoutput)
			free(tp[i].typoutput);
		if (tp[i].typreceive)
			free(tp[i].typreceive);
		if (tp[i].typsend)
			free(tp[i].typsend);
		if (tp[i].typelem)
			free(tp[i].typelem);
		if (tp[i].typdelim)
			free(tp[i].typdelim);
		if (tp[i].typdefault)
			free(tp[i].typdefault);
		if (tp[i].typrelid)
			free(tp[i].typrelid);
1611 1612 1613 1614
		if (tp[i].typalign)
			free(tp[i].typalign);
		if (tp[i].typstorage)
			free(tp[i].typstorage);
1615 1616
		if (tp[i].usename)
			free(tp[i].usename);
1617 1618
		if (tp[i].typedefn)
			free(tp[i].typedefn);
1619 1620
	}
	free(tp);
1621 1622 1623
}

void
1624
clearFuncInfo(FuncInfo *fun, int numFuncs)
1625
{
1626 1627
	int			i,
				a;
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638

	if (!fun)
		return;
	for (i = 0; i < numFuncs; ++i)
	{
		if (fun[i].oid)
			free(fun[i].oid);
		if (fun[i].proname)
			free(fun[i].proname);
		if (fun[i].usename)
			free(fun[i].usename);
1639
		for (a = 0; a < FUNC_MAX_ARGS; ++a)
1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
			if (fun[i].argtypes[a])
				free(fun[i].argtypes[a]);
		if (fun[i].prorettype)
			free(fun[i].prorettype);
		if (fun[i].prosrc)
			free(fun[i].prosrc);
		if (fun[i].probin)
			free(fun[i].probin);
	}
	free(fun);
1650 1651
}

1652
static void
1653
clearTableInfo(TableInfo *tblinfo, int numTables)
1654
{
1655 1656
	int			i,
				j;
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681

	for (i = 0; i < numTables; ++i)
	{

		if (tblinfo[i].oid)
			free(tblinfo[i].oid);
		if (tblinfo[i].relacl)
			free(tblinfo[i].relacl);
		if (tblinfo[i].usename)
			free(tblinfo[i].usename);

		if (tblinfo[i].relname)
			free(tblinfo[i].relname);

		if (tblinfo[i].sequence)
			continue;

		/* Process Attributes */
		for (j = 0; j < tblinfo[i].numatts; j++)
		{
			if (tblinfo[i].attnames[j])
				free(tblinfo[i].attnames[j]);
			if (tblinfo[i].typnames[j])
				free(tblinfo[i].typnames[j]);
		}
B
Bruce Momjian 已提交
1682

B
Bruce Momjian 已提交
1683 1684 1685
		if (tblinfo[i].triggers)
		{
			for (j = 0; j < tblinfo[i].ntrig; j++)
B
Bruce Momjian 已提交
1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698
			{
				if (tblinfo[i].triggers[j].tgsrc)
					free(tblinfo[i].triggers[j].tgsrc);
				if (tblinfo[i].triggers[j].oid)
					free(tblinfo[i].triggers[j].oid);
				if (tblinfo[i].triggers[j].tgname)
					free(tblinfo[i].triggers[j].tgname);
				if (tblinfo[i].triggers[j].tgdel)
					free(tblinfo[i].triggers[j].tgdel);
			}
			free(tblinfo[i].triggers);
		}

1699 1700
		if (tblinfo[i].atttypmod)
			free((int *) tblinfo[i].atttypmod);
1701 1702
		if (tblinfo[i].inhAttrs)
			free((int *) tblinfo[i].inhAttrs);
1703 1704 1705 1706
		if (tblinfo[i].inhAttrDef)
			free((int *) tblinfo[i].inhAttrDef);
		if (tblinfo[i].inhNotNull)
			free((int *) tblinfo[i].inhNotNull);
1707 1708
		if (tblinfo[i].attnames)
			free(tblinfo[i].attnames);
1709 1710
		if (tblinfo[i].atttypedefns)
			free(tblinfo[i].atttypedefns);
1711 1712 1713 1714
		if (tblinfo[i].typnames)
			free(tblinfo[i].typnames);
		if (tblinfo[i].notnull)
			free(tblinfo[i].notnull);
1715 1716
		if (tblinfo[i].primary_key_name)
			free(tblinfo[i].primary_key_name);
1717 1718
	}
	free(tblinfo);
1719 1720
}

1721
void
1722
clearInhInfo(InhInfo *inh, int numInherits)
1723
{
1724
	int			i;
1725 1726 1727 1728 1729

	if (!inh)
		return;
	for (i = 0; i < numInherits; ++i)
	{
1730 1731
		if (inh[i].inhrelid)
			free(inh[i].inhrelid);
1732 1733 1734 1735
		if (inh[i].inhparent)
			free(inh[i].inhparent);
	}
	free(inh);
1736 1737 1738
}

void
1739
clearOprInfo(OprInfo *opr, int numOprs)
1740
{
1741
	int			i;
1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776

	if (!opr)
		return;
	for (i = 0; i < numOprs; ++i)
	{
		if (opr[i].oid)
			free(opr[i].oid);
		if (opr[i].oprname)
			free(opr[i].oprname);
		if (opr[i].oprkind)
			free(opr[i].oprkind);
		if (opr[i].oprcode)
			free(opr[i].oprcode);
		if (opr[i].oprleft)
			free(opr[i].oprleft);
		if (opr[i].oprright)
			free(opr[i].oprright);
		if (opr[i].oprcom)
			free(opr[i].oprcom);
		if (opr[i].oprnegate)
			free(opr[i].oprnegate);
		if (opr[i].oprrest)
			free(opr[i].oprrest);
		if (opr[i].oprjoin)
			free(opr[i].oprjoin);
		if (opr[i].oprcanhash)
			free(opr[i].oprcanhash);
		if (opr[i].oprlsortop)
			free(opr[i].oprlsortop);
		if (opr[i].oprrsortop)
			free(opr[i].oprrsortop);
		if (opr[i].usename)
			free(opr[i].usename);
	}
	free(opr);
1777 1778 1779
}

void
1780
clearIndInfo(IndInfo *ind, int numIndexes)
1781
{
1782 1783
	int			i,
				a;
1784 1785 1786

	if (!ind)
		return;
1787
	for (i = 0; i < numIndexes; ++i)
1788
	{
1789 1790 1791 1792
		if (ind[i].indexreloid)
			free(ind[i].indexreloid);
		if (ind[i].indreloid)
			free(ind[i].indreloid);
1793 1794 1795 1796
		if (ind[i].indexrelname)
			free(ind[i].indexrelname);
		if (ind[i].indrelname)
			free(ind[i].indrelname);
1797 1798
		if (ind[i].indexdef)
			free(ind[i].indexdef);
1799 1800
		if (ind[i].indisprimary)
			free(ind[i].indisprimary);
1801 1802 1803 1804 1805 1806 1807
		for (a = 0; a < INDEX_MAX_KEYS; ++a)
		{
			if (ind[i].indkey[a])
				free(ind[i].indkey[a]);
		}
	}
	free(ind);
1808 1809 1810
}

void
B
Bruce Momjian 已提交
1811
clearAggInfo(AggInfo *agginfo, int numArgs)
1812
{
1813
	int			i;
1814 1815 1816 1817 1818 1819 1820 1821 1822

	if (!agginfo)
		return;
	for (i = 0; i < numArgs; ++i)
	{
		if (agginfo[i].oid)
			free(agginfo[i].oid);
		if (agginfo[i].aggname)
			free(agginfo[i].aggname);
1823 1824
		if (agginfo[i].aggtransfn)
			free(agginfo[i].aggtransfn);
1825 1826
		if (agginfo[i].aggfinalfn)
			free(agginfo[i].aggfinalfn);
1827 1828
		if (agginfo[i].aggtranstype)
			free(agginfo[i].aggtranstype);
1829 1830
		if (agginfo[i].aggbasetype)
			free(agginfo[i].aggbasetype);
1831 1832
		if (agginfo[i].agginitval)
			free(agginfo[i].agginitval);
1833 1834 1835 1836
		if (agginfo[i].usename)
			free(agginfo[i].usename);
	}
	free(agginfo);
1837
}
1838 1839 1840

/*
 * getAggregates:
1841
 *	  read all the user-defined aggregates in the system catalogs and
1842 1843
 * return them in the AggInfo* structure
 *
1844
 * numAggs is set to the number of aggregates read in
1845
 */
1846
AggInfo *
1847 1848
getAggregates(int *numAggs)
{
B
Bruce Momjian 已提交
1849
	PGresult   *res;
1850 1851
	int			ntups;
	int			i;
1852
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1853
	AggInfo    *agginfo;
1854 1855 1856

	int			i_oid;
	int			i_aggname;
1857
	int			i_aggtransfn;
1858
	int			i_aggfinalfn;
1859
	int			i_aggtranstype;
1860
	int			i_aggbasetype;
1861
	int			i_agginitval;
1862
	int			i_usename;
1863
	int			i_convertok;
1864 1865 1866

	/* find all user-defined aggregates */

1867 1868 1869
	if (g_fout->remoteVersion < 70100)
	{
		appendPQExpBuffer(query, "SELECT pg_aggregate.oid, aggname, aggtransfn1 as aggtransfn, "
1870 1871 1872 1873 1874 1875 1876 1877
			   "aggfinalfn, aggtranstype1 as aggtranstype, aggbasetype, "
						  "agginitval1 as agginitval, "
						  "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) as convertok, "
						  "(select usename from pg_user where aggowner = usesysid) as usename "
						  "from pg_aggregate");
	}
	else
	{
1878
		appendPQExpBuffer(query, "SELECT pg_aggregate.oid, aggname, aggtransfn, "
1879 1880 1881 1882 1883
						  "aggfinalfn, aggtranstype, aggbasetype, "
						  "agginitval, "
						  "'t'::boolean as convertok, "
						  "(select usename from pg_user where aggowner = usesysid) as usename "
						  "from pg_aggregate");
1884
	}
1885

B
Hi, all  
Bruce Momjian 已提交
1886
	res = PQexec(g_conn, query->data);
1887 1888 1889
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
1890
		write_msg(NULL, "query to obtain list of aggregate functions failed: %s",
1891
				  PQerrorMessage(g_conn));
1892
		exit_nicely();
1893 1894 1895 1896 1897 1898 1899 1900 1901
	}

	ntups = PQntuples(res);
	*numAggs = ntups;

	agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));

	i_oid = PQfnumber(res, "oid");
	i_aggname = PQfnumber(res, "aggname");
1902
	i_aggtransfn = PQfnumber(res, "aggtransfn");
1903
	i_aggfinalfn = PQfnumber(res, "aggfinalfn");
1904
	i_aggtranstype = PQfnumber(res, "aggtranstype");
1905
	i_aggbasetype = PQfnumber(res, "aggbasetype");
1906
	i_agginitval = PQfnumber(res, "agginitval");
1907
	i_usename = PQfnumber(res, "usename");
1908
	i_convertok = PQfnumber(res, "convertok");
1909 1910 1911 1912 1913

	for (i = 0; i < ntups; i++)
	{
		agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
		agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
1914
		agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
1915
		agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
1916
		agginfo[i].aggtranstype = strdup(PQgetvalue(res, i, i_aggtranstype));
1917
		agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
1918
		agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
1919
		agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1920
		if (strlen(agginfo[i].usename) == 0)
1921 1922
			write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
					  agginfo[i].aggname);
1923

1924 1925
		agginfo[i].convertok = (PQgetvalue(res, i, i_convertok)[0] == 't');

1926 1927 1928 1929
	}

	PQclear(res);

1930 1931
	destroyPQExpBuffer(query);

1932
	return agginfo;
1933 1934 1935 1936
}

/*
 * getFuncs:
1937
 *	  read all the user-defined functions in the system catalogs and
1938 1939
 * return them in the FuncInfo* structure
 *
1940 1941
 * numFuncs is set to the number of functions read in
 *
1942 1943
 *
 */
1944
FuncInfo *
1945 1946
getFuncs(int *numFuncs)
{
1947
	PGresult   *res;
1948 1949
	int			ntups;
	int			i;
1950 1951
	PQExpBuffer query = createPQExpBuffer();
	FuncInfo   *finfo;
1952 1953 1954 1955 1956 1957 1958 1959 1960 1961

	int			i_oid;
	int			i_proname;
	int			i_prolang;
	int			i_pronargs;
	int			i_proargtypes;
	int			i_prorettype;
	int			i_proretset;
	int			i_prosrc;
	int			i_probin;
1962
	int			i_provolatile;
1963
	int			i_isstrict;
1964
	int			i_usename;
1965 1966 1967

	/* find all user-defined funcs */

1968 1969 1970 1971
	if (g_fout->remoteVersion < 70100)
	{
		appendPQExpBuffer(query,
		   "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
1972 1973
						  "proretset, proargtypes, prosrc, probin, "
						  "(select usename from pg_user where proowner = usesysid) as usename, "
1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987
						  "case when proiscachable then 'i' else 'v' end as provolatile, "
"'f'::boolean as proisstrict "
						  "from pg_proc "
						  "where pg_proc.oid > '%u'::oid",
						  g_last_builtin_oid);
	}
	else if (g_fout->remoteVersion < 70300)
	{
		appendPQExpBuffer(query,
		   "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
						  "proretset, proargtypes, prosrc, probin, "
						  "(select usename from pg_user where proowner = usesysid) as usename, "
						  "case when proiscachable then 'i' else 'v' end as provolatile, "
						  "proisstrict "
1988 1989 1990 1991 1992 1993
						  "from pg_proc "
						  "where pg_proc.oid > '%u'::oid",
						  g_last_builtin_oid);
	}
	else
	{
1994
		appendPQExpBuffer(query,
1995
		   "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
1996 1997
						  "proretset, proargtypes, prosrc, probin, "
						  "(select usename from pg_user where proowner = usesysid) as usename, "
1998
						  "provolatile, proisstrict "
1999 2000 2001
						  "from pg_proc "
						  "where pg_proc.oid > '%u'::oid",
						  g_last_builtin_oid);
2002
	}
2003

B
Hi, all  
Bruce Momjian 已提交
2004
	res = PQexec(g_conn, query->data);
2005 2006 2007
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
2008 2009
		write_msg(NULL, "query to obtain list of functions failed: %s",
				  PQerrorMessage(g_conn));
2010
		exit_nicely();
2011 2012 2013 2014 2015 2016 2017 2018
	}

	ntups = PQntuples(res);

	*numFuncs = ntups;

	finfo = (FuncInfo *) malloc(ntups * sizeof(FuncInfo));

2019 2020
	memset((char *) finfo, 0, ntups * sizeof(FuncInfo));

2021 2022 2023 2024 2025 2026 2027 2028 2029
	i_oid = PQfnumber(res, "oid");
	i_proname = PQfnumber(res, "proname");
	i_prolang = PQfnumber(res, "prolang");
	i_pronargs = PQfnumber(res, "pronargs");
	i_proargtypes = PQfnumber(res, "proargtypes");
	i_prorettype = PQfnumber(res, "prorettype");
	i_proretset = PQfnumber(res, "proretset");
	i_prosrc = PQfnumber(res, "prosrc");
	i_probin = PQfnumber(res, "probin");
2030
	i_provolatile = PQfnumber(res, "provolatile");
2031
	i_isstrict = PQfnumber(res, "proisstrict");
2032 2033 2034 2035 2036 2037 2038
	i_usename = PQfnumber(res, "usename");

	for (i = 0; i < ntups; i++)
	{
		finfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
		finfo[i].proname = strdup(PQgetvalue(res, i, i_proname));

2039
		finfo[i].prosrc = strdup(PQgetvalue(res, i, i_prosrc));
2040 2041 2042 2043 2044
		finfo[i].probin = strdup(PQgetvalue(res, i, i_probin));

		finfo[i].prorettype = strdup(PQgetvalue(res, i, i_prorettype));
		finfo[i].retset = (strcmp(PQgetvalue(res, i, i_proretset), "t") == 0);
		finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
2045
		finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
2046
		finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
2047
		finfo[i].provolatile = (PQgetvalue(res, i, i_provolatile))[0];
B
Bruce Momjian 已提交
2048
		finfo[i].isstrict = (strcmp(PQgetvalue(res, i, i_isstrict), "t") == 0);
2049 2050

		if (strlen(finfo[i].usename) == 0)
2051 2052
			write_msg(NULL, "WARNING: owner of function \"%s\" appears to be invalid\n",
					  finfo[i].proname);
2053

2054 2055
		if (finfo[i].nargs < 0 || finfo[i].nargs > FUNC_MAX_ARGS)
		{
2056 2057
			write_msg(NULL, "failed sanity check: function %s has more than %d (namely %d) arguments\n",
					  finfo[i].proname, FUNC_MAX_ARGS, finfo[i].nargs);
2058
			exit_nicely();
2059 2060 2061 2062
		}
		parseNumericArray(PQgetvalue(res, i, i_proargtypes),
						  finfo[i].argtypes,
						  finfo[i].nargs);
2063 2064 2065 2066 2067
		finfo[i].dumped = 0;
	}

	PQclear(res);

2068
	destroyPQExpBuffer(query);
2069

2070
	return finfo;
2071 2072 2073 2074
}

/*
 * getTables
2075
 *	  read all the user-defined tables (no indexes, no catalogs)
2076 2077
 * in the system catalogs return them in the TableInfo* structure
 *
2078
 * numTables is set to the number of tables read in
2079
 */
2080
TableInfo *
2081
getTables(int *numTables, FuncInfo *finfo, int numFuncs, const char *tablename)
2082
{
2083
	PGresult   *res;
2084 2085
	int			ntups;
	int			i;
2086
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2087
	PQExpBuffer delqry = createPQExpBuffer();
2088
	PQExpBuffer lockquery = createPQExpBuffer();
2089
	TableInfo  *tblinfo;
2090

B
Bruce Momjian 已提交
2091
	int			i_reloid;
2092 2093 2094 2095
	int			i_relname;
	int			i_relkind;
	int			i_relacl;
	int			i_usename;
V
Vadim B. Mikheev 已提交
2096 2097
	int			i_relchecks;
	int			i_reltriggers;
2098
	int			i_relhasindex;
2099
	int			i_relhasoids;
2100

2101
	/*
2102
	 * find all the user-defined tables (no indexes and no catalogs),
2103 2104 2105
	 * ordering by oid is important so that we always process the parent
	 * tables before the child tables when traversing the tblinfo*
	 *
2106
	 * we ignore tables that are not type 'r' (ordinary relation) or 'S'
2107
	 * (sequence) or 'v' (view).
2108 2109
	 */

2110
	if (g_fout->remoteVersion >= 70200)
2111 2112
	{
		appendPQExpBuffer(query,
2113
						"SELECT pg_class.oid, relname, relacl, relkind, "
2114
						  "(select usename from pg_user where relowner = usesysid) as usename, "
2115
					   "relchecks, reltriggers, relhasindex, relhasoids "
2116 2117 2118 2119
						  "from pg_class "
						  "where relname !~ '^pg_' "
						  "and relkind in ('%c', '%c', '%c') "
						  "order by oid",
2120
					   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2121 2122 2123 2124 2125
	}
	else if (g_fout->remoteVersion >= 70100)
	{
		/* all tables have oids in 7.1 */
		appendPQExpBuffer(query,
2126
						"SELECT pg_class.oid, relname, relacl, relkind, "
2127
						  "(select usename from pg_user where relowner = usesysid) as usename, "
2128
		  "relchecks, reltriggers, relhasindex, 't'::bool as relhasoids "
2129 2130 2131 2132
						  "from pg_class "
						  "where relname !~ '^pg_' "
						  "and relkind in ('%c', '%c', '%c') "
						  "order by oid",
2133 2134 2135 2136
					   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
	}
	else
	{
2137
		/*
2138 2139
		 * Before 7.1, view relkind was not set to 'v', so we must check
		 * if we have a view by looking for a rule in pg_rewrite.
2140 2141
		 */
		appendPQExpBuffer(query,
2142 2143
						  "SELECT c.oid, relname, relacl, "
						  "CASE WHEN relhasrules and relkind = 'r' "
2144 2145
				  "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
				  "             r.ev_class = c.oid AND r.ev_type = '1') "
2146 2147 2148
						  "THEN '%c'::\"char\" "
						  "ELSE relkind END AS relkind,"
						  "(select usename from pg_user where relowner = usesysid) as usename, "
2149
		  "relchecks, reltriggers, relhasindex, 't'::bool as relhasoids "
2150 2151 2152 2153 2154
						  "from pg_class c "
						  "where relname !~ '^pg_' "
						  "and relkind in ('%c', '%c', '%c') "
						  "order by oid",
						  RELKIND_VIEW,
2155
					   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2156
	}
2157

B
Hi, all  
Bruce Momjian 已提交
2158
	res = PQexec(g_conn, query->data);
2159 2160 2161
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
2162 2163
		write_msg(NULL, "query to obtain list of tables failed: %s",
				  PQerrorMessage(g_conn));
2164
		exit_nicely();
2165 2166 2167 2168 2169 2170
	}

	ntups = PQntuples(res);

	*numTables = ntups;

2171 2172
	/*
	 * First pass: extract data from result and lock tables.  We do the
2173 2174
	 * locking before anything else, to minimize the window wherein a
	 * table could disappear under us.
2175 2176 2177 2178 2179
	 *
	 * Note that we have to collect info about all tables here, even when
	 * dumping only one, because we don't know which tables might be
	 * inheritance ancestors of the target table.  Possible future
	 * improvement: suppress later collection of schema info about tables
2180 2181
	 * that are determined not to be either targets or ancestors of
	 * targets.
2182
	 */
2183 2184
	tblinfo = (TableInfo *) malloc(ntups * sizeof(TableInfo));

B
Bruce Momjian 已提交
2185
	i_reloid = PQfnumber(res, "oid");
2186 2187
	i_relname = PQfnumber(res, "relname");
	i_relacl = PQfnumber(res, "relacl");
2188
	i_relkind = PQfnumber(res, "relkind");
2189
	i_usename = PQfnumber(res, "usename");
V
Vadim B. Mikheev 已提交
2190 2191
	i_relchecks = PQfnumber(res, "relchecks");
	i_reltriggers = PQfnumber(res, "reltriggers");
B
Hi, all  
Bruce Momjian 已提交
2192
	i_relhasindex = PQfnumber(res, "relhasindex");
2193
	i_relhasoids = PQfnumber(res, "relhasoids");
2194 2195 2196

	for (i = 0; i < ntups; i++)
	{
B
Bruce Momjian 已提交
2197
		tblinfo[i].oid = strdup(PQgetvalue(res, i, i_reloid));
2198 2199
		tblinfo[i].relname = strdup(PQgetvalue(res, i, i_relname));
		tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
2200 2201 2202 2203
		tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
		tblinfo[i].sequence = (tblinfo[i].relkind == RELKIND_SEQUENCE);
		tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
		tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
2204
		tblinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
V
Vadim B. Mikheev 已提交
2205 2206
		tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
		tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
2207

2208 2209 2210 2211 2212 2213
		/*
		 * Read-lock target tables to make sure they aren't DROPPED or
		 * altered in schema before we get around to dumping them.
		 *
		 * If no target tablename was specified, lock all tables we see,
		 * otherwise lock only the specified table.  (This is incomplete
2214 2215 2216 2217
		 * because we'll still try to collect schema info about all
		 * tables, and could possibly lose during that phase.  But for the
		 * typical use where we're dumping all tables anyway, it matters
		 * not.)
2218
		 *
2219 2220
		 * NOTE: it'd be kinda nice to lock views and sequences too, not only
		 * plain tables, but the backend doesn't presently allow that.
2221 2222
		 */
		if ((tblinfo[i].relkind == RELKIND_RELATION) &&
2223
		(tablename == NULL || strcmp(tblinfo[i].relname, tablename) == 0))
2224
		{
2225
			PGresult   *lres;
2226 2227 2228 2229 2230

			resetPQExpBuffer(lockquery);
			appendPQExpBuffer(lockquery,
							  "LOCK TABLE %s IN ACCESS SHARE MODE",
							  fmtId(tblinfo[i].relname, force_quotes));
2231
			lres = PQexec(g_conn, lockquery->data);
2232 2233
			if (!lres || PQresultStatus(lres) != PGRES_COMMAND_OK)
			{
2234
				write_msg(NULL, "Attempt to lock table \"%s\" failed.  %s",
2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245
						  tblinfo[i].relname, PQerrorMessage(g_conn));
				exit_nicely();
			}
			PQclear(lres);
		}
	}

	PQclear(res);
	res = NULL;

	/*
2246 2247
	 * Second pass: pick up additional information about each table, as
	 * required.
2248 2249 2250 2251
	 */
	for (i = 0; i < *numTables; i++)
	{
		/* Emit notice if join for owner failed */
2252
		if (strlen(tblinfo[i].usename) == 0)
2253 2254
			write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
					  tblinfo[i].relname);
2255

2256 2257
		/* Get definition if it's a view */
		if (tblinfo[i].relkind == RELKIND_VIEW)
2258 2259 2260 2261
		{
			PGresult   *res2;

			resetPQExpBuffer(query);
2262
			appendPQExpBuffer(query, "SELECT definition as viewdef, ");
2263 2264 2265 2266 2267

			/*
			 * XXX 7.2 - replace with att from pg_views or some other
			 * generic source
			 */
2268
			appendPQExpBuffer(query, "(select oid from pg_rewrite where "
2269 2270
					  " rulename=('_RET' || viewname)::name) as view_oid"
							  " from pg_views where viewname = ");
2271
			formatStringLiteral(query, tblinfo[i].relname, CONV_ALL);
2272 2273
			appendPQExpBuffer(query, ";");

2274 2275 2276
			res2 = PQexec(g_conn, query->data);
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
2277 2278
				write_msg(NULL, "query to obtain definition of view \"%s\" failed: %s",
						  tblinfo[i].relname, PQerrorMessage(g_conn));
2279
				exit_nicely();
2280 2281
			}

B
Bruce Momjian 已提交
2282
			if (PQntuples(res2) != 1)
2283 2284
			{
				if (PQntuples(res2) < 1)
2285 2286
					write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
							  tblinfo[i].relname);
B
Bruce Momjian 已提交
2287
				else
2288
					write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
2289
							  tblinfo[i].relname);
2290
				exit_nicely();
2291 2292
			}

2293 2294
			if (PQgetisnull(res2, 0, 1))
			{
2295 2296
				write_msg(NULL, "query to obtain definition of view \"%s\" returned NULL oid\n",
						  tblinfo[i].relname);
2297
				exit_nicely();
2298 2299
			}

2300
			tblinfo[i].viewdef = strdup(PQgetvalue(res2, 0, 0));
2301
			tblinfo[i].viewoid = strdup(PQgetvalue(res2, 0, 1));
2302

B
Bruce Momjian 已提交
2303
			if (strlen(tblinfo[i].viewdef) == 0)
2304
			{
2305 2306
				write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
						  tblinfo[i].relname);
2307
				exit_nicely();
2308
			}
2309
			PQclear(res2);
2310 2311 2312 2313
		}
		else
			tblinfo[i].viewdef = NULL;

2314
		/*
2315 2316
		 * Get non-inherited CHECK constraints, if any.
		 *
B
Bruce Momjian 已提交
2317 2318
		 * Exclude inherited CHECKs from CHECK constraints total. If a
		 * constraint matches by name and condition with a constraint
2319 2320
		 * belonging to a parent class (OR conditions match and both names
		 * start with '$', we assume it was inherited.
2321 2322
		 */
		if (tblinfo[i].ncheck > 0)
V
Vadim B. Mikheev 已提交
2323 2324
		{
			PGresult   *res2;
2325 2326
			int			i_rcname,
						i_rcsrc;
V
Vadim B. Mikheev 已提交
2327 2328
			int			ntups2;
			int			i2;
2329

V
Vadim B. Mikheev 已提交
2330
			if (g_verbose)
2331 2332
				write_msg(NULL, "finding CHECK constraints for table %s\n",
						  tblinfo[i].relname);
2333

B
Hi, all  
Bruce Momjian 已提交
2334 2335
			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
2336
							  " where rcrelid = '%s'::oid "
2337
							  "   and not exists "
2338 2339
				   "  (select * from pg_relcheck as c, pg_inherits as i "
							"    where i.inhrelid = pg_relcheck.rcrelid "
2340 2341
							  "      and (c.rcname = pg_relcheck.rcname "
							  "          or (    c.rcname[0] = '$' "
2342
						 "              and pg_relcheck.rcname[0] = '$')"
2343 2344 2345
							  "          )"
							  "      and c.rcsrc = pg_relcheck.rcsrc "
							  "      and c.rcrelid = i.inhparent) "
2346
							  " order by rcname ",
2347
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2348
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2349
			if (!res2 ||
2350
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2351
			{
2352
				write_msg(NULL, "query to obtain check constraints failed: %s", PQerrorMessage(g_conn));
2353
				exit_nicely();
V
Vadim B. Mikheev 已提交
2354 2355
			}
			ntups2 = PQntuples(res2);
2356
			if (ntups2 > tblinfo[i].ncheck)
V
Vadim B. Mikheev 已提交
2357
			{
2358 2359 2360
				write_msg(NULL, "expected %d check constraints on table \"%s\" but found %d\n",
						  tblinfo[i].ncheck, tblinfo[i].relname, ntups2);
				write_msg(NULL, "(The system catalogs might be corrupted.)\n");
2361
				exit_nicely();
V
Vadim B. Mikheev 已提交
2362
			}
2363

2364 2365 2366 2367
			/*
			 * Set ncheck to the number of *non-inherited* CHECK
			 * constraints
			 */
2368 2369
			tblinfo[i].ncheck = ntups2;

V
Vadim B. Mikheev 已提交
2370 2371
			i_rcname = PQfnumber(res2, "rcname");
			i_rcsrc = PQfnumber(res2, "rcsrc");
2372
			tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
V
Vadim B. Mikheev 已提交
2373 2374
			for (i2 = 0; i2 < ntups2; i2++)
			{
B
Bruce Momjian 已提交
2375 2376
				const char *name = PQgetvalue(res2, i2, i_rcname);
				const char *expr = PQgetvalue(res2, i2, i_rcsrc);
2377

B
Hi, all  
Bruce Momjian 已提交
2378
				resetPQExpBuffer(query);
2379 2380
				if (name[0] != '$')
				{
2381 2382
					appendPQExpBuffer(query, "CONSTRAINT %s ",
									  fmtId(name, force_quotes));
B
Bruce Momjian 已提交
2383
				}
2384
				appendPQExpBuffer(query, "CHECK (%s)", expr);
B
Hi, all  
Bruce Momjian 已提交
2385
				tblinfo[i].check_expr[i2] = strdup(query->data);
V
Vadim B. Mikheev 已提交
2386 2387 2388 2389 2390
			}
			PQclear(res2);
		}
		else
			tblinfo[i].check_expr = NULL;
2391

2392
		/* Get primary key */
2393
		if (tblinfo[i].hasindex)
2394
		{
2395
			PGresult   *res2;
B
Bruce Momjian 已提交
2396

B
Hi, all  
Bruce Momjian 已提交
2397
			resetPQExpBuffer(query);
B
Bruce Momjian 已提交
2398
			appendPQExpBuffer(query,
2399
							  "SELECT indexrelid FROM pg_index i WHERE i.indisprimary AND i.indrelid = '%s'::oid ",
2400
							  tblinfo[i].oid);
2401
			res2 = PQexec(g_conn, query->data);
B
Bruce Momjian 已提交
2402 2403
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
2404 2405
				write_msg(NULL, "query to obtain primary key of table \"%s\" failed: %s",
						  tblinfo[i].relname, PQerrorMessage(g_conn));
2406
				exit_nicely();
B
Bruce Momjian 已提交
2407
			}
2408

B
Bruce Momjian 已提交
2409 2410
			if (PQntuples(res2) > 1)
			{
2411
				write_msg(NULL, "query to obtain primary key of table \"%s\" produced more than one result\n",
2412
						  tblinfo[i].relname);
2413
				exit_nicely();
2414 2415
			}

B
Bruce Momjian 已提交
2416
			if (PQntuples(res2) == 1)
2417
				tblinfo[i].pkIndexOid = strdup(PQgetvalue(res2, 0, 0));
B
Bruce Momjian 已提交
2418
			else
2419 2420
				tblinfo[i].pkIndexOid = NULL;

2421
		}
2422
		else
2423
			tblinfo[i].pkIndexOid = NULL;
B
Bruce Momjian 已提交
2424

2425
		/* Get primary key name (if primary key exist) */
2426
		if (tblinfo[i].pkIndexOid != NULL)
2427 2428
		{
			PGresult   *res2;
B
Bruce Momjian 已提交
2429
			int			n;
2430 2431

			resetPQExpBuffer(query);
2432 2433
			appendPQExpBuffer(query,
							  "SELECT relname FROM pg_class "
2434
							  "WHERE oid = '%s'::oid",
2435
							  tblinfo[i].pkIndexOid);
2436

2437 2438 2439
			res2 = PQexec(g_conn, query->data);
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
2440 2441
				write_msg(NULL, "query to obtain name of primary key of table \"%s\" failed: %s",
						  tblinfo[i].relname, PQerrorMessage(g_conn));
2442
				exit_nicely();
2443 2444 2445 2446 2447
			}

			n = PQntuples(res2);
			if (n != 1)
			{
2448 2449 2450 2451 2452 2453
				if (n == 0)
					write_msg(NULL, "query to obtain name of primary key of table \"%s\" returned no rows\n",
							  tblinfo[i].relname);
				else
					write_msg(NULL, "query to obtain name of primary key of table \"%s\" returned %d rows\n",
							  tblinfo[i].relname, n);
2454
				exit_nicely();
2455 2456 2457 2458 2459 2460
			}

			tblinfo[i].primary_key_name =
				strdup(fmtId(PQgetvalue(res2, 0, 0), force_quotes));
			if (tblinfo[i].primary_key_name == NULL)
			{
2461
				write_msg(NULL, "out of memory\n");
2462
				exit_nicely();
2463 2464 2465 2466 2467
			}
		}
		else
			tblinfo[i].primary_key_name = NULL;

V
Vadim B. Mikheev 已提交
2468 2469 2470 2471
		/* Get Triggers */
		if (tblinfo[i].ntrig > 0)
		{
			PGresult   *res2;
B
Bruce,  
Bruce Momjian 已提交
2472
			int			i_tgoid,
2473
						i_tgname,
2474 2475 2476
						i_tgfoid,
						i_tgtype,
						i_tgnargs,
2477 2478 2479 2480
						i_tgargs,
						i_tgisconstraint,
						i_tgconstrname,
						i_tgdeferrable,
2481 2482
						i_tgconstrrelid,
						i_tgconstrrelname,
2483
						i_tginitdeferred;
V
Vadim B. Mikheev 已提交
2484 2485
			int			ntups2;
			int			i2;
2486

V
Vadim B. Mikheev 已提交
2487
			if (g_verbose)
2488
				write_msg(NULL, "finding triggers for table %s\n", tblinfo[i].relname);
2489

B
Hi, all  
Bruce Momjian 已提交
2490
			resetPQExpBuffer(query);
2491
			appendPQExpBuffer(query,
2492 2493 2494 2495 2496
					   "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, "
						   "tgisconstraint, tgconstrname, tgdeferrable, "
							  "tgconstrrelid, tginitdeferred, oid, "
			  "(select relname from pg_class where oid = tgconstrrelid) "
							  "		as tgconstrrelname "
2497 2498 2499
							  "from pg_trigger "
							  "where tgrelid = '%s'::oid ",
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2500
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2501
			if (!res2 ||
2502
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2503
			{
2504
				write_msg(NULL, "query to obtain list of triggers failed: %s", PQerrorMessage(g_conn));
2505
				exit_nicely();
V
Vadim B. Mikheev 已提交
2506 2507 2508 2509
			}
			ntups2 = PQntuples(res2);
			if (ntups2 != tblinfo[i].ntrig)
			{
2510 2511
				write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
						  tblinfo[i].ntrig, tblinfo[i].relname, ntups2);
2512
				exit_nicely();
V
Vadim B. Mikheev 已提交
2513 2514 2515 2516 2517 2518
			}
			i_tgname = PQfnumber(res2, "tgname");
			i_tgfoid = PQfnumber(res2, "tgfoid");
			i_tgtype = PQfnumber(res2, "tgtype");
			i_tgnargs = PQfnumber(res2, "tgnargs");
			i_tgargs = PQfnumber(res2, "tgargs");
B
Bruce,  
Bruce Momjian 已提交
2519
			i_tgoid = PQfnumber(res2, "oid");
2520 2521 2522
			i_tgisconstraint = PQfnumber(res2, "tgisconstraint");
			i_tgconstrname = PQfnumber(res2, "tgconstrname");
			i_tgdeferrable = PQfnumber(res2, "tgdeferrable");
2523 2524
			i_tgconstrrelid = PQfnumber(res2, "tgconstrrelid");
			i_tgconstrrelname = PQfnumber(res2, "tgconstrrelname");
2525 2526
			i_tginitdeferred = PQfnumber(res2, "tginitdeferred");

B
Bruce Momjian 已提交
2527
			tblinfo[i].triggers = (TrigInfo *) malloc(ntups2 * sizeof(TrigInfo));
B
Hi, all  
Bruce Momjian 已提交
2528 2529
			resetPQExpBuffer(query);
			for (i2 = 0; i2 < ntups2; i2++)
V
Vadim B. Mikheev 已提交
2530
			{
2531
				const char *tgfuncoid = PQgetvalue(res2, i2, i_tgfoid);
2532
				char	   *tgfunc = NULL;
2533 2534
				int2		tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
				int			tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
B
Bruce Momjian 已提交
2535
				const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
2536 2537 2538
				int			tgisconstraint;
				int			tgdeferrable;
				int			tginitdeferred;
2539 2540
				char	   *tgconstrrelid;
				char	   *tgname;
B
Bruce Momjian 已提交
2541
				const char *p;
2542 2543
				int			findx;

2544 2545
				tgname = PQgetvalue(res2, i2, i_tgname);

2546
				if (strcmp(PQgetvalue(res2, i2, i_tgisconstraint), "f") == 0)
2547
					tgisconstraint = 0;
2548
				else
2549
					tgisconstraint = 1;
2550 2551

				if (strcmp(PQgetvalue(res2, i2, i_tgdeferrable), "f") == 0)
2552
					tgdeferrable = 0;
2553
				else
2554
					tgdeferrable = 1;
2555 2556

				if (strcmp(PQgetvalue(res2, i2, i_tginitdeferred), "f") == 0)
2557
					tginitdeferred = 0;
2558
				else
2559
					tginitdeferred = 1;
2560

V
Vadim B. Mikheev 已提交
2561 2562
				for (findx = 0; findx < numFuncs; findx++)
				{
2563
					if (strcmp(finfo[findx].oid, tgfuncoid) == 0 &&
2564
						finfo[findx].nargs == 0 &&
V
Vadim B. Mikheev 已提交
2565 2566 2567
						strcmp(finfo[findx].prorettype, "0") == 0)
						break;
				}
2568

V
Vadim B. Mikheev 已提交
2569 2570
				if (findx == numFuncs)
				{
2571
					PGresult   *r;
2572
					int			numFuncs;
2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589

					/*
					 * the funcname is an oid which we use to find the
					 * name of the pg_proc.  We need to do this because
					 * getFuncs() only reads in the user-defined funcs not
					 * all the funcs.  We might not find what we want by
					 * looking in FuncInfo*
					 */
					resetPQExpBuffer(query);
					appendPQExpBuffer(query,
									  "SELECT proname from pg_proc "
									  "where pg_proc.oid = '%s'::oid",
									  tgfuncoid);

					r = PQexec(g_conn, query->data);
					if (!r || PQresultStatus(r) != PGRES_TUPLES_OK)
					{
2590 2591
						write_msg(NULL, "query to obtain procedure name for trigger \"%s\" failed: %s",
								  tgname, PQerrorMessage(g_conn));
2592
						exit_nicely();
2593 2594 2595 2596
					}

					/* Sanity: Check we got only one tuple */
					numFuncs = PQntuples(r);
B
Bruce Momjian 已提交
2597 2598
					if (numFuncs != 1)
					{
2599 2600 2601 2602 2603 2604
						if (numFuncs == 0)
							write_msg(NULL, "query to obtain procedure name for trigger \"%s\" (procedure OID %s) returned no rows\n",
									  tgname, tgfuncoid);
						else
							write_msg(NULL, "query to obtain procedure name for trigger \"%s\" (procedure OID %s) returned %d rows\n",
									  tgname, tgfuncoid, numFuncs);
2605
						exit_nicely();
2606
					}
2607

2608
					tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
2609
					PQclear(r);
2610
				}
2611
				else
2612
					tgfunc = strdup(finfo[findx].proname);
B
Bruce Momjian 已提交
2613

2614
				appendPQExpBuffer(delqry, "DROP TRIGGER %s ", fmtId(tgname, force_quotes));
B
Bruce Momjian 已提交
2615
				appendPQExpBuffer(delqry, "ON %s;\n",
B
Bruce Momjian 已提交
2616
								fmtId(tblinfo[i].relname, force_quotes));
2617

B
Hi, all  
Bruce Momjian 已提交
2618
				resetPQExpBuffer(query);
2619 2620 2621 2622 2623
				if (tgisconstraint)
				{
					appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgconstrname), force_quotes));
				}
2624 2625
				else
				{
2626
					appendPQExpBuffer(query, "CREATE TRIGGER ");
2627
					appendPQExpBuffer(query, fmtId(tgname, force_quotes));
2628
				}
B
Bruce Momjian 已提交
2629
				appendPQExpBufferChar(query, ' ');
V
Vadim B. Mikheev 已提交
2630 2631 2632
				/* Trigger type */
				findx = 0;
				if (TRIGGER_FOR_BEFORE(tgtype))
B
Hi, all  
Bruce Momjian 已提交
2633
					appendPQExpBuffer(query, "BEFORE");
V
Vadim B. Mikheev 已提交
2634
				else
B
Hi, all  
Bruce Momjian 已提交
2635
					appendPQExpBuffer(query, "AFTER");
V
Vadim B. Mikheev 已提交
2636 2637
				if (TRIGGER_FOR_INSERT(tgtype))
				{
B
Hi, all  
Bruce Momjian 已提交
2638
					appendPQExpBuffer(query, " INSERT");
V
Vadim B. Mikheev 已提交
2639 2640 2641 2642 2643
					findx++;
				}
				if (TRIGGER_FOR_DELETE(tgtype))
				{
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2644
						appendPQExpBuffer(query, " OR DELETE");
V
Vadim B. Mikheev 已提交
2645
					else
B
Hi, all  
Bruce Momjian 已提交
2646
						appendPQExpBuffer(query, " DELETE");
V
Vadim B. Mikheev 已提交
2647 2648 2649
					findx++;
				}
				if (TRIGGER_FOR_UPDATE(tgtype))
2650
				{
V
Vadim B. Mikheev 已提交
2651
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2652
						appendPQExpBuffer(query, " OR UPDATE");
V
Vadim B. Mikheev 已提交
2653
					else
B
Hi, all  
Bruce Momjian 已提交
2654
						appendPQExpBuffer(query, " UPDATE");
2655
				}
2656 2657
				appendPQExpBuffer(query, " ON %s ", fmtId(tblinfo[i].relname, force_quotes));

2658
				if (tgisconstraint)
2659
				{
2660 2661
					tgconstrrelid = PQgetvalue(res2, i2, i_tgconstrrelid);

2662 2663
					if (strcmp(tgconstrrelid, "0") != 0)
					{
2664 2665

						if (PQgetisnull(res2, i2, i_tgconstrrelname))
2666
						{
2667
							write_msg(NULL, "query produced NULL referenced table name for foreign key trigger \"%s\" on table \"%s\" (oid of table: %s)\n",
2668
							  tgname, tblinfo[i].relname, tgconstrrelid);
2669
							exit_nicely();
2670
						}
2671

2672
						appendPQExpBuffer(query, " FROM %s",
2673
										  fmtId(PQgetvalue(res2, i2, i_tgconstrrelname), force_quotes));
2674
					}
2675
					if (!tgdeferrable)
2676 2677 2678 2679
						appendPQExpBuffer(query, " NOT");
					appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
					if (tginitdeferred)
						appendPQExpBuffer(query, "DEFERRED");
2680
					else
2681
						appendPQExpBuffer(query, "IMMEDIATE");
2682

2683 2684 2685
				}

				appendPQExpBuffer(query, " FOR EACH ROW");
2686 2687
				appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
								  fmtId(tgfunc, force_quotes));
V
Vadim B. Mikheev 已提交
2688 2689
				for (findx = 0; findx < tgnargs; findx++)
				{
2690
					const char *s;
2691 2692

					for (p = tgargs;;)
V
Vadim B. Mikheev 已提交
2693
					{
2694
						p = strchr(p, '\\');
V
Vadim B. Mikheev 已提交
2695 2696
						if (p == NULL)
						{
2697 2698 2699 2700
							write_msg(NULL, "bad argument string (%s) for trigger \"%s\" on table \"%s\"\n",
									  PQgetvalue(res2, i2, i_tgargs),
									  tgname,
									  tblinfo[i].relname);
2701
							exit_nicely();
V
Vadim B. Mikheev 已提交
2702 2703 2704 2705 2706 2707 2708
						}
						p++;
						if (*p == '\\')
						{
							p++;
							continue;
						}
2709
						if (p[0] == '0' && p[1] == '0' && p[2] == '0')
V
Vadim B. Mikheev 已提交
2710 2711 2712
							break;
					}
					p--;
2713
					appendPQExpBufferChar(query, '\'');
B
Bruce Momjian 已提交
2714
					for (s = tgargs; s < p;)
V
Vadim B. Mikheev 已提交
2715 2716
					{
						if (*s == '\'')
2717 2718
							appendPQExpBufferChar(query, '\\');
						appendPQExpBufferChar(query, *s++);
V
Vadim B. Mikheev 已提交
2719
					}
B
Bruce Momjian 已提交
2720 2721
					appendPQExpBufferChar(query, '\'');
					appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
V
Vadim B. Mikheev 已提交
2722 2723
					tgargs = p + 4;
				}
B
Hi, all  
Bruce Momjian 已提交
2724
				appendPQExpBuffer(query, ");\n");
2725

B
Bruce Momjian 已提交
2726
				tblinfo[i].triggers[i2].tgsrc = strdup(query->data);
B
Bruce,  
Bruce Momjian 已提交
2727 2728

				/*** Initialize trcomments and troids ***/
2729

B
Bruce,  
Bruce Momjian 已提交
2730
				resetPQExpBuffer(query);
2731
				appendPQExpBuffer(query, "TRIGGER %s ",
2732
								  fmtId(tgname, force_quotes));
B
Bruce,  
Bruce Momjian 已提交
2733
				appendPQExpBuffer(query, "ON %s",
2734
								fmtId(tblinfo[i].relname, force_quotes));
B
Bruce Momjian 已提交
2735 2736
				tblinfo[i].triggers[i2].tgcomment = strdup(query->data);
				tblinfo[i].triggers[i2].oid = strdup(PQgetvalue(res2, i2, i_tgoid));
2737
				tblinfo[i].triggers[i2].tgname = strdup(fmtId(tgname, false));
B
Bruce Momjian 已提交
2738
				tblinfo[i].triggers[i2].tgdel = strdup(delqry->data);
B
Bruce,  
Bruce Momjian 已提交
2739

2740 2741
				if (tgfunc)
					free(tgfunc);
V
Vadim B. Mikheev 已提交
2742 2743 2744 2745 2746
			}
			PQclear(res2);
		}
		else
			tblinfo[i].triggers = NULL;
2747

2748 2749
	}

2750 2751
	destroyPQExpBuffer(query);
	destroyPQExpBuffer(delqry);
2752
	destroyPQExpBuffer(lockquery);
2753

2754
	return tblinfo;
2755 2756 2757 2758
}

/*
 * getInherits
2759
 *	  read all the inheritance information
2760 2761
 * from the system catalogs return them in the InhInfo* structure
 *
2762
 * numInherits is set to the number of tables read in
2763
 */
2764
InhInfo *
2765 2766
getInherits(int *numInherits)
{
2767
	PGresult   *res;
2768 2769
	int			ntups;
	int			i;
2770 2771
	PQExpBuffer query = createPQExpBuffer();
	InhInfo    *inhinfo;
2772

2773
	int			i_inhrelid;
2774
	int			i_inhparent;
2775 2776 2777

	/* find all the inheritance information */

B
Hi, all  
Bruce Momjian 已提交
2778
	appendPQExpBuffer(query, "SELECT inhrelid, inhparent from pg_inherits");
2779

B
Hi, all  
Bruce Momjian 已提交
2780
	res = PQexec(g_conn, query->data);
2781 2782 2783
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
2784 2785
		write_msg(NULL, "query to obtain inheritance relationships failed: %s",
				  PQerrorMessage(g_conn));
2786
		exit_nicely();
2787 2788 2789 2790 2791 2792 2793 2794
	}

	ntups = PQntuples(res);

	*numInherits = ntups;

	inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));

2795
	i_inhrelid = PQfnumber(res, "inhrelid");
2796 2797 2798 2799
	i_inhparent = PQfnumber(res, "inhparent");

	for (i = 0; i < ntups; i++)
	{
2800
		inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
2801 2802 2803 2804
		inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
	}

	PQclear(res);
2805 2806 2807

	destroyPQExpBuffer(query);

2808
	return inhinfo;
2809 2810 2811 2812
}

/*
 * getTableAttrs -
2813 2814
 *	  for each table in tblinfo, read its attributes types and names
 *
2815
 * this is implemented in a very inefficient way right now, looping
2816
 * through the tblinfo and doing a join per table to find the attrs and their
2817 2818
 * types
 *
2819
 *	modifies tblinfo
2820 2821
 */
void
2822
getTableAttrs(TableInfo *tblinfo, int numTables)
2823
{
2824 2825
	int			i,
				j;
2826
	PQExpBuffer q = createPQExpBuffer();
2827 2828
	int			i_attname;
	int			i_typname;
2829
	int			i_atttypmod;
2830
	int			i_attnotnull;
V
Vadim B. Mikheev 已提交
2831
	int			i_atthasdef;
2832
	int			i_atttypedefn;
2833
	PGresult   *res;
2834
	int			ntups;
2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848

	for (i = 0; i < numTables; i++)
	{
		if (tblinfo[i].sequence)
			continue;

		/* find all the user attributes and their types */
		/* we must read the attribute names in attribute number order! */

		/*
		 * because we will use the attnum to index into the attnames array
		 * later
		 */
		if (g_verbose)
2849 2850
			write_msg(NULL, "finding the columns and types for table %s\n",
					  tblinfo[i].relname);
2851

B
Hi, all  
Bruce Momjian 已提交
2852
		resetPQExpBuffer(q);
2853 2854 2855 2856

		if (g_fout->remoteVersion < 70100)
		{
			/* Fake the LOJ below */
2857
			appendPQExpBuffer(q,
2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875
				 "  SELECT a.attnum, a.attname, t.typname, a.atttypmod, "
				"        a.attnotnull, a.atthasdef, NULL as atttypedefn "
							  "    from pg_attribute a, pg_type t "
							  "    where a.attrelid = '%s'::oid "
							  "        and a.attnum > 0 "
							  "        and a.atttypid = t.oid "
							  " UNION ALL SELECT a.attnum, a.attname, NULL as typname, a.atttypmod, "
				"        a.attnotnull, a.atthasdef, NULL as atttypedefn "
							  "    from pg_attribute a "
							  "    where a.attrelid = '%s'::oid "
							  "        and a.attnum > 0 "
							  "        and Not Exists(Select * From pg_type t where a.atttypid = t.oid)"
							  "    order by attnum",
							  tblinfo[i].oid, tblinfo[i].oid);

		}
		else
		{
2876
			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, t.typname, a.atttypmod, "
2877 2878 2879 2880 2881
							  "a.attnotnull, a.atthasdef, format_type(a.atttypid, a.atttypmod) as atttypedefn "
							  "from pg_attribute a LEFT OUTER JOIN pg_type t ON a.atttypid = t.oid "
							  "where a.attrelid = '%s'::oid "
							  "and a.attnum > 0 order by attnum",
							  tblinfo[i].oid);
2882 2883
		}

B
Hi, all  
Bruce Momjian 已提交
2884
		res = PQexec(g_conn, q->data);
2885 2886 2887
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
2888
			write_msg(NULL, "query to get table columns failed: %s", PQerrorMessage(g_conn));
2889
			exit_nicely();
2890 2891 2892 2893 2894 2895
		}

		ntups = PQntuples(res);

		i_attname = PQfnumber(res, "attname");
		i_typname = PQfnumber(res, "typname");
2896
		i_atttypmod = PQfnumber(res, "atttypmod");
2897
		i_attnotnull = PQfnumber(res, "attnotnull");
V
Vadim B. Mikheev 已提交
2898
		i_atthasdef = PQfnumber(res, "atthasdef");
2899
		i_atttypedefn = PQfnumber(res, "atttypedefn");
2900 2901 2902

		tblinfo[i].numatts = ntups;
		tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
2903
		tblinfo[i].atttypedefns = (char **) malloc(ntups * sizeof(char *));
2904
		tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
2905
		tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
2906
		tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
2907 2908
		tblinfo[i].inhAttrDef = (int *) malloc(ntups * sizeof(int));
		tblinfo[i].inhNotNull = (int *) malloc(ntups * sizeof(int));
2909
		tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
V
Vadim B. Mikheev 已提交
2910
		tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
2911 2912 2913 2914
		tblinfo[i].parentRels = NULL;
		tblinfo[i].numParents = 0;
		for (j = 0; j < ntups; j++)
		{
2915 2916 2917
			/* Sanity check on LOJ */
			if (PQgetisnull(res, j, i_typname))
			{
2918
				write_msg(NULL, "query produced NULL name for data type of column %d of table %s\n",
2919
						  j + 1, tblinfo[i].relname);
2920
				exit_nicely();
2921 2922
			}

2923
			tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
2924
			tblinfo[i].atttypedefns[j] = strdup(PQgetvalue(res, j, i_atttypedefn));
2925
			tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
2926
			tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
2927 2928
			tblinfo[i].inhAttrs[j] = 0; /* this flag is set in
										 * flagInhAttrs() */
2929 2930 2931
			tblinfo[i].inhAttrDef[j] = 0;
			tblinfo[i].inhNotNull[j] = 0;

2932
			tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't') ? true : false;
V
Vadim B. Mikheev 已提交
2933 2934 2935
			if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
			{
				PGresult   *res2;
2936
				int			numAttr;
2937

V
Vadim B. Mikheev 已提交
2938
				if (g_verbose)
2939 2940
					write_msg(NULL, "finding DEFAULT expression for column %s\n",
							  tblinfo[i].attnames[j]);
2941

B
Hi, all  
Bruce Momjian 已提交
2942 2943
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
2944 2945
							 "where adrelid = '%s'::oid and adnum = %d ",
								  tblinfo[i].oid, j + 1);
B
Hi, all  
Bruce Momjian 已提交
2946
				res2 = PQexec(g_conn, q->data);
V
Vadim B. Mikheev 已提交
2947
				if (!res2 ||
2948
					PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2949
				{
2950 2951
					write_msg(NULL, "query to get column default value failed: %s",
							  PQerrorMessage(g_conn));
2952
					exit_nicely();
V
Vadim B. Mikheev 已提交
2953
				}
2954 2955 2956

				/* Sanity: Check we got only one tuple */
				numAttr = PQntuples(res2);
B
Bruce Momjian 已提交
2957 2958
				if (numAttr != 1)
				{
2959 2960
					write_msg(NULL, "query to get default value for column \"%s\" returned %d rows; expected 1\n",
							  tblinfo[i].attnames[j], numAttr);
2961
					exit_nicely();
2962 2963
				}

V
Vadim B. Mikheev 已提交
2964 2965 2966 2967 2968
				tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
				PQclear(res2);
			}
			else
				tblinfo[i].adef_expr[j] = NULL;
2969 2970 2971
		}
		PQclear(res);
	}
2972 2973

	destroyPQExpBuffer(q);
2974 2975 2976 2977
}


/*
2978 2979
 * getIndexes
 *	  read all the user-defined indexes information
2980 2981
 * from the system catalogs return them in the InhInfo* structure
 *
2982
 * numIndexes is set to the number of indexes read in
2983
 *
2984 2985
 *
 */
2986
IndInfo *
2987
getIndexes(int *numIndexes)
2988
{
2989
	int			i;
2990
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2991
	PGresult   *res;
2992
	int			ntups;
B
Bruce Momjian 已提交
2993
	IndInfo    *indinfo;
2994

2995 2996
	int			i_indexreloid;
	int			i_indreloid;
2997 2998
	int			i_indexrelname;
	int			i_indrelname;
2999
	int			i_indexdef;
3000
	int			i_indisprimary;
3001
	int			i_indkey;
3002 3003

	/*
3004
	 * find all the user-defined indexes.
3005
	 *
3006
	 * Notice we skip indexes on system classes
3007
	 *
3008
	 * XXXX: Use LOJ
3009 3010
	 */

B
Hi, all  
Bruce Momjian 已提交
3011
	appendPQExpBuffer(query,
3012 3013
					  "SELECT i.indexrelid as indexreloid, "
					  "i.indrelid as indreloid, "
3014
				 "t1.relname as indexrelname, t2.relname as indrelname, "
3015 3016 3017
					  "pg_get_indexdef(i.indexrelid) as indexdef, "
					  "i.indisprimary, i.indkey "
					  "from pg_index i, pg_class t1, pg_class t2 "
3018
				   "WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid "
3019
					  "and i.indexrelid > '%u'::oid "
3020
					  "and t2.relname !~ '^pg_' ",
3021
					  g_last_builtin_oid);
3022

3023 3024 3025
	if (g_fout->remoteVersion < 70100)
		appendPQExpBuffer(query, " and t2.relkind != 'l'");

B
Hi, all  
Bruce Momjian 已提交
3026
	res = PQexec(g_conn, query->data);
3027 3028 3029
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
3030
		write_msg(NULL, "query to obtain list of indexes failed: %s", PQerrorMessage(g_conn));
3031
		exit_nicely();
3032 3033 3034 3035
	}

	ntups = PQntuples(res);

3036
	*numIndexes = ntups;
3037 3038 3039

	indinfo = (IndInfo *) malloc(ntups * sizeof(IndInfo));

3040 3041
	memset((char *) indinfo, 0, ntups * sizeof(IndInfo));

3042 3043
	i_indexreloid = PQfnumber(res, "indexreloid");
	i_indreloid = PQfnumber(res, "indreloid");
3044 3045
	i_indexrelname = PQfnumber(res, "indexrelname");
	i_indrelname = PQfnumber(res, "indrelname");
3046
	i_indexdef = PQfnumber(res, "indexdef");
3047
	i_indisprimary = PQfnumber(res, "indisprimary");
3048
	i_indkey = PQfnumber(res, "indkey");
3049 3050 3051

	for (i = 0; i < ntups; i++)
	{
3052 3053
		indinfo[i].indexreloid = strdup(PQgetvalue(res, i, i_indexreloid));
		indinfo[i].indreloid = strdup(PQgetvalue(res, i, i_indreloid));
3054 3055
		indinfo[i].indexrelname = strdup(PQgetvalue(res, i, i_indexrelname));
		indinfo[i].indrelname = strdup(PQgetvalue(res, i, i_indrelname));
3056 3057
		indinfo[i].indexdef = strdup(PQgetvalue(res, i, i_indexdef));
		indinfo[i].indisprimary = strdup(PQgetvalue(res, i, i_indisprimary));
3058 3059 3060
		parseNumericArray(PQgetvalue(res, i, i_indkey),
						  indinfo[i].indkey,
						  INDEX_MAX_KEYS);
3061 3062
	}
	PQclear(res);
3063 3064 3065

	destroyPQExpBuffer(query);

3066
	return indinfo;
3067 3068
}

B
Bruce,  
Bruce Momjian 已提交
3069
/*------------------------------------------------------------------
3070
 * dumpComment --
B
Bruce,  
Bruce Momjian 已提交
3071
 *
3072
 * This routine is used to dump any comments associated with the
B
Bruce,  
Bruce Momjian 已提交
3073
 * oid handed to this routine. The routine takes a constant character
3074 3075 3076 3077 3078 3079
 * string for the target part of the comment-creation command, plus
 * OID, class name, and subid which are the primary key for pg_description.
 * If a matching pg_description entry is found, it is dumped.
 * Additional dependencies can be passed for the comment, too --- this is
 * needed for VIEWs, whose comments are filed under the table OID but
 * which are dumped in order by their rule OID.
B
Bruce,  
Bruce Momjian 已提交
3080 3081 3082
 *------------------------------------------------------------------
*/

T
Tom Lane 已提交
3083
static void
3084
dumpComment(Archive *fout, const char *target, const char *oid,
3085
			const char *classname, int subid,
3086
			const char *((*deps)[]))
3087 3088
{
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
3089
	PQExpBuffer query;
3090
	int			i_description;
B
Bruce,  
Bruce Momjian 已提交
3091

3092 3093 3094 3095
	/* Comments are SCHEMA not data */
	if (dataOnly)
		return;

B
Bruce,  
Bruce Momjian 已提交
3096 3097 3098
	/*** Build query to find comment ***/

	query = createPQExpBuffer();
3099 3100 3101 3102

	if (fout->remoteVersion >= 70200)
	{
		appendPQExpBuffer(query, "SELECT description FROM pg_description "
3103
						  "WHERE objoid = '%s'::oid and classoid = "
3104
					   "(SELECT oid FROM pg_class where relname = '%s') "
3105 3106 3107 3108 3109 3110
						  "and objsubid = %d",
						  oid, classname, subid);
	}
	else
	{
		/* Note: this will fail to find attribute comments in pre-7.2... */
3111
		appendPQExpBuffer(query, "SELECT description FROM pg_description WHERE objoid = '%s'::oid", oid);
3112
	}
B
Bruce,  
Bruce Momjian 已提交
3113 3114 3115 3116

	/*** Execute query ***/

	res = PQexec(g_conn, query->data);
3117 3118
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
3119
		write_msg(NULL, "query to get comment on oid %s failed: %s",
3120
				  oid, PQerrorMessage(g_conn));
3121
		exit_nicely();
B
Bruce,  
Bruce Momjian 已提交
3122 3123 3124 3125
	}

	/*** If a comment exists, build COMMENT ON statement ***/

3126
	if (PQntuples(res) == 1)
3127
	{
B
Bruce,  
Bruce Momjian 已提交
3128
		i_description = PQfnumber(res, "description");
B
Bruce Momjian 已提交
3129
		resetPQExpBuffer(query);
3130
		appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
3131 3132
		formatStringLiteral(query, PQgetvalue(res, 0, i_description),
							PASS_LFTAB);
3133
		appendPQExpBuffer(query, ";\n");
B
Bruce Momjian 已提交
3134

3135 3136
		ArchiveEntry(fout, oid, target, "COMMENT", deps,
					 query->data, "" /* Del */ ,
B
Bruce Momjian 已提交
3137
					 "" /* Copy */ , "" /* Owner */ , NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
3138 3139 3140 3141 3142
	}

	/*** Clear the statement buffer and return ***/

	PQclear(res);
3143
	destroyPQExpBuffer(query);
B
Bruce,  
Bruce Momjian 已提交
3144 3145 3146
}

/*------------------------------------------------------------------
3147
 * dumpDBComment --
B
Bruce,  
Bruce Momjian 已提交
3148
 *
3149 3150
 * This routine is used to dump any comments associated with the
 * database to which we are currently connected. If the user chose
B
Bruce,  
Bruce Momjian 已提交
3151 3152 3153 3154 3155
 * to dump the schema of the database, then this is the first
 * statement issued.
 *------------------------------------------------------------------
*/

3156
void
B
Bruce Momjian 已提交
3157
dumpDBComment(Archive *fout)
3158 3159
{
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
3160
	PQExpBuffer query;
3161
	int			i_oid;
B
Bruce,  
Bruce Momjian 已提交
3162 3163 3164 3165

	/*** Build query to find comment ***/

	query = createPQExpBuffer();
3166
	appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = ");
3167
	formatStringLiteral(query, PQdb(g_conn), CONV_ALL);
B
Bruce,  
Bruce Momjian 已提交
3168 3169 3170 3171

	/*** Execute query ***/

	res = PQexec(g_conn, query->data);
3172 3173
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
3174
		write_msg(NULL, "query to get database oid failed: %s",
3175
				  PQerrorMessage(g_conn));
3176
		exit_nicely();
B
Bruce,  
Bruce Momjian 已提交
3177 3178 3179 3180
	}

	/*** If a comment exists, build COMMENT ON statement ***/

3181 3182
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
3183 3184 3185
		i_oid = PQfnumber(res, "oid");
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "DATABASE %s", fmtId(PQdb(g_conn), force_quotes));
3186 3187
		dumpComment(fout, query->data, PQgetvalue(res, 0, i_oid),
					"pg_database", 0, NULL);
B
Bruce,  
Bruce Momjian 已提交
3188 3189 3190 3191 3192
	}

	/*** Clear the statement buffer and return ***/

	PQclear(res);
3193
	destroyPQExpBuffer(query);
B
Bruce,  
Bruce Momjian 已提交
3194 3195
}

3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277
/*
 * dumpOneDomain
 *    wites out to fout the queries to recrease a user-defined domains
 *    as requested by dumpTypes
 */
void
dumpOneDomain(Archive *fout, TypeInfo *tinfo)
{
	PQExpBuffer q = createPQExpBuffer();
	PQExpBuffer delq = createPQExpBuffer();

	PGresult   *res;
	PQExpBuffer query = createPQExpBuffer();
	int			ntups;
	const char *((*deps)[]);
	int			depIdx = 0;


	deps = malloc(sizeof(char *) * 10);

	/* Fetch domain specific details */
	resetPQExpBuffer(query);
	appendPQExpBuffer(query, "SELECT typnotnull, "
							 "format_type(typbasetype, typtypmod) as typdefn, "
							 "typbasetype "
							 "FROM pg_type "
							 "WHERE typname = '%s'",
							 tinfo->typname);

	res = PQexec(g_conn, query->data);
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
		write_msg(NULL, "query to obtain domain information failed: %s", PQerrorMessage(g_conn));
		exit_nicely();
	}

	/* Expecting a single result only */
	ntups = PQntuples(res);
	if (ntups != 1)
		write_msg(NULL, "Domain %s non-existant.", fmtId(tinfo->typname, force_quotes));


	/* Drop the old copy */
	resetPQExpBuffer(delq);
	appendPQExpBuffer(delq, "DROP DOMAIN %s RESTRICT;\n", fmtId(tinfo->typname, force_quotes));

	resetPQExpBuffer(q);
	appendPQExpBuffer(q,
					  "CREATE DOMAIN %s AS %s",
					  fmtId(tinfo->typname, force_quotes),
					  PQgetvalue(res, 0, PQfnumber(res, "typdefn"))
					  );

	/* Depends on the base type */
	(*deps)[depIdx++] = strdup(PQgetvalue(res, 0, PQfnumber(res, "typbasetype")));

	if (PQgetvalue(res, 0, PQfnumber(res, "typnotnull"))[0] == 't')
		appendPQExpBuffer(q, " NOT NULL");

	if (tinfo->typdefault)
	{
		appendPQExpBuffer(q,
						  " DEFAULT %s",
						  tinfo->typdefault);
	}

	appendPQExpBuffer(q, ";\n");


	(*deps)[depIdx++] = NULL;		/* End of List */

	ArchiveEntry(fout, tinfo->oid, tinfo->typname, "DOMAIN", deps,
				 q->data, delq->data, "", tinfo->usename, NULL, NULL);

	/*** Dump Domain Comments ***/
	resetPQExpBuffer(q);

	appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->typname, force_quotes));
	dumpComment(fout, q->data, tinfo->oid, "pg_type", 0, NULL);
}

3278 3279
/*
 * dumpTypes
3280
 *	  writes out to fout the queries to recreate all the user-defined types
3281 3282 3283
 *
 */
void
B
Bruce Momjian 已提交
3284
dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
3285
		  TypeInfo *tinfo, int numTypes)
3286
{
3287
	int			i;
3288
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3289
	PQExpBuffer delq = createPQExpBuffer();
3290
	int			funcInd;
3291
	const char *((*deps)[]);
3292
	int			depIdx;
3293 3294 3295 3296

	for (i = 0; i < numTypes; i++)
	{
		/* skip all the builtin types */
3297
		if (atooid(tinfo[i].oid) <= g_last_builtin_oid)
3298 3299 3300
			continue;

		/* skip relation types */
3301
		if (atooid(tinfo[i].typrelid) != 0)
3302 3303
			continue;

3304 3305 3306 3307
		/* skip undefined placeholder types */
		if (!tinfo[i].isDefined)
			continue;

3308 3309 3310 3311 3312
		/* skip all array types that start w/ underscore */
		if ((tinfo[i].typname[0] == '_') &&
			(strcmp(tinfo[i].typinput, "array_in") == 0))
			continue;

3313 3314 3315 3316 3317 3318 3319
		/* Dump out domains as we run across them */
		if (strcmp(tinfo[i].typtype, "d") == 0) {
			dumpOneDomain(fout, &tinfo[i]);
			continue;
		}


3320
		deps = malloc(sizeof(char *) * 10);
3321 3322
		depIdx = 0;

3323 3324 3325 3326 3327 3328
		/*
		 * before we create a type, we need to create the input and output
		 * functions for it, if they haven't been created already
		 */
		funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typinput);
		if (funcInd != -1)
3329 3330
		{
			(*deps)[depIdx++] = strdup(finfo[funcInd].oid);
3331
			dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
3332
		}
3333 3334 3335

		funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
		if (funcInd != -1)
3336 3337
		{
			(*deps)[depIdx++] = strdup(finfo[funcInd].oid);
3338
			dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
3339
		}
3340

3341
		resetPQExpBuffer(delq);
B
Bruce Momjian 已提交
3342
		appendPQExpBuffer(delq, "DROP TYPE %s;\n", fmtId(tinfo[i].typname, force_quotes));
3343

B
Hi, all  
Bruce Momjian 已提交
3344 3345
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
3346
						  "CREATE TYPE %s "
3347
						  "( internallength = %s, externallength = %s,",
3348
						  fmtId(tinfo[i].typname, force_quotes),
3349 3350 3351 3352
						  (strcmp(tinfo[i].typlen, "-1") == 0) ?
						  "variable" : tinfo[i].typlen,
						  (strcmp(tinfo[i].typprtlen, "-1") == 0) ?
						  "variable" : tinfo[i].typprtlen);
3353 3354 3355 3356 3357 3358 3359
		/* cannot combine these because fmtId uses static result area */
		appendPQExpBuffer(q, " input = %s,",
						  fmtId(tinfo[i].typinput, force_quotes));
		appendPQExpBuffer(q, " output = %s,",
						  fmtId(tinfo[i].typoutput, force_quotes));
		appendPQExpBuffer(q, " send = %s,",
						  fmtId(tinfo[i].typsend, force_quotes));
3360
		appendPQExpBuffer(q, " receive = %s",
3361
						  fmtId(tinfo[i].typreceive, force_quotes));
3362 3363 3364 3365 3366 3367

		if (tinfo[i].typdefault != NULL)
		{
			appendPQExpBuffer(q, ", default = ");
			formatStringLiteral(q, tinfo[i].typdefault, CONV_ALL);
		}
3368 3369 3370

		if (tinfo[i].isArray)
		{
3371
			char	   *elemType;
3372

3373
			elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
3374 3375
			if (elemType == NULL)
			{
3376
				write_msg(NULL, "notice: array type %s - type for elements (oid %s) is not dumped\n",
3377
						  tinfo[i].typname, tinfo[i].typelem);
3378 3379 3380
				continue;
			}

3381
			appendPQExpBuffer(q, ", element = %s, delimiter = ", elemType);
3382
			formatStringLiteral(q, tinfo[i].typdelim, CONV_ALL);
3383 3384

			(*deps)[depIdx++] = strdup(tinfo[i].typelem);
3385
		}
3386

3387 3388 3389 3390 3391
		if (strcmp(tinfo[i].typalign, "c") == 0)
			appendPQExpBuffer(q, ", alignment = char");
		else if (strcmp(tinfo[i].typalign, "s") == 0)
			appendPQExpBuffer(q, ", alignment = int2");
		else if (strcmp(tinfo[i].typalign, "i") == 0)
3392 3393 3394 3395 3396 3397
			appendPQExpBuffer(q, ", alignment = int4");
		else if (strcmp(tinfo[i].typalign, "d") == 0)
			appendPQExpBuffer(q, ", alignment = double");

		if (strcmp(tinfo[i].typstorage, "p") == 0)
			appendPQExpBuffer(q, ", storage = plain");
3398
		else if (strcmp(tinfo[i].typstorage, "e") == 0)
3399
			appendPQExpBuffer(q, ", storage = external");
3400
		else if (strcmp(tinfo[i].typstorage, "x") == 0)
3401
			appendPQExpBuffer(q, ", storage = extended");
3402
		else if (strcmp(tinfo[i].typstorage, "m") == 0)
3403 3404
			appendPQExpBuffer(q, ", storage = main");

3405
		if (tinfo[i].passedbyvalue)
3406
			appendPQExpBuffer(q, ", passedbyvalue);\n");
3407
		else
B
Hi, all  
Bruce Momjian 已提交
3408
			appendPQExpBuffer(q, ");\n");
3409

3410
		(*deps)[depIdx++] = NULL;		/* End of List */
3411 3412

		ArchiveEntry(fout, tinfo[i].oid, tinfo[i].typname, "TYPE", deps,
B
Bruce Momjian 已提交
3413
				  q->data, delq->data, "", tinfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
3414

3415 3416


B
Bruce,  
Bruce Momjian 已提交
3417 3418 3419
		/*** Dump Type Comments ***/

		resetPQExpBuffer(q);
B
Bruce Momjian 已提交
3420

B
Bruce,  
Bruce Momjian 已提交
3421
		appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo[i].typname, force_quotes));
3422
		dumpComment(fout, q->data, tinfo[i].oid, "pg_type", 0, NULL);
3423
	}
3424 3425 3426

	destroyPQExpBuffer(q);
	destroyPQExpBuffer(delq);
3427 3428
}

3429 3430
/*
 * dumpProcLangs
B
Bruce Momjian 已提交
3431
 *		  writes out to fout the queries to recreate user-defined procedural languages
3432 3433 3434
 *
 */
void
B
Bruce Momjian 已提交
3435
dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
B
Bruce Momjian 已提交
3436
			  TypeInfo *tinfo, int numTypes)
3437
{
3438 3439
	PGresult   *res;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
3440 3441
	PQExpBuffer defqry = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
3442
	int			ntups;
B
Bruce Momjian 已提交
3443
	int			i_oid;
3444 3445 3446 3447
	int			i_lanname;
	int			i_lanpltrusted;
	int			i_lanplcallfoid;
	int			i_lancompiler;
3448
	Oid			lanoid;
3449 3450 3451
	char	   *lanname;
	char	   *lancompiler;
	const char *lanplcallfoid;
3452 3453 3454
	int			i,
				fidx;

B
Bruce Momjian 已提交
3455
	appendPQExpBuffer(query, "SELECT oid, * FROM pg_language "
3456 3457
					  "WHERE lanispl "
					  "ORDER BY oid");
B
Hi, all  
Bruce Momjian 已提交
3458
	res = PQexec(g_conn, query->data);
3459 3460 3461
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
3462
		write_msg(NULL, "query to obtain list of procedural languages failed: %s",
3463
				  PQerrorMessage(g_conn));
3464
		exit_nicely();
3465 3466 3467
	}
	ntups = PQntuples(res);

B
Bruce Momjian 已提交
3468 3469 3470 3471
	i_lanname = PQfnumber(res, "lanname");
	i_lanpltrusted = PQfnumber(res, "lanpltrusted");
	i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
	i_lancompiler = PQfnumber(res, "lancompiler");
B
Bruce Momjian 已提交
3472
	i_oid = PQfnumber(res, "oid");
3473

B
Bruce Momjian 已提交
3474 3475
	for (i = 0; i < ntups; i++)
	{
3476
		lanoid = atooid(PQgetvalue(res, i, i_oid));
3477 3478 3479
		if (lanoid <= g_last_builtin_oid)
			continue;

3480
		lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
3481 3482


3483 3484 3485 3486 3487 3488 3489
		for (fidx = 0; fidx < numFuncs; fidx++)
		{
			if (!strcmp(finfo[fidx].oid, lanplcallfoid))
				break;
		}
		if (fidx >= numFuncs)
		{
3490
			write_msg(NULL, "handler procedure for procedural language %s not found\n",
3491
					  PQgetvalue(res, i, i_lanname));
3492
			exit_nicely();
3493 3494 3495 3496
		}

		dumpOneFunc(fout, finfo, fidx, tinfo, numTypes);

3497 3498
		lanname = PQgetvalue(res, i, i_lanname);
		lancompiler = PQgetvalue(res, i, i_lancompiler);
3499

3500
		appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE ");
3501
		formatStringLiteral(delqry, lanname, CONV_ALL);
3502
		appendPQExpBuffer(delqry, ";\n");
3503

3504 3505 3506
		appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE ",
						  (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
						  "TRUSTED " : "");
3507
		formatStringLiteral(defqry, lanname, CONV_ALL);
3508 3509
		appendPQExpBuffer(defqry, " HANDLER %s LANCOMPILER ",
						  fmtId(finfo[fidx].proname, force_quotes));
3510
		formatStringLiteral(defqry, lancompiler, CONV_ALL);
3511
		appendPQExpBuffer(defqry, ";\n");
3512

B
Bruce Momjian 已提交
3513
		ArchiveEntry(fout, PQgetvalue(res, i, i_oid), lanname, "PROCEDURAL LANGUAGE",
B
Bruce Momjian 已提交
3514
				   NULL, defqry->data, delqry->data, "", "", NULL, NULL);
B
Bruce Momjian 已提交
3515

3516 3517
		resetPQExpBuffer(defqry);
		resetPQExpBuffer(delqry);
3518 3519 3520 3521
	}

	PQclear(res);

3522 3523 3524
	destroyPQExpBuffer(query);
	destroyPQExpBuffer(defqry);
	destroyPQExpBuffer(delqry);
3525 3526
}

3527 3528
/*
 * dumpFuncs
3529
 *	  writes out to fout the queries to recreate all the user-defined functions
3530 3531 3532
 *
 */
void
B
Bruce Momjian 已提交
3533
dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs,
3534
		  TypeInfo *tinfo, int numTypes)
3535
{
3536
	int			i;
3537 3538 3539

	for (i = 0; i < numFuncs; i++)
		dumpOneFunc(fout, finfo, i, tinfo, numTypes);
3540 3541 3542 3543
}

/*
 * dumpOneFunc:
3544 3545
 *	  dump out only one function,  the index of which is given in the third
 *	argument
3546 3547 3548
 *
 */

3549
static void
B
Bruce Momjian 已提交
3550
dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
3551
			TypeInfo *tinfo, int numTypes)
3552
{
3553
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3554 3555
	PQExpBuffer fn = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
B
Bruce,  
Bruce Momjian 已提交
3556
	PQExpBuffer fnlist = createPQExpBuffer();
3557
	PQExpBuffer asPart = createPQExpBuffer();
3558
	char		func_lang[NAMEDATALEN + 1];
3559 3560
	PGresult   *res;
	int			nlangs;
3561
	int			j;
3562 3563
	int			i_lanname;
	char		query[256];
3564

B
Bruce Momjian 已提交
3565 3566 3567 3568
	char	   *listSep;
	char	   *listSepComma = ",";
	char	   *listSepNone = "";
	char	   *rettypename;
3569

3570
	if (finfo[i].dumped)
3571 3572 3573
		goto done;

	finfo[i].dumped = 1;
3574

B
Bruce Momjian 已提交
3575
	/* becomeUser(fout, finfo[i].usename); */
3576

3577
	sprintf(query, "SELECT lanname FROM pg_language WHERE oid = '%u'::oid",
3578 3579 3580 3581
			finfo[i].lang);
	res = PQexec(g_conn, query);
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
B
Bruce Momjian 已提交
3582
	{
3583
		write_msg(NULL, "query to get name of procedural language failed: %s", PQerrorMessage(g_conn));
3584
		exit_nicely();
B
Bruce Momjian 已提交
3585
	}
3586 3587 3588
	nlangs = PQntuples(res);

	if (nlangs != 1)
B
Bruce Momjian 已提交
3589
	{
3590
		write_msg(NULL, "procedural language for function %s not found\n", finfo[i].proname);
3591
		exit_nicely();
B
Bruce Momjian 已提交
3592 3593
	}

3594
	i_lanname = PQfnumber(res, "lanname");
3595

3596
	/*
B
Bruce Momjian 已提交
3597 3598
	 * See backend/commands/define.c for details of how the 'AS' clause is
	 * used.
3599 3600 3601
	 */
	if (strcmp(finfo[i].probin, "-") != 0)
	{
3602
		appendPQExpBuffer(asPart, "AS ");
3603
		formatStringLiteral(asPart, finfo[i].probin, CONV_ALL);
3604
		if (strcmp(finfo[i].prosrc, "-") != 0)
3605 3606
		{
			appendPQExpBuffer(asPart, ", ");
3607
			formatStringLiteral(asPart, finfo[i].prosrc, PASS_LFTAB);
3608
		}
3609 3610 3611 3612
	}
	else
	{
		if (strcmp(finfo[i].prosrc, "-") != 0)
3613 3614
		{
			appendPQExpBuffer(asPart, "AS ");
3615
			formatStringLiteral(asPart, finfo[i].prosrc, PASS_LFTAB);
3616
		}
3617 3618
	}

3619
	strcpy(func_lang, PQgetvalue(res, 0, i_lanname));
B
Bruce Momjian 已提交
3620

3621
	PQclear(res);
B
Bruce Momjian 已提交
3622

B
Bruce Momjian 已提交
3623 3624
	resetPQExpBuffer(fn);
	appendPQExpBuffer(fn, "%s (", fmtId(finfo[i].proname, force_quotes));
3625 3626
	for (j = 0; j < finfo[i].nargs; j++)
	{
B
Bruce Momjian 已提交
3627
		char	   *typname;
3628

3629
		typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j], zeroAsOpaque);
3630 3631
		if (typname == NULL)
		{
3632 3633
			write_msg(NULL, "WARNING: function \"%s\" not dumped\n",
					  finfo[i].proname);
3634

3635
			write_msg(NULL, "reason: data type name of argument %d (oid %s) not found\n",
3636
					  j, finfo[i].argtypes[j]);
3637
			goto done;
3638 3639
		}

B
Bruce Momjian 已提交
3640 3641 3642
		appendPQExpBuffer(fn, "%s%s",
						  (j > 0) ? "," : "",
						  typname);
B
Bruce,  
Bruce Momjian 已提交
3643
		appendPQExpBuffer(fnlist, "%s%s",
B
Bruce Momjian 已提交
3644 3645
						  (j > 0) ? "," : "",
						  typname);
3646
	}
B
Bruce Momjian 已提交
3647 3648 3649
	appendPQExpBuffer(fn, ")");

	resetPQExpBuffer(delqry);
B
Bruce Momjian 已提交
3650
	appendPQExpBuffer(delqry, "DROP FUNCTION %s;\n", fn->data);
B
Bruce Momjian 已提交
3651

3652 3653 3654 3655
	rettypename = findTypeByOid(tinfo, numTypes, finfo[i].prorettype, zeroAsOpaque);

	if (rettypename == NULL)
	{
3656 3657
		write_msg(NULL, "WARNING: function \"%s\" not dumped\n",
				  finfo[i].proname);
3658

3659 3660
		write_msg(NULL, "reason: name of return data type (oid %s) not found\n",
				  finfo[i].prorettype);
3661
		goto done;
3662 3663
	}

B
Bruce Momjian 已提交
3664
	resetPQExpBuffer(q);
B
Bruce Momjian 已提交
3665
	appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data);
3666 3667
	appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ",
					  (finfo[i].retset) ? "SETOF " : "",
3668
					  rettypename,
3669
					  asPart->data);
3670
	formatStringLiteral(q, func_lang, CONV_ALL);
3671

3672 3673
	if (finfo[i].provolatile != PROVOLATILE_VOLATILE ||
		finfo[i].isstrict)		/* OR in new attrs here */
3674
	{
3675 3676 3677
		appendPQExpBuffer(q, " WITH (");
		listSep = listSepNone;

3678 3679 3680 3681 3682 3683
		if (finfo[i].provolatile == PROVOLATILE_IMMUTABLE)
		{
			appendPQExpBuffer(q, "%s isImmutable", listSep);
			listSep = listSepComma;
		}
		else if (finfo[i].provolatile == PROVOLATILE_STABLE)
B
Bruce Momjian 已提交
3684
		{
3685
			appendPQExpBuffer(q, "%s isStable", listSep);
3686 3687
			listSep = listSepComma;
		}
3688 3689 3690 3691 3692 3693
		else if (finfo[i].provolatile != PROVOLATILE_VOLATILE)
		{
			write_msg(NULL, "Unexpected provolatile value for function %s\n",
					  finfo[i].proname);
			exit_nicely();
		}
3694

B
Bruce Momjian 已提交
3695 3696
		if (finfo[i].isstrict)
		{
3697
			appendPQExpBuffer(q, "%s isStrict", listSep);
3698 3699 3700
			listSep = listSepComma;
		}
		appendPQExpBuffer(q, " )");
3701 3702 3703 3704
	}

	appendPQExpBuffer(q, ";\n");

B
Bruce Momjian 已提交
3705
	ArchiveEntry(fout, finfo[i].oid, fn->data, "FUNCTION", NULL, q->data, delqry->data,
B
Bruce Momjian 已提交
3706
				 "", finfo[i].usename, NULL, NULL);
3707

B
Bruce,  
Bruce Momjian 已提交
3708 3709 3710 3711 3712 3713
	/*** Dump Function Comments ***/

	resetPQExpBuffer(q);
	appendPQExpBuffer(q, "FUNCTION %s ",
					  fmtId(finfo[i].proname, force_quotes));
	appendPQExpBuffer(q, "( %s )", fnlist->data);
3714
	dumpComment(fout, q->data, finfo[i].oid, "pg_proc", 0, NULL);
3715 3716 3717 3718 3719 3720 3721

done:
	destroyPQExpBuffer(q);
	destroyPQExpBuffer(fn);
	destroyPQExpBuffer(delqry);
	destroyPQExpBuffer(fnlist);
	destroyPQExpBuffer(asPart);
3722 3723 3724 3725
}

/*
 * dumpOprs
3726
 *	  writes out to fout the queries to recreate all the user-defined operators
3727 3728
 *
 */
3729
void
B
Bruce Momjian 已提交
3730
dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
3731
		 TypeInfo *tinfo, int numTypes)
3732
{
B
Bruce Momjian 已提交
3733
	int			i;
3734
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3735
	PQExpBuffer delq = createPQExpBuffer();
3736 3737 3738 3739 3740 3741 3742 3743
	PQExpBuffer leftarg = createPQExpBuffer();
	PQExpBuffer rightarg = createPQExpBuffer();
	PQExpBuffer commutator = createPQExpBuffer();
	PQExpBuffer negator = createPQExpBuffer();
	PQExpBuffer restrictor = createPQExpBuffer();
	PQExpBuffer join = createPQExpBuffer();
	PQExpBuffer sort1 = createPQExpBuffer();
	PQExpBuffer sort2 = createPQExpBuffer();
3744 3745 3746

	for (i = 0; i < numOperators; i++)
	{
B
Bruce Momjian 已提交
3747
		char	   *name;
3748

B
Hi, all  
Bruce Momjian 已提交
3749 3750 3751 3752 3753 3754 3755 3756 3757
		resetPQExpBuffer(leftarg);
		resetPQExpBuffer(rightarg);
		resetPQExpBuffer(commutator);
		resetPQExpBuffer(negator);
		resetPQExpBuffer(restrictor);
		resetPQExpBuffer(join);
		resetPQExpBuffer(sort1);
		resetPQExpBuffer(sort2);

3758
		/* skip all the builtin oids */
3759
		if (atooid(oprinfo[i].oid) <= g_last_builtin_oid)
3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775
			continue;

		/*
		 * some operator are invalid because they were the result of user
		 * defining operators before commutators exist
		 */
		if (strcmp(oprinfo[i].oprcode, "-") == 0)
			continue;

		/*
		 * right unary means there's a left arg and left unary means
		 * there's a right arg
		 */
		if (strcmp(oprinfo[i].oprkind, "r") == 0 ||
			strcmp(oprinfo[i].oprkind, "b") == 0)
		{
B
Bruce Momjian 已提交
3776 3777
			name = findTypeByOid(tinfo, numTypes,
								 oprinfo[i].oprleft, zeroAsOpaque);
3778 3779
			if (name == NULL)
			{
3780 3781 3782 3783
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprleft (oid %s) not found\n",
						  oprinfo[i].oprleft);
3784 3785
				continue;
			}
B
Bruce Momjian 已提交
3786
			appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ", name);
3787
		}
3788

3789 3790 3791
		if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
			strcmp(oprinfo[i].oprkind, "b") == 0)
		{
B
Bruce Momjian 已提交
3792 3793
			name = findTypeByOid(tinfo, numTypes,
								 oprinfo[i].oprright, zeroAsOpaque);
3794 3795
			if (name == NULL)
			{
3796 3797 3798 3799
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprright (oid %s) not found\n",
						  oprinfo[i].oprright);
3800 3801 3802
				continue;
			}
			appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ", name);
3803
		}
3804

B
Hi, all  
Bruce Momjian 已提交
3805
		if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
3806 3807 3808 3809
		{
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom);
			if (name == NULL)
			{
3810 3811 3812 3813
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprcom (oid %s) not found\n",
						  oprinfo[i].oprcom);
3814 3815 3816 3817
				continue;
			}
			appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ", name);
		}
3818

B
Hi, all  
Bruce Momjian 已提交
3819
		if (!(strcmp(oprinfo[i].oprnegate, "0") == 0))
3820 3821 3822 3823
		{
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate);
			if (name == NULL)
			{
3824 3825 3826 3827
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprnegate (oid %s) not found\n",
						  oprinfo[i].oprnegate);
3828 3829 3830 3831
				continue;
			}
			appendPQExpBuffer(negator, ",\n\tNEGATOR = %s ", name);
		}
3832

B
Hi, all  
Bruce Momjian 已提交
3833 3834
		if (!(strcmp(oprinfo[i].oprrest, "-") == 0))
			appendPQExpBuffer(restrictor, ",\n\tRESTRICT = %s ", oprinfo[i].oprrest);
3835

B
Hi, all  
Bruce Momjian 已提交
3836 3837
		if (!(strcmp(oprinfo[i].oprjoin, "-") == 0))
			appendPQExpBuffer(join, ",\n\tJOIN = %s ", oprinfo[i].oprjoin);
3838

B
Hi, all  
Bruce Momjian 已提交
3839
		if (!(strcmp(oprinfo[i].oprlsortop, "0") == 0))
3840
		{
B
Bruce Momjian 已提交
3841
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprlsortop);
3842 3843
			if (name == NULL)
			{
3844 3845 3846 3847
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprlsortop (oid %s) not found\n",
						  oprinfo[i].oprlsortop);
3848 3849 3850 3851
				continue;
			}
			appendPQExpBuffer(sort1, ",\n\tSORT1 = %s ", name);
		}
3852

B
Hi, all  
Bruce Momjian 已提交
3853
		if (!(strcmp(oprinfo[i].oprrsortop, "0") == 0))
3854
		{
B
Bruce Momjian 已提交
3855
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprrsortop);
3856 3857
			if (name == NULL)
			{
3858 3859 3860 3861
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprrsortop (oid %s) not found\n",
						  oprinfo[i].oprrsortop);
3862 3863 3864 3865
				continue;
			}
			appendPQExpBuffer(sort2, ",\n\tSORT2 = %s ", name);
		}
3866

B
Bruce Momjian 已提交
3867
		resetPQExpBuffer(delq);
3868 3869
		appendPQExpBuffer(delq, "DROP OPERATOR %s (%s",
						  oprinfo[i].oprname,
3870 3871
					   findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft,
									 zeroAsNone));
B
Bruce Momjian 已提交
3872
		appendPQExpBuffer(delq, ", %s);\n",
3873 3874
					  findTypeByOid(tinfo, numTypes, oprinfo[i].oprright,
									zeroAsNone));
3875

B
Hi, all  
Bruce Momjian 已提交
3876 3877
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
3878 3879 3880 3881 3882 3883 3884 3885 3886
						  "CREATE OPERATOR %s "
						  "(PROCEDURE = %s %s%s%s%s%s%s%s%s%s);\n",
						  oprinfo[i].oprname,
						  oprinfo[i].oprcode,
						  leftarg->data,
						  rightarg->data,
						  commutator->data,
						  negator->data,
						  restrictor->data,
B
Bruce Momjian 已提交
3887
		  (strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
3888 3889 3890
						  join->data,
						  sort1->data,
						  sort2->data);
3891

B
Bruce Momjian 已提交
3892
		ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
B
Bruce Momjian 已提交
3893
				q->data, delq->data, "", oprinfo[i].usename, NULL, NULL);
3894
	}
3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905

	destroyPQExpBuffer(q);
	destroyPQExpBuffer(delq);
	destroyPQExpBuffer(leftarg);
	destroyPQExpBuffer(rightarg);
	destroyPQExpBuffer(commutator);
	destroyPQExpBuffer(negator);
	destroyPQExpBuffer(restrictor);
	destroyPQExpBuffer(join);
	destroyPQExpBuffer(sort1);
	destroyPQExpBuffer(sort2);
3906 3907 3908 3909
}

/*
 * dumpAggs
3910
 *	  writes out to fout the queries to create all the user-defined aggregates
3911 3912 3913
 *
 */
void
B
Bruce Momjian 已提交
3914
dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
3915
		 TypeInfo *tinfo, int numTypes)
3916
{
B
Bruce Momjian 已提交
3917
	int			i;
3918
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3919 3920
	PQExpBuffer delq = createPQExpBuffer();
	PQExpBuffer aggSig = createPQExpBuffer();
3921
	PQExpBuffer details = createPQExpBuffer();
3922 3923 3924

	for (i = 0; i < numAggs; i++)
	{
B
Bruce Momjian 已提交
3925
		char	   *name;
3926

3927
		resetPQExpBuffer(details);
B
Hi, all  
Bruce Momjian 已提交
3928

3929
		/* skip all the builtin oids */
3930
		if (oidle(atooid(agginfo[i].oid), g_last_builtin_oid))
3931 3932 3933 3934
			continue;

		resetPQExpBuffer(aggSig);
		appendPQExpBuffer(aggSig, "%s(%s)", agginfo[i].aggname,
3935 3936 3937
						  findTypeByOid(tinfo, numTypes,
										agginfo[i].aggbasetype,
										zeroAsStar + useBaseTypeName));
3938 3939 3940

		if (!agginfo[i].convertok)
		{
3941 3942 3943
			write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
					  aggSig->data);

3944
			resetPQExpBuffer(q);
3945
			appendPQExpBuffer(q, "-- WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
3946
							  aggSig->data);
3947
			ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
3948
			 q->data, "" /* Del */ , "", agginfo[i].usename, NULL, NULL);
3949
			continue;
3950
		}
3951

3952 3953
		name = findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype,
							 zeroAsAny + useBaseTypeName);
3954 3955
		if (name == NULL)
		{
3956 3957 3958 3959 3960 3961 3962 3963 3964
			write_msg(NULL, "WARNING: aggregate function \"%s\" (oid %s) not dumped\n",
					  agginfo[i].aggname, agginfo[i].oid);
			write_msg(NULL, "reason: aggbasetype (oid %s) not found\n",
					  agginfo[i].aggbasetype);

			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "-- WARNING: aggregate function \"%s\" (oid %s) not dumped\n", agginfo[i].aggname, agginfo[i].oid);
			appendPQExpBuffer(q, "-- reason: aggbasetype (oid %s) not found\n", agginfo[i].aggbasetype);
			ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
3965
			 q->data, "" /* Del */ , "", agginfo[i].usename, NULL, NULL);
3966 3967 3968
			continue;
		}
		appendPQExpBuffer(details, "BASETYPE = %s, ", name);
3969

3970 3971
		name = findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype,
							 zeroAsOpaque + useBaseTypeName);
3972 3973
		if (name == NULL)
		{
3974 3975 3976 3977 3978 3979 3980 3981 3982
			write_msg(NULL, "WARNING: aggregate function \"%s\" (oid %s) not dumped\n",
					  agginfo[i].aggname, agginfo[i].oid);
			write_msg(NULL, "reason: aggtranstype (oid %s) not found\n",
					  agginfo[i].aggtranstype);

			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "-- WARNING: aggregate function \"%s\" (oid %s) not dumped\n", agginfo[i].aggname, agginfo[i].oid);
			appendPQExpBuffer(q, "-- reason: aggtranstype (oid %s) not found\n", agginfo[i].aggtranstype);
			ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
3983
			 q->data, "" /* Del */ , "", agginfo[i].usename, NULL, NULL);
3984 3985
			continue;
		}
3986 3987
		appendPQExpBuffer(details,
						  "SFUNC = %s, STYPE = %s",
3988
						  agginfo[i].aggtransfn, name);
3989

3990
		if (agginfo[i].agginitval)
3991 3992
		{
			appendPQExpBuffer(details, ", INITCOND = ");
3993
			formatStringLiteral(details, agginfo[i].agginitval, CONV_ALL);
3994
		}
3995

B
Hi, all  
Bruce Momjian 已提交
3996
		if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
3997 3998
			appendPQExpBuffer(details, ", FINALFUNC = %s",
							  agginfo[i].aggfinalfn);
3999

B
Bruce Momjian 已提交
4000 4001
		resetPQExpBuffer(delq);
		appendPQExpBuffer(delq, "DROP AGGREGATE %s;\n", aggSig->data);
4002

B
Hi, all  
Bruce Momjian 已提交
4003
		resetPQExpBuffer(q);
4004
		appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
4005
						  agginfo[i].aggname,
4006
						  details->data);
4007

B
Bruce Momjian 已提交
4008
		ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
B
Bruce Momjian 已提交
4009
				q->data, delq->data, "", agginfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
4010 4011 4012 4013

		/*** Dump Aggregate Comments ***/

		resetPQExpBuffer(q);
4014
		appendPQExpBuffer(q, "AGGREGATE %s", aggSig->data);
4015
		dumpComment(fout, q->data, agginfo[i].oid, "pg_aggregate", 0, NULL);
4016
	}
4017 4018 4019 4020 4021

	destroyPQExpBuffer(q);
	destroyPQExpBuffer(delq);
	destroyPQExpBuffer(aggSig);
	destroyPQExpBuffer(details);
4022 4023
}

4024 4025 4026 4027 4028
/*
 * These are some support functions to fix the acl problem of pg_dump
 *
 * Matthew C. Aycock 12/02/97
 */
4029 4030 4031

/* Append a keyword to a keyword list, inserting comma if needed.
 * Caller must make aclbuf big enough for all possible keywords.
4032
 */
4033
static void
B
Bruce Momjian 已提交
4034
AddAcl(char *aclbuf, const char *keyword)
4035
{
4036 4037 4038
	if (*aclbuf)
		strcat(aclbuf, ",");
	strcat(aclbuf, keyword);
4039
}
4040

4041
/*
4042 4043 4044 4045 4046
 * This will take a string of privilege code letters and return a malloced,
 * comma delimited string of keywords for GRANT.
 *
 * Note: for cross-version compatibility, it's important to use ALL when
 * appropriate.
4047
 */
V
Vadim B. Mikheev 已提交
4048
static char *
4049
GetPrivileges(Archive *AH, const char *s)
4050
{
4051
	char		aclbuf[100];
4052
	bool		all = true;
4053

4054
	aclbuf[0] = '\0';
4055

4056 4057 4058 4059 4060
#define CONVERT_PRIV(code,keywd) \
	if (strchr(s, code)) \
		AddAcl(aclbuf, keywd); \
	else \
		all = false
4061

4062 4063 4064
	CONVERT_PRIV('a', "INSERT");
	CONVERT_PRIV('r', "SELECT");
	CONVERT_PRIV('R', "RULE");
4065

4066 4067
	if (AH->remoteVersion >= 70200)
	{
4068 4069 4070 4071
		CONVERT_PRIV('w', "UPDATE");
		CONVERT_PRIV('d', "DELETE");
		CONVERT_PRIV('x', "REFERENCES");
		CONVERT_PRIV('t', "TRIGGER");
4072 4073 4074
	}
	else
	{
4075 4076
		/* 7.0 and 7.1 have a simpler worldview */
		CONVERT_PRIV('w', "UPDATE,DELETE");
4077
	}
4078

4079 4080 4081 4082 4083 4084
#undef CONVERT_PRIV

	if (all)
		return strdup("ALL");
	else
		return strdup(aclbuf);
4085
}
4086

B
Bruce Momjian 已提交
4087
/*
4088
 * The name says it all; a function to append a string if the dest
B
Bruce Momjian 已提交
4089 4090
 * is big enough. If not, it does a realloc.
 */
B
Bruce Momjian 已提交
4091 4092
static void
strcatalloc(char **dest, int *dSize, char *src)
B
Bruce Momjian 已提交
4093
{
B
Bruce Momjian 已提交
4094 4095 4096 4097 4098 4099 4100 4101 4102 4103
	int			dLen = strlen(*dest);
	int			sLen = strlen(src);

	if ((dLen + sLen) >= *dSize)
	{
		*dSize = (dLen + sLen) * 2;
		*dest = realloc(*dest, *dSize);
	}
	strcpy(*dest + dLen, src);
}
B
Bruce Momjian 已提交
4104 4105


B
Bruce Momjian 已提交
4106 4107
/*
 * dumpACL:
4108 4109
 *	  Write out grant/revoke information
 *	  Called for sequences and tables
B
Bruce Momjian 已提交
4110 4111
 */

4112
static void
B
Bruce Momjian 已提交
4113
dumpACL(Archive *fout, TableInfo tbinfo)
B
Bruce Momjian 已提交
4114
{
B
Bruce Momjian 已提交
4115 4116
	const char *acls = tbinfo.relacl;
	char	   *aclbuf,
B
Bruce Momjian 已提交
4117 4118 4119
			   *tok,
			   *eqpos,
			   *priv;
4120
	char	   *objoid;
B
Bruce Momjian 已提交
4121
	char	   *sql;
B
Bruce Momjian 已提交
4122
	char		tmp[1024];
B
Bruce Momjian 已提交
4123
	int			sSize = 4096;
4124 4125 4126 4127

	if (strlen(acls) == 0)
		return;					/* table has default permissions */

B
Bruce Momjian 已提交
4128 4129 4130
	/*
	 * Allocate a larginsh buffer for the output SQL.
	 */
B
Bruce Momjian 已提交
4131
	sql = (char *) malloc(sSize);
B
Bruce Momjian 已提交
4132

B
Bruce Momjian 已提交
4133 4134 4135
	/*
	 * Revoke Default permissions for PUBLIC. Is this actually necessary,
	 * or is it just a waste of time?
4136
	 */
B
Bruce Momjian 已提交
4137
	sprintf(sql, "REVOKE ALL on %s from PUBLIC;\n",
4138
			fmtId(tbinfo.relname, force_quotes));
4139 4140 4141

	/* Make a working copy of acls so we can use strtok */
	aclbuf = strdup(acls);
B
Bruce Momjian 已提交
4142

4143 4144
	/* Scan comma-separated ACL items */
	for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
4145
	{
B
Bruce Momjian 已提交
4146 4147 4148
		/*
		 * Token may start with '{' and/or '"'.  Actually only the start
		 * of the string should have '{', but we don't verify that.
4149 4150 4151 4152 4153 4154 4155 4156
		 */
		if (*tok == '{')
			tok++;
		if (*tok == '"')
			tok++;

		/* User name is string up to = in tok */
		eqpos = strchr(tok, '=');
B
Bruce Momjian 已提交
4157
		if (!eqpos)
B
Bruce Momjian 已提交
4158
		{
4159 4160 4161
			write_msg(NULL, "could not parse ACL list ('%s') for relation %s\n",
					  acls, tbinfo.relname);
			exit_nicely();
B
Bruce Momjian 已提交
4162 4163
		}

B
Bruce Momjian 已提交
4164 4165 4166 4167
		/*
		 * Parse the privileges (right-hand side).	Skip if there are
		 * none.
		 */
4168
		priv = GetPrivileges(fout, eqpos + 1);
4169
		if (*priv)
4170
		{
B
Bruce Momjian 已提交
4171
			sprintf(tmp, "GRANT %s on %s to ",
4172
					priv, fmtId(tbinfo.relname, force_quotes));
B
Bruce Momjian 已提交
4173
			strcatalloc(&sql, &sSize, tmp);
B
Bruce Momjian 已提交
4174 4175 4176

			/*
			 * Note: fmtId() can only be called once per printf, so don't
4177 4178 4179 4180 4181
			 * try to merge printing of username into the above printf.
			 */
			if (eqpos == tok)
			{
				/* Empty left-hand side means "PUBLIC" */
B
Bruce Momjian 已提交
4182
				strcatalloc(&sql, &sSize, "PUBLIC;\n");
4183
			}
4184
			else
4185 4186
			{
				*eqpos = '\0';	/* it's ok to clobber aclbuf */
4187
				if (strncmp(tok, "group ", strlen("group ")) == 0)
B
Bruce Momjian 已提交
4188
					sprintf(tmp, "GROUP %s;\n",
4189 4190
							fmtId(tok + strlen("group "), force_quotes));
				else
B
Bruce Momjian 已提交
4191 4192
					sprintf(tmp, "%s;\n", fmtId(tok, force_quotes));
				strcatalloc(&sql, &sSize, tmp);
4193
			}
4194
		}
4195
		free(priv);
B
Bruce Momjian 已提交
4196
	}
4197 4198

	free(aclbuf);
B
Bruce Momjian 已提交
4199

4200 4201 4202 4203 4204 4205
	if (tbinfo.viewdef != NULL)
		objoid = tbinfo.viewoid;
	else
		objoid = tbinfo.oid;

	ArchiveEntry(fout, objoid, tbinfo.relname, "ACL", NULL, sql, "", "", "", NULL, NULL);
B
Bruce Momjian 已提交
4206 4207
}

4208 4209 4210
static void
_dumpTableAttr70(Archive *fout, TableInfo *tblinfo, int i, int j, PQExpBuffer q)
{
4211 4212 4213
	int32		tmp_typmod;
	int			precision;
	int			scale;
4214 4215 4216 4217 4218 4219 4220 4221 4222

	/* Show lengths on bpchar and varchar */
	if (!strcmp(tblinfo[i].typnames[j], "bpchar"))
	{
		int			len = (tblinfo[i].atttypmod[j] - VARHDRSZ);

		appendPQExpBuffer(q, "character");
		if (len > 1)
			appendPQExpBuffer(q, "(%d)",
4223
							  tblinfo[i].atttypmod[j] - VARHDRSZ);
4224 4225 4226 4227 4228 4229 4230
	}
	else if (!strcmp(tblinfo[i].typnames[j], "varchar"))
	{
		appendPQExpBuffer(q, "character varying");
		if (tblinfo[i].atttypmod[j] != -1)
		{
			appendPQExpBuffer(q, "(%d)",
4231
							  tblinfo[i].atttypmod[j] - VARHDRSZ);
4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247
		}
	}
	else if (!strcmp(tblinfo[i].typnames[j], "numeric"))
	{
		appendPQExpBuffer(q, "numeric");
		if (tblinfo[i].atttypmod[j] != -1)
		{
			tmp_typmod = tblinfo[i].atttypmod[j] - VARHDRSZ;
			precision = (tmp_typmod >> 16) & 0xffff;
			scale = tmp_typmod & 0xffff;
			appendPQExpBuffer(q, "(%d,%d)",
							  precision, scale);
		}
	}

	/*
4248 4249
	 * char is an internal single-byte data type; Let's make sure we force
	 * it through with quotes. - thomas 1998-12-13
4250 4251 4252 4253
	 */
	else if (!strcmp(tblinfo[i].typnames[j], "char"))
	{
		appendPQExpBuffer(q, "%s",
4254
						  fmtId(tblinfo[i].typnames[j], true));
4255 4256 4257 4258
	}
	else
	{
		appendPQExpBuffer(q, "%s",
4259
						  fmtId(tblinfo[i].typnames[j], false));
4260 4261
	}
}
4262

4263 4264
/*
 * dumpTables:
4265
 *	  write out to fout all the user-define tables
4266
 */
4267

4268
void
B
Bruce Momjian 已提交
4269
dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
4270
		   IndInfo *indinfo, int numIndexes,
4271 4272
		   InhInfo *inhinfo, int numInherits,
		   TypeInfo *tinfo, int numTypes, const char *tablename,
B
Bruce Momjian 已提交
4273 4274
		   const bool aclsSkip, const bool oids,
		   const bool schemaOnly, const bool dataOnly)
4275
{
4276 4277
	int			i,
				j,
B
Bruce Momjian 已提交
4278
				k;
4279
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
4280
	PQExpBuffer delq = createPQExpBuffer();
4281
	char	   *serialSeq = NULL;		/* implicit sequence name created
B
Bruce Momjian 已提交
4282 4283 4284 4285
										 * by SERIAL datatype */
	const char *serialSeqSuffix = "_id_seq";	/* suffix for implicit
												 * SERIAL sequences */
	char	  **parentRels;		/* list of names of parent relations */
4286
	int			numParents;
B
Bruce Momjian 已提交
4287
	int			actual_atts;	/* number of attrs in this CREATE statment */
4288
	char	   *reltypename;
4289
	char	   *objoid;
4290
	const char *((*commentDeps)[]);
4291

V
Vadim B. Mikheev 已提交
4292
	/* First - dump SEQUENCEs */
4293
	if (tablename && strlen(tablename) > 0)
B
Bruce Momjian 已提交
4294
	{
4295 4296
		/* XXX this code only works for serial columns named "id" */
		/* We really need dependency analysis! */
B
Bruce Momjian 已提交
4297 4298 4299 4300
		serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
		strcpy(serialSeq, tablename);
		strcat(serialSeq, serialSeqSuffix);
	}
V
Vadim B. Mikheev 已提交
4301 4302 4303 4304
	for (i = 0; i < numTables; i++)
	{
		if (!(tblinfo[i].sequence))
			continue;
B
Bruce Momjian 已提交
4305
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
B
Bruce Momjian 已提交
4306
			|| (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
V
Vadim B. Mikheev 已提交
4307
		{
B
Bruce Momjian 已提交
4308
			/* becomeUser(fout, tblinfo[i].usename); */
4309
			dumpSequence(fout, tblinfo[i], schemaOnly, dataOnly);
4310
			if (!aclsSkip)
B
Bruce Momjian 已提交
4311
				dumpACL(fout, tblinfo[i]);
V
Vadim B. Mikheev 已提交
4312 4313
		}
	}
4314
	if (serialSeq)
B
Bruce Momjian 已提交
4315
		free(serialSeq);
4316

4317 4318
	for (i = 0; i < numTables; i++)
	{
4319
		if (tblinfo[i].sequence)	/* already dumped */
V
Vadim B. Mikheev 已提交
4320
			continue;
4321

4322
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename)) || (strlen(tablename) == 0))
4323 4324
		{

4325 4326
			resetPQExpBuffer(delq);
			resetPQExpBuffer(q);
4327

4328 4329 4330 4331
			/* Use the view definition if there is one */
			if (tblinfo[i].viewdef != NULL)
			{
				reltypename = "VIEW";
4332
				objoid = tblinfo[i].viewoid;
4333
				appendPQExpBuffer(delq, "DROP VIEW %s;\n", fmtId(tblinfo[i].relname, force_quotes));
4334
				appendPQExpBuffer(q, "CREATE VIEW %s as %s\n", fmtId(tblinfo[i].relname, force_quotes), tblinfo[i].viewdef);
4335
				commentDeps = malloc(sizeof(char *) * 2);
4336
				(*commentDeps)[0] = strdup(objoid);
4337
				(*commentDeps)[1] = NULL;		/* end of list */
4338 4339
			}
			else
4340
			{
4341
				reltypename = "TABLE";
4342
				objoid = tblinfo[i].oid;
4343
				commentDeps = NULL;
4344 4345
				parentRels = tblinfo[i].parentRels;
				numParents = tblinfo[i].numParents;
B
Bruce Momjian 已提交
4346

4347
				appendPQExpBuffer(delq, "DROP TABLE %s;\n", fmtId(tblinfo[i].relname, force_quotes));
B
Bruce Momjian 已提交
4348

4349 4350 4351 4352 4353 4354
				appendPQExpBuffer(q, "CREATE TABLE %s (\n\t", fmtId(tblinfo[i].relname, force_quotes));
				actual_atts = 0;
				for (j = 0; j < tblinfo[i].numatts; j++)
				{
					/* Is this one of the table's own attrs ? */
					if (tblinfo[i].inhAttrs[j] == 0)
4355
					{
4356 4357 4358 4359 4360
						/* Format properly if not first attr */
						if (actual_atts > 0)
							appendPQExpBuffer(q, ",\n\t");

						/* Attr name & type */
4361 4362 4363 4364
						appendPQExpBuffer(q, "%s ", fmtId(tblinfo[i].attnames[j], force_quotes));

						if (g_fout->remoteVersion >= 70100)
							appendPQExpBuffer(q, "%s", tblinfo[i].atttypedefns[j]);
4365
						else
4366
							_dumpTableAttr70(fout, tblinfo, i, j, q);
4367 4368

						/* Default value */
4369
						if (tblinfo[i].adef_expr[j] != NULL && tblinfo[i].inhAttrDef[j] == 0)
4370
							appendPQExpBuffer(q, " DEFAULT %s",
B
Bruce Momjian 已提交
4371
											  tblinfo[i].adef_expr[j]);
4372 4373

						/* Not Null constraint */
4374
						if (tblinfo[i].notnull[j] && tblinfo[i].inhNotNull[j] == 0)
4375 4376 4377 4378
							appendPQExpBuffer(q, " NOT NULL");

						actual_atts++;
					}
4379
				}
B
Hi all  
Bruce Momjian 已提交
4380

4381 4382


4383
				/* Put the CONSTRAINTS inside the table def */
4384 4385 4386 4387 4388 4389
				for (k = 0; k < tblinfo[i].ncheck; k++)
				{
					if (actual_atts + k > 0)
						appendPQExpBuffer(q, ",\n\t");

					appendPQExpBuffer(q, "%s",
B
Bruce Momjian 已提交
4390
									  tblinfo[i].check_expr[k]);
4391
				}
4392

4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422
				/* Primary Key */
				if (tblinfo[i].pkIndexOid != NULL)
				{
					PQExpBuffer consDef;

					/* Find the corresponding index */
					for (k = 0; k < numIndexes; k++)
					{
						if (strcmp(indinfo[k].indexreloid,
								   tblinfo[i].pkIndexOid) == 0)
							break;
					}

					if (k >= numIndexes)
					{
						write_msg(NULL, "dumpTables(): failed sanity check, could not find index (%s) for primary key constraint\n",
								  tblinfo[i].pkIndexOid);
						exit_nicely();
					}

					consDef = getPKconstraint(&tblinfo[i], &indinfo[k]);

					if ((actual_atts + tblinfo[i].ncheck) > 0)
						appendPQExpBuffer(q, ",\n\t");

					appendPQExpBuffer(q, "%s", consDef->data);

					destroyPQExpBuffer(consDef);
				}

4423 4424 4425 4426 4427 4428 4429 4430 4431
				/*
				 * Primary Key: In versions of PostgreSQL prior to 7.2, we
				 * needed to include the primary key in the table definition.
				 * However, this is not ideal because it creates an index
				 * on the table, which makes COPY slower. As of release 7.2,
				 * we can add primary keys to a table after is has been created,
				 * using ALTER TABLE ; see dumpIndexes() for more information.
				 * Therefore, we ignore primary keys in this function.
				 */
4432

4433
				appendPQExpBuffer(q, "\n)");
4434

4435
				if (numParents > 0)
B
Hi all  
Bruce Momjian 已提交
4436
				{
4437
					appendPQExpBuffer(q, "\nINHERITS (");
4438 4439 4440
					for (k = 0; k < numParents; k++)
					{
						appendPQExpBuffer(q, "%s%s",
B
Bruce Momjian 已提交
4441 4442
										  (k > 0) ? ", " : "",
									 fmtId(parentRels[k], force_quotes));
4443 4444
					}
					appendPQExpBuffer(q, ")");
B
Hi all  
Bruce Momjian 已提交
4445 4446
				}

4447 4448 4449
				if (!tblinfo[i].hasoids)
					appendPQExpBuffer(q, " WITHOUT OIDS");

4450 4451
				appendPQExpBuffer(q, ";\n");
			}
B
Bruce Momjian 已提交
4452

B
Bruce Momjian 已提交
4453 4454
			if (!dataOnly)
			{
4455

4456
				ArchiveEntry(fout, objoid, tblinfo[i].relname,
B
Bruce Momjian 已提交
4457 4458
							 reltypename, NULL, q->data, delq->data, "", tblinfo[i].usename,
							 NULL, NULL);
B
Bruce Momjian 已提交
4459

4460 4461 4462 4463
				if (!aclsSkip)
					dumpACL(fout, tblinfo[i]);

			}
4464

4465
			/* Dump Field Comments */
B
Bruce,  
Bruce Momjian 已提交
4466

4467 4468
			for (j = 0; j < tblinfo[i].numatts; j++)
			{
B
Bruce,  
Bruce Momjian 已提交
4469 4470 4471 4472
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "COLUMN %s", fmtId(tblinfo[i].relname, force_quotes));
				appendPQExpBuffer(q, ".");
				appendPQExpBuffer(q, "%s", fmtId(tblinfo[i].attnames[j], force_quotes));
4473
				dumpComment(fout, q->data, tblinfo[i].oid,
4474
							"pg_class", j + 1, commentDeps);
B
Bruce,  
Bruce Momjian 已提交
4475
			}
4476

B
Bruce,  
Bruce Momjian 已提交
4477
			/* Dump Table Comments */
4478

B
Bruce,  
Bruce Momjian 已提交
4479
			resetPQExpBuffer(q);
4480
			appendPQExpBuffer(q, "%s %s", reltypename, fmtId(tblinfo[i].relname, force_quotes));
4481 4482
			dumpComment(fout, q->data, tblinfo[i].oid,
						"pg_class", 0, commentDeps);
4483

4484 4485
		}
	}
4486 4487 4488

	destroyPQExpBuffer(q);
	destroyPQExpBuffer(delq);
4489 4490
}

B
Bruce Momjian 已提交
4491 4492
static PQExpBuffer
getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo)
4493
{
B
Bruce Momjian 已提交
4494 4495
	PQExpBuffer pkBuf = createPQExpBuffer();
	int			k;
4496 4497

	appendPQExpBuffer(pkBuf, "Constraint %s Primary Key (",
B
Bruce Momjian 已提交
4498
					  tblInfo->primary_key_name);
4499 4500 4501

	for (k = 0; k < INDEX_MAX_KEYS; k++)
	{
4502 4503
		int			indkey;
		const char *attname;
4504 4505 4506 4507

		indkey = atoi(indInfo->indkey[k]);
		if (indkey == InvalidAttrNumber)
			break;
4508
		attname = getAttrName(indkey, tblInfo);
4509 4510

		appendPQExpBuffer(pkBuf, "%s%s",
B
Bruce Momjian 已提交
4511 4512
						  (k == 0) ? "" : ", ",
						  fmtId(attname, force_quotes));
4513 4514 4515 4516 4517 4518 4519
	}

	appendPQExpBuffer(pkBuf, ")");

	return pkBuf;
}

4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530
/*
 * getAttrName: extract the correct name for an attribute
 *
 * The array tblInfo->attnames[] only provides names of user attributes;
 * if a system attribute number is supplied, we have to fake it.
 * We also do a little bit of bounds checking for safety's sake.
 */
static const char *
getAttrName(int attrnum, TableInfo *tblInfo)
{
	if (attrnum > 0 && attrnum <= tblInfo->numatts)
4531
		return tblInfo->attnames[attrnum - 1];
4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548
	switch (attrnum)
	{
		case SelfItemPointerAttributeNumber:
			return "ctid";
		case ObjectIdAttributeNumber:
			return "oid";
		case MinTransactionIdAttributeNumber:
			return "xmin";
		case MinCommandIdAttributeNumber:
			return "cmin";
		case MaxTransactionIdAttributeNumber:
			return "xmax";
		case MaxCommandIdAttributeNumber:
			return "cmax";
		case TableOidAttributeNumber:
			return "tableoid";
	}
4549
	write_msg(NULL, "getAttrName(): invalid column number %d for table %s\n",
4550
			  attrnum, tblInfo->relname);
4551
	exit_nicely();
4552 4553 4554
	return NULL;				/* keep compiler quiet */
}

4555
/*
4556
 * dumpIndexes:
4557
 *	  write out to fout all the user-defined indexes
4558
 */
4559
void
4560
dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes,
4561
			TableInfo *tblinfo, int numTables, const char *tablename)
4562
{
4563
	int			i;
4564
	int			tableInd;
4565 4566 4567
	PQExpBuffer q = createPQExpBuffer();
	PQExpBuffer delq = createPQExpBuffer();
	PQExpBuffer id1 = createPQExpBuffer();
4568

4569
	for (i = 0; i < numIndexes; i++)
4570
	{
4571 4572 4573 4574
		if (tablename && tablename[0] &&
			(strcmp(indinfo[i].indrelname, tablename) != 0))
			continue;

4575
		tableInd = findTableByName(tblinfo, numTables,
4576 4577 4578
								   indinfo[i].indrelname);
		if (tableInd < 0)
		{
4579
			write_msg(NULL, "dumpIndexes(): failed sanity check, table %s was not found\n",
4580
					  indinfo[i].indrelname);
4581
			exit_nicely();
4582
		}
4583

4584 4585 4586
		/* Handle PK indexes */
		if (strcmp(indinfo[i].indisprimary, "t") == 0)
		{
4587 4588
			PQExpBuffer consDef = getPKconstraint(&tblinfo[tableInd], &indinfo[i]);

4589
			resetPQExpBuffer(q);
4590

4591
			appendPQExpBuffer(q, "Alter Table %s Add %s;",
4592
							  fmtId(tblinfo[tableInd].relname, force_quotes),
4593 4594
							  consDef->data);

4595
			ArchiveEntry(fout, indinfo[i].indexreloid, tblinfo[tableInd].primary_key_name,
4596
						 "CONSTRAINT", NULL, q->data, "",
4597 4598 4599
						 "", tblinfo[tableInd].usename, NULL, NULL);

			destroyPQExpBuffer(consDef);
B
Bruce Momjian 已提交
4600 4601 4602 4603 4604

			/*
			 * Don't need to do anything else for this system-generated
			 * index
			 */
4605 4606 4607
			continue;
		}

4608 4609
		resetPQExpBuffer(id1);
		appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
4610

4611 4612
		resetPQExpBuffer(q);
		appendPQExpBuffer(q, "%s;\n", indinfo[i].indexdef);
B
Bruce,  
Bruce Momjian 已提交
4613

4614 4615
		resetPQExpBuffer(delq);
		appendPQExpBuffer(delq, "DROP INDEX %s;\n", id1->data);
B
Bruce Momjian 已提交
4616

4617
		/*
4618 4619 4620
		 * We make the index belong to the owner of its table, which is
		 * not necessarily right but should answer 99% of the time. Would
		 * have to add owner name to IndInfo to do it right.
4621 4622 4623 4624
		 */
		ArchiveEntry(fout, indinfo[i].indexreloid, id1->data,
					 "INDEX", NULL, q->data, delq->data,
					 "", tblinfo[tableInd].usename, NULL, NULL);
4625

4626 4627 4628 4629 4630
		/* Dump Index Comments */
		resetPQExpBuffer(q);
		appendPQExpBuffer(q, "INDEX %s", id1->data);
		dumpComment(fout, q->data, indinfo[i].indexreloid,
					"pg_class", 0, NULL);
4631
	}
4632

4633 4634 4635
	destroyPQExpBuffer(q);
	destroyPQExpBuffer(delq);
	destroyPQExpBuffer(id1);
4636
}
4637

4638
/*
B
Bruce Momjian 已提交
4639
 * dumpTuples
4640 4641 4642 4643 4644
 *	  prints out the tuples in ASCII representation. The output is a valid
 *	  input to COPY FROM stdin.
 *
 *	  We only need to do this for POSTGRES 4.2 databases since the
 *	  COPY TO statment doesn't escape newlines properly. It's been fixed
4645
 *	  in PostgreSQL.
4646 4647 4648 4649
 *
 * the attrmap passed in tells how to map the attributes copied in to the
 * attributes copied out
 */
4650
#ifdef NOT_USED
4651
void
4652
dumpTuples(PGresult *res, FILE *fout, int *attrmap)
4653
{
4654 4655 4656 4657
	int			j,
				k;
	int			m,
				n;
B
Bruce Momjian 已提交
4658
	char	  **outVals = NULL; /* values to copy out */
4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676

	n = PQntuples(res);
	m = PQnfields(res);

	if (m > 0)
	{
		/*
		 * Print out the tuples but only print tuples with at least 1
		 * field.
		 */
		outVals = (char **) malloc(m * sizeof(char *));

		for (j = 0; j < n; j++)
		{
			for (k = 0; k < m; k++)
				outVals[attrmap[k]] = PQgetvalue(res, j, k);
			for (k = 0; k < m; k++)
			{
4677
				char	   *pval = outVals[k];
4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697

				if (k != 0)
					fputc('\t', fout);	/* delimiter for attribute */

				if (pval)
				{
					while (*pval != '\0')
					{
						/* escape tabs, newlines and backslashes */
						if (*pval == '\t' || *pval == '\n' || *pval == '\\')
							fputc('\\', fout);
						fputc(*pval, fout);
						pval++;
					}
				}
			}
			fputc('\n', fout);	/* delimiter for a tuple */
		}
		free(outVals);
	}
4698
}
4699
#endif
4700

4701 4702 4703 4704
/*
 * setMaxOid -
 * find the maximum oid and generate a COPY statement to set it
*/
4705

4706
static void
B
Bruce Momjian 已提交
4707
setMaxOid(Archive *fout)
4708
{
B
Bruce Momjian 已提交
4709 4710
	PGresult   *res;
	Oid			max_oid;
B
Bruce Momjian 已提交
4711
	char		sql[1024];
4712

4713
	res = PQexec(g_conn, "CREATE TEMPORARY TABLE pgdump_oid (dummy int4)");
4714 4715 4716
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4717
		write_msg(NULL, "could not create pgdump_oid table: %s", PQerrorMessage(g_conn));
4718
		exit_nicely();
4719 4720
	}
	PQclear(res);
4721
	res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
4722 4723 4724
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4725
		write_msg(NULL, "could not insert into pgdump_oid table: %s", PQerrorMessage(g_conn));
4726
		exit_nicely();
4727
	}
4728
	max_oid = PQoidValue(res);
4729 4730
	if (max_oid == 0)
	{
4731
		write_msg(NULL, "inserted invalid oid\n");
4732
		exit_nicely();
4733 4734
	}
	PQclear(res);
4735
	res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
4736 4737 4738
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4739
		write_msg(NULL, "could not drop pgdump_oid table: %s", PQerrorMessage(g_conn));
4740
		exit_nicely();
4741 4742 4743
	}
	PQclear(res);
	if (g_verbose)
4744
		write_msg(NULL, "maximum system oid is %u\n", max_oid);
4745 4746 4747
	snprintf(sql, 1024,
			 "CREATE TEMPORARY TABLE pgdump_oid (dummy int4);\n"
			 "COPY pgdump_oid WITH OIDS FROM stdin;\n"
4748
			 "%u\t0\n"
4749 4750 4751
			 "\\.\n"
			 "DROP TABLE pgdump_oid;\n",
			 max_oid);
B
Bruce Momjian 已提交
4752

4753
	ArchiveEntry(fout, "0", "Max OID", "<Init>", NULL, sql, "", "", "", NULL, NULL);
4754
}
4755 4756 4757

/*
 * findLastBuiltInOid -
4758
 * find the last built in oid
4759 4760
 * we do this by retrieving datlastsysoid from the pg_database entry for this database,
 */
4761

4762
static Oid
4763
findLastBuiltinOid_V71(const char *dbname)
4764
{
B
Bruce Momjian 已提交
4765
	PGresult   *res;
4766
	int			ntups;
4767
	Oid			last_oid;
4768 4769 4770
	PQExpBuffer query = createPQExpBuffer();

	resetPQExpBuffer(query);
4771
	appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
4772
	formatStringLiteral(query, dbname, CONV_ALL);
4773

4774
	res = PQexec(g_conn, query->data);
4775 4776 4777
	if (res == NULL ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
4778
		write_msg(NULL, "error in finding the last system oid: %s", PQerrorMessage(g_conn));
4779
		exit_nicely();
4780 4781
	}
	ntups = PQntuples(res);
4782
	if (ntups < 1)
4783
	{
4784
		write_msg(NULL, "missing pg_database entry for this database\n");
4785
		exit_nicely();
4786 4787 4788
	}
	if (ntups > 1)
	{
4789
		write_msg(NULL, "found more than one pg_database entry for this database\n");
4790
		exit_nicely();
4791
	}
4792
	last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
4793
	PQclear(res);
4794
	destroyPQExpBuffer(query);
4795
	return last_oid;
4796 4797
}

4798 4799 4800 4801 4802 4803 4804
/*
 * findLastBuiltInOid -
 * find the last built in oid
 * we do this by looking up the oid of 'template1' in pg_database,
 * this is probably not foolproof but comes close
*/

4805
static Oid
4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816
findLastBuiltinOid_V70(void)
{
	PGresult   *res;
	int			ntups;
	int			last_oid;

	res = PQexec(g_conn,
			  "SELECT oid from pg_database where datname = 'template1'");
	if (res == NULL ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
4817
		write_msg(NULL, "error in finding the template1 database: %s", PQerrorMessage(g_conn));
4818
		exit_nicely();
4819 4820 4821 4822
	}
	ntups = PQntuples(res);
	if (ntups < 1)
	{
4823
		write_msg(NULL, "could not find template1 database entry in the pg_database table\n");
4824
		exit_nicely();
4825 4826 4827
	}
	if (ntups > 1)
	{
4828
		write_msg(NULL, "found more than one template1 database entry in the pg_database table\n");
4829
		exit_nicely();
4830 4831 4832 4833 4834
	}
	last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
	PQclear(res);
	return last_oid;
}
4835

4836
static void
4837
dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool dataOnly)
4838
{
4839
	PGresult   *res;
4840 4841 4842 4843 4844 4845
	char	   *last,
			   *incby,
			   *maxv,
			   *minv,
			   *cache;
	bool		cycled,
B
Bruce Momjian 已提交
4846
				called;
4847
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
4848
	PQExpBuffer delqry = createPQExpBuffer();
4849

B
Hi, all  
Bruce Momjian 已提交
4850
	appendPQExpBuffer(query,
4851
			"SELECT sequence_name, last_value, increment_by, max_value, "
4852 4853
				  "min_value, cache_value, is_cycled, is_called from %s",
					  fmtId(tbinfo.relname, force_quotes));
4854

B
Hi, all  
Bruce Momjian 已提交
4855
	res = PQexec(g_conn, query->data);
4856 4857
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
4858
		write_msg(NULL, "query to get data of sequence \"%s\" failed: %s", tbinfo.relname, PQerrorMessage(g_conn));
4859
		exit_nicely();
4860 4861 4862 4863
	}

	if (PQntuples(res) != 1)
	{
4864
		write_msg(NULL, "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
4865
				  tbinfo.relname, PQntuples(res));
4866
		exit_nicely();
4867 4868
	}

4869 4870
	/* Disable this check: it fails if sequence has been renamed */
#ifdef NOT_USED
4871 4872
	if (strcmp(PQgetvalue(res, 0, 0), tbinfo.relname) != 0)
	{
4873
		write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
4874
				  tbinfo.relname, PQgetvalue(res, 0, 0));
4875
		exit_nicely();
4876
	}
4877
#endif
4878

4879 4880 4881 4882 4883 4884 4885
	last = PQgetvalue(res, 0, 1);
	incby = PQgetvalue(res, 0, 2);
	maxv = PQgetvalue(res, 0, 3);
	minv = PQgetvalue(res, 0, 4);
	cache = PQgetvalue(res, 0, 5);
	cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
	called = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
4886

4887
	/*
B
Bruce Momjian 已提交
4888 4889
	 * The logic we use for restoring sequences is as follows: -   Add a
	 * basic CREATE SEQUENCE statement (use last_val for start if called
4890
	 * is false, else use min_val for start_val).
4891
	 *
4892 4893
	 * Add a 'SETVAL(seq, last_val, iscalled)' at restore-time iff we load
	 * data
4894
	 */
4895

4896 4897 4898
	if (!dataOnly)
	{
		resetPQExpBuffer(delqry);
4899 4900
		appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
						  fmtId(tbinfo.relname, force_quotes));
4901

4902 4903
		resetPQExpBuffer(query);
		appendPQExpBuffer(query,
4904 4905
						  "CREATE SEQUENCE %s start %s increment %s "
						  "maxvalue %s minvalue %s cache %s%s;\n",
B
Bruce Momjian 已提交
4906
						  fmtId(tbinfo.relname, force_quotes),
4907
						  (called ? minv : last),
4908
						  incby, maxv, minv, cache,
4909
						  (cycled ? " cycle" : ""));
4910

P
Philip Warner 已提交
4911
		ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "SEQUENCE", NULL,
4912 4913
					 query->data, delqry->data, "", tbinfo.usename,
					 NULL, NULL);
4914
	}
4915

4916 4917 4918 4919 4920
	if (!schemaOnly)
	{
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "SELECT setval (");
		formatStringLiteral(query, fmtId(tbinfo.relname, force_quotes), CONV_ALL);
4921 4922
		appendPQExpBuffer(query, ", %s, %s);\n",
						  last, (called ? "true" : "false"));
4923

P
Philip Warner 已提交
4924
		ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "SEQUENCE SET", NULL,
4925 4926
					 query->data, "" /* Del */ , "", tbinfo.usename,
					 NULL, NULL);
4927
	}
B
Bruce,  
Bruce Momjian 已提交
4928

4929 4930 4931
	if (!dataOnly)
	{
		/* Dump Sequence Comments */
B
Bruce,  
Bruce Momjian 已提交
4932

4933 4934
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo.relname, force_quotes));
4935 4936
		dumpComment(fout, query->data, tbinfo.oid,
					"pg_class", 0, NULL);
4937
	}
4938

4939 4940
	PQclear(res);

4941 4942
	destroyPQExpBuffer(query);
	destroyPQExpBuffer(delqry);
4943
}
V
Vadim B. Mikheev 已提交
4944 4945


4946
static void
B
Bruce Momjian 已提交
4947
dumpTriggers(Archive *fout, const char *tablename,
4948
			 TableInfo *tblinfo, int numTables)
V
Vadim B. Mikheev 已提交
4949
{
4950 4951 4952
	int			i,
				j;

V
Vadim B. Mikheev 已提交
4953
	if (g_verbose)
4954
		write_msg(NULL, "dumping out triggers\n");
4955

V
Vadim B. Mikheev 已提交
4956 4957
	for (i = 0; i < numTables; i++)
	{
B
Bruce Momjian 已提交
4958
		if (tablename && (strcmp(tblinfo[i].relname, tablename) != 0) && (strlen(tablename) > 0))
V
Vadim B. Mikheev 已提交
4959
			continue;
4960

V
Vadim B. Mikheev 已提交
4961 4962
		for (j = 0; j < tblinfo[i].ntrig; j++)
		{
B
Bruce Momjian 已提交
4963
			ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
B
Bruce Momjian 已提交
4964 4965
				   "TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "", "",
						 tblinfo[i].usename, NULL, NULL);
4966 4967
			dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid,
						"pg_trigger", 0, NULL);
V
Vadim B. Mikheev 已提交
4968 4969 4970
		}
	}
}
4971 4972


4973
static void
B
Bruce Momjian 已提交
4974
dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
4975
		  TableInfo *tblinfo, int numTables)
4976
{
B
Bruce Momjian 已提交
4977 4978 4979 4980
	PGresult   *res;
	int			nrules;
	int			i,
				t;
4981
	PQExpBuffer query = createPQExpBuffer();
4982

B
Bruce Momjian 已提交
4983
	int			i_definition;
4984
	int			i_oid;
4985
	int			i_owner;
4986
	int			i_rulename;
4987 4988

	if (g_verbose)
4989
		write_msg(NULL, "dumping out rules\n");
4990 4991 4992 4993 4994 4995

	/*
	 * For each table we dump
	 */
	for (t = 0; t < numTables; t++)
	{
B
Bruce Momjian 已提交
4996
		if (tablename && (strcmp(tblinfo[t].relname, tablename) != 0) && (strlen(tablename) > 0))
4997 4998 4999
			continue;

		/*
B
Bruce Momjian 已提交
5000 5001
		 * Get all rules defined for this table We include pg_rules in the
		 * cross since it filters out all view rules (pjw 15-Sep-2000).
5002 5003
		 *
		 * XXXX: Use LOJ here
5004
		 */
B
Hi, all  
Bruce Momjian 已提交
5005
		resetPQExpBuffer(query);
5006
		appendPQExpBuffer(query, "SELECT definition,"
5007
						  "   (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
5008 5009
						  "   pg_rewrite.oid, pg_rewrite.rulename "
						  "FROM pg_rewrite, pg_class, pg_rules "
5010
						  "WHERE pg_class.relname = ");
5011
		formatStringLiteral(query, tblinfo[t].relname, CONV_ALL);
5012
		appendPQExpBuffer(query,
5013 5014
						  "    AND pg_rewrite.ev_class = pg_class.oid "
						  "    AND pg_rules.tablename = pg_class.relname "
B
Bruce Momjian 已提交
5015
					   "    AND pg_rules.rulename = pg_rewrite.rulename "
5016
						  "ORDER BY pg_rewrite.oid");
B
Hi, all  
Bruce Momjian 已提交
5017
		res = PQexec(g_conn, query->data);
5018 5019 5020
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
5021
			write_msg(NULL, "query to get rules associated with table \"%s\" failed: %s",
5022
					  tblinfo[t].relname, PQerrorMessage(g_conn));
5023
			exit_nicely();
5024 5025 5026 5027
		}

		nrules = PQntuples(res);
		i_definition = PQfnumber(res, "definition");
5028
		i_owner = PQfnumber(res, "viewowner");
B
Bruce,  
Bruce Momjian 已提交
5029 5030
		i_oid = PQfnumber(res, "oid");
		i_rulename = PQfnumber(res, "rulename");
5031 5032 5033 5034

		/*
		 * Dump them out
		 */
B
Bruce,  
Bruce Momjian 已提交
5035

5036 5037
		for (i = 0; i < nrules; i++)
		{
B
Bruce Momjian 已提交
5038
			ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
B
Bruce Momjian 已提交
5039 5040
						 "RULE", NULL, PQgetvalue(res, i, i_definition),
						 "", "", PQgetvalue(res, i, i_owner), NULL, NULL);
5041

B
Bruce,  
Bruce Momjian 已提交
5042 5043 5044 5045
			/* Dump rule comments */

			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "RULE %s", fmtId(PQgetvalue(res, i, i_rulename), force_quotes));
5046 5047
			dumpComment(fout, query->data, PQgetvalue(res, i, i_oid),
						"pg_rewrite", 0, NULL);
5048

B
Bruce,  
Bruce Momjian 已提交
5049 5050
		}

5051 5052
		PQclear(res);
	}
5053 5054

	destroyPQExpBuffer(query);
5055
}