pg_dump.c 116.9 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * pg_dump.c
4
 *	  pg_dump is an utility for dumping out a postgres database
5 6
 * into a script file.
 *
7 8 9 10 11 12 13 14 15 16
 *	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
 *		  indices
 *		  aggregates
 *		  operators
 *		  ACL - grant/revoke
17
 *
18
 * the output script is SQL that is understood by PostgreSQL
19
 *
B
Add:  
Bruce Momjian 已提交
20 21
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
22 23 24
 *
 *
 * IDENTIFICATION
25
 *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.187 2001/01/12 15:41:29 pjw Exp $
26
 *
27
 * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
28
 *
29 30 31 32
 *	 Applied 'insert string' patch from "Marc G. Fournier" <scrappy@ki.net>
 *	 Added '-t table' option
 *	 Added '-a' option
 *	 Added '-da' option
33
 *
34 35
 * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
 *
36 37 38
 *	 - Fixed dumpTable output to output lengths for char and varchar types!
 *	 - Added single. quote to twin single quote expansion for 'insert' string
 *	   mode.
39
 *
40 41
 * Modifications - 7/26/96 - asussman@vidya.com
 *
42
 *	 - Fixed ouput lengths for char and varchar type where the length is variable (-1)
43
 *
44 45
 * Modifications - 6/1/97 - igor@sba.miami.edu
 * - Added functions to free allocated memory used for retrieving
46 47
 *	 indices,tables,inheritance,types,functions and aggregates.
 *	 No more leaks reported by Purify.
48 49 50
 *
 *
 * Modifications - 1/26/98 - pjlobo@euitt.upm.es
51
 *		 - Added support for password authentication
B
Bruce Momjian 已提交
52 53 54 55 56 57 58 59 60 61 62 63
 *
 * Modifications - 28-Jun-2000 - Philip Warner pjw@rhyme.com.au
 *		 - Used custom IO routines to allow for more
 *		   output formats and simple rearrangement of order.
 *		 - Discouraged operations more appropriate to the 'restore'
 *		   operation. (eg. -c "clear schema" - now always dumps
 *		   commands, but pg_restore can be told not to output them). 
 *		 - Added RI warnings to the 'as insert strings' output mode
 *		 - Added a small number of comments
 *		 - Added a -Z option for compression level on compressed formats
 *		 - Restored '-f' in usage output
 *
64 65 66 67 68
 *
 * Modifications - 17-Jul-2000 - Philip Warner pjw@rhyme.com.au
 *		 - Support for BLOB output.
 *		 - Sort archive by OID, put some items at end (out of OID order)
 *
69 70 71 72 73 74 75 76 77 78 79 80 81
 * Modifications - 28-Jul-2000 - pjw@rhyme.com.au (1.45)
 *
 * 		Added --create, --no-owner, --superuser, --no-reconnect (pg_dump & pg_restore)
 *		Added code to dump 'Create Schema' statement (pg_dump)
 *		Don't bother to disable/enable triggers if we don't have a superuser (pg_restore)
 *		Cleaned up code for reconnecting to database.
 *		Force a reconnect as superuser before enabling/disabling triggers.
 *
 * Modifications - 31-Jul-2000 - pjw@rhyme.com.au (1.46, 1.47)
 *		Added & Removed --throttle (pg_dump)
 *		Fixed minor bug in language dumping code: expbuffres were not being reset.
 *		Fixed version number initialization in _allocAH (pg_backup_archiver.c)
 *
82 83 84 85 86 87 88 89
 * Modifications - 14-Sep-2000 - pjw@rhyme.com.au 
 *		Use symbols for tests on relkind (ie. use RELKIND_VIEW, not 'v')
 * 		Support for relkind = RELKIND_VIEW.
 * 		Fix bug in support for -b option (== --blobs).
 *		Dump views as views (using 'create view').
 *		Remove 'isViewRule' since we check the relkind when getting tables.
 *		Now uses temp table 'pgdump_oid' rather than 'pg_dump_oid' (errors otherwise).
 *
90 91 92 93 94 95 96 97 98
 * Modifications - 02-Oct-2000 - pjw@rhyme.com.au
 *
 *	  - Be more paranoid when getting views: call get_viewdef in separate statement
 *		so we can be more informative in error messages.
 *	  - Support for 'isstrict' procedure attribute. 
 *	  - Disable --blobs and --table since (a) it's a pain to get ONLY the blobs for the 
 *		table with the currently implementation, and (b) it's not clear how to restore
 *		a partial BLOB backup (given the current OID-based BLOB implementation).
 *
99 100 101 102 103
 * Modifications - 04-Jan-2000 - pjw@rhyme.com.au
 *
 *	  - Check ntuples == 1 for various SELECT statements.
 *	  - Fix handling of --tables=* (multiple tables never worked properly, AFAICT)
 *
104
 *-------------------------------------------------------------------------
105 106
 */

107
#include <unistd.h>				/* for getopt() */
108
#include <ctype.h>
109

110 111
#include "pg_backup.h"

112
#include "postgres.h"
113 114 115 116 117 118 119 120 121

#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif

#include "access/attnum.h"
122
#include "access/htup.h"
123
#include "catalog/pg_index.h"
124
#include "catalog/pg_language.h"
V
Vadim B. Mikheev 已提交
125
#include "catalog/pg_trigger.h"
126
#include "catalog/pg_type.h"
127

128
#include "libpq-fe.h"
129
#include <libpq/libpq-fs.h>
130
#ifndef HAVE_STRDUP
131 132
#include "strdup.h"
#endif
133 134

#include "pg_dump.h"
B
Bruce Momjian 已提交
135
#include "pg_backup.h"
136

137 138
#define atooid(x)  ((Oid) strtoul((x), NULL, 10))

B
Bruce Momjian 已提交
139 140 141 142
static void dumpComment(Archive *outfile, const char *target, const char *oid);
static void dumpSequence(Archive *fout, TableInfo tbinfo);
static void dumpACL(Archive *fout, TableInfo tbinfo);
static void dumpTriggers(Archive *fout, const char *tablename,
143
			 TableInfo *tblinfo, int numTables);
B
Bruce Momjian 已提交
144
static void dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
145
		  TableInfo *tblinfo, int numTables);
146
static void formatStringLiteral(PQExpBuffer buf, const char *str);
147
static void clearTableInfo(TableInfo *, int);
B
Bruce Momjian 已提交
148
static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
149
			TypeInfo *tinfo, int numTypes);
150
static Oid	findLastBuiltinOid(const char*);
B
Bruce Momjian 已提交
151
static void setMaxOid(Archive *fout);
152

153 154
static void AddAcl(char *aclbuf, const char *keyword);
static char *GetPrivileges(const char *s);
V
Vadim B. Mikheev 已提交
155

156
static int dumpBlobs(Archive *AH, char*, void*);
157
static int dumpDatabase(Archive *AH);
158
static PQExpBuffer getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo);
159

B
Bruce Momjian 已提交
160
extern char *optarg;
161
extern int	optind,
B
Bruce Momjian 已提交
162
			opterr;
163 164

/* global decls */
165
bool		g_verbose;			/* User wants verbose narration of our
B
Bruce Momjian 已提交
166
								 * activities. */
167
Oid			g_last_builtin_oid; /* value of the last builtin oid */
B
Bruce Momjian 已提交
168
Archive	   *g_fout;				/* the script file */
B
Bruce Momjian 已提交
169 170 171
PGconn	   *g_conn;				/* the database connection */

bool		force_quotes;		/* User wants to suppress double-quotes */
172 173 174 175
bool		dumpData;			/* dump data using proper insert strings */
bool		attrNames;			/* put attr names into insert strings */
bool		schemaOnly;
bool		dataOnly;
176
bool		aclsSkip;
177

B
Bruce Momjian 已提交
178
char		g_opaque_type[10];	/* name for the opaque type */
179 180

/* placeholders for the delimiters for comments */
181 182
char		g_comment_start[10];
char		g_comment_end[10];
183 184


B
Bruce Momjian 已提交
185 186 187 188 189 190
typedef struct _dumpContext {
	TableInfo	*tblinfo;
	int		tblidx;
	bool		oids;
} DumpContext;

191
static void
192
help(const char *progname)
193
{
P
Peter Eisentraut 已提交
194
	printf("%s dumps a database as a text file.\n\n", progname);
195 196 197
	puts("Usage:");
	printf("  %s [options] dbname\n\n", progname);
	puts("Options:");
B
Hi,  
Bruce Momjian 已提交
198 199

#ifdef HAVE_GETOPT_LONG
200
	puts(
B
Bruce Momjian 已提交
201
		"  -a, --data-only          dump out only the data, not the schema\n"
202
		"  -b, --blobs              dump out blob data\n"
B
Bruce Momjian 已提交
203
	   	"  -c, --clean              clean (drop) schema prior to create\n"
204
		"  -C, --create             output commands to create database\n"
B
Bruce Momjian 已提交
205 206
		"  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"
		"  -D, --attribute-inserts  dump data as INSERT commands with attribute names\n"
207
		"  -f, --file=FILENAME      specify output file name\n"
B
Bruce Momjian 已提交
208
		"  -F, --format {c|f|p}     output file format (custom, files, plain text)\n"
209
		"  -h, --host=HOSTNAME      server host name\n"
B
Bruce Momjian 已提交
210 211 212 213
		"  -i, --ignore-version     proceed when database version != pg_dump version\n"
		"  -n, --no-quotes          suppress most quotes around identifiers\n"
		"  -N, --quotes             enable most quotes around identifiers\n"
		"  -o, --oids               dump object ids (oids)\n"
214 215 216 217 218
		"  -O, --no-owner           do not output \\connect commands in plain text\n"
		"                           format\n"
		"  -p, --port=PORT          server port number\n"
		"  -R, --no-reconnect       disable ALL reconnections to the database in\n"
		"                           plain text format\n"
B
Bruce Momjian 已提交
219
		"  -s, --schema-only        dump out only the schema, no data\n"
220 221
		"  -S, --superuser=NAME     specify the superuser user name to use in plain\n"
		"                           text format\n"
222
		"  -t, --table=TABLE        dump for this table only (* for all)\n"
B
Bruce Momjian 已提交
223 224 225 226
		"  -u, --password           use password authentication\n"
		"  -v, --verbose            verbose\n"
		"  -x, --no-acl             do not dump ACL's (grant/revoke)\n"
		"  -Z, --compress {0-9}     compression level for compressed formats\n"
227
		);
B
Hi,  
Bruce Momjian 已提交
228
#else
229
	puts(
B
Bruce Momjian 已提交
230
		"  -a                       dump out only the data, no schema\n"
231
		"  -b                       dump out blob data\n"
B
Bruce Momjian 已提交
232
		"  -c                       clean (drop) schema prior to create\n"
233
		"  -C                       output commands to create database\n"
B
Bruce Momjian 已提交
234 235
		"  -d                       dump data as INSERT, rather than COPY, commands\n"
		"  -D                       dump data as INSERT commands with attribute names\n"
236
		"  -f FILENAME              specify output file name\n"
B
Bruce Momjian 已提交
237
		"  -F {c|f|p}               output file format (custom, files, plain text)\n"
238
		"  -h HOSTNAME              server host name\n"
B
Bruce Momjian 已提交
239 240 241 242
		"  -i                       proceed when database version != pg_dump version\n"
		"  -n                       suppress most quotes around identifiers\n"
		"  -N                       enable most quotes around identifiers\n"
		"  -o                       dump object ids (oids)\n"
243 244 245 246 247
		"  -O                       do not output \\connect commands in plain text\n"
		"                           format\n"
		"  -p PORT                  server port number\n"
		"  -R                       disable ALL reconnections to the database in\n"
		"                           plain text format\n"
B
Bruce Momjian 已提交
248
		"  -s                       dump out only the schema, no data\n"
249 250
		"  -S NAME                  specify the superuser user name to use in plain\n"
		"                           text format\n"
251
		"  -t TABLE                 dump for this table only (* for all)\n"
B
Bruce Momjian 已提交
252 253 254 255
		"  -u                       use password authentication\n"
		"  -v                       verbose\n"
		"  -x                       do not dump ACL's (grant/revoke)\n"
		"  -Z {0-9}                 compression level for compressed formats\n"
256
		);
B
Hi,  
Bruce Momjian 已提交
257
#endif
258 259
	puts("If no database name is not supplied, then the PGDATABASE environment\nvariable value is used.\n");
	puts("Report bugs to <pgsql-bugs@postgresql.org>.");
260
}
261

262

263 264 265
static void
version(void)
{
266
	puts("pg_dump (PostgreSQL) " PG_VERSION);
267
	puts("Portions Copyright (c) 1996-2000, PostgreSQL, Inc");
268
	puts("Portions Copyright (c) 1996 Regents of the University of California");
269
	puts("Read the file COPYRIGHT to see the usage and distribution terms.");
270 271
}

272

273
static void
274
exit_nicely(PGconn *conn)
275
{
276 277
	PQfinish(conn);
	exit(1);
278 279 280
}


281 282
#define COPYBUFSIZ		8192

B
Bruce Momjian 已提交
283 284 285 286 287
/*
 *	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.
 */
288

B
Bruce Momjian 已提交
289 290
static int 
dumpClasses_nodumpData(Archive *fout, char* oid, void *dctxv)
291
{
B
Bruce Momjian 已提交
292 293 294
	const DumpContext	*dctx = (DumpContext*)dctxv; 	
	const char 	*classname = dctx->tblinfo[dctx->tblidx].relname;
	const bool	oids = dctx->oids;
295

296 297 298 299 300
	PGresult   *res;
	char		query[255];
	int			ret;
	bool		copydone;
	char		copybuf[COPYBUFSIZ];
301

302 303 304
    if (g_verbose)
        fprintf(stderr, "%s dumping out the contents of table %s\n", g_comment_start, classname);

305
	if (oids == true)
306
	{
307 308 309 310 311 312 313 314
		/* 
		 * archprintf(fout, "COPY %s WITH OIDS FROM stdin;\n",
		 *		fmtId(classname, force_quotes));
		 *
		 *  - Not used as of V1.3 (needs to be in ArchiveEntry call)
		 *
		 */

315
		sprintf(query, "COPY %s WITH OIDS TO stdout;\n",
316
				fmtId(classname, force_quotes));
317 318 319
	}
	else
	{
320 321 322 323 324 325 326
		/* 
		 *archprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname, force_quotes));
		 *
		 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
		 *
		 */

327
		sprintf(query, "COPY %s TO stdout;\n", fmtId(classname, force_quotes));
328 329
	}
	res = PQexec(g_conn, query);
330 331
	if (!res ||
		PQresultStatus(res) == PGRES_FATAL_ERROR)
332
	{
333
		fprintf(stderr, "SQL query to dump the contents of Table '%s' "
334 335 336 337 338 339 340 341 342
				"did not execute.  Explanation from backend: '%s'.\n"
				"The query was: '%s'.\n",
				classname, PQerrorMessage(g_conn), query);
		exit_nicely(g_conn);
	}
	else
	{
		if (PQresultStatus(res) != PGRES_COPY_OUT)
		{
343
			fprintf(stderr, "SQL query to dump the contents of Table '%s' "
344 345 346 347 348 349 350 351 352
					"executed abnormally.\n"
					"PQexec() returned status %d when %d was expected.\n"
					"The query was: '%s'.\n",
				  classname, PQresultStatus(res), PGRES_COPY_OUT, query);
			exit_nicely(g_conn);
		}
		else
		{
			copydone = false;
353

354 355
			while (!copydone)
			{
356
				ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
357 358 359 360 361 362 363 364 365

				if (copybuf[0] == '\\' &&
					copybuf[1] == '.' &&
					copybuf[2] == '\0')
				{
					copydone = true;	/* don't print this... */
				}
				else
				{
B
Bruce Momjian 已提交
366
					archputs(copybuf, fout);
367 368
					switch (ret)
					{
369 370 371 372
						case EOF:
							copydone = true;
							/* FALLTHROUGH */
						case 0:
B
Bruce Momjian 已提交
373
							archputc('\n', fout);
374 375 376
							break;
						case 1:
							break;
377 378
					}
				}
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418

				/* 
				 * THROTTLE:
				 *
				 * 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.
				 *
				 * 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:
				 *
				 * 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
				 * EndIf
				 *
				 * where the throttle value was the number of ms to sleep per ms of work. The calculation was 
				 * done in each loop.
				 *
				 * 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.
				 *
				 * Further discussion ensued, and the proposal was dropped.
				 *
				 * 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.
				 *
				 *        select(0, NULL, NULL, NULL, &tvi);
				 *
				 * This will return after the interval specified in the structure tvi. Fianally, call
				 * gettimeofday again to save the 'last sleep time'.
				 */	
419
			}
B
Bruce Momjian 已提交
420
			archprintf(fout, "\\.\n");
421
		}
422
		ret = PQendcopy(g_conn);
423 424
		if (ret != 0)
		{
425
			fprintf(stderr, "SQL query to dump the contents of Table '%s' "
426 427 428 429 430
					"did not execute correctly.  After we read all the "
				 "table contents from the backend, PQendcopy() failed.  "
					"Explanation from backend: '%s'.\n"
					"The query was: '%s'.\n",
					classname, PQerrorMessage(g_conn), query);
B
Bruce Momjian 已提交
431
			PQclear(res);
432 433 434
			exit_nicely(g_conn);
		}
	}
435

B
Bruce Momjian 已提交
436
	return 1;
437 438
}

B
Bruce Momjian 已提交
439 440
static int
dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
441
{
B
Bruce Momjian 已提交
442 443 444
	const DumpContext	*dctx = (DumpContext*)dctxv;
	const char			*classname = dctx->tblinfo[dctx->tblidx].relname;

445 446
	PGresult   *res;
	PQExpBuffer q = createPQExpBuffer();
447 448
	int			tuple;
	int			field;
449

B
Hi, all  
Bruce Momjian 已提交
450 451
	appendPQExpBuffer(q, "SELECT * FROM %s", fmtId(classname, force_quotes));
	res = PQexec(g_conn, q->data);
452 453 454
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
455 456
		fprintf(stderr, "dumpClasses(): command failed.  Explanation from backend: '%s'.\n", 
					PQerrorMessage(g_conn));
457 458
		exit_nicely(g_conn);
	}
459
	for (tuple = 0; tuple < PQntuples(res); tuple++)
460
	{
B
Bruce Momjian 已提交
461
		archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
462
		if (attrNames == true)
463
		{
B
Hi, all  
Bruce Momjian 已提交
464 465
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "(");
466
			for (field = 0; field < PQnfields(res); field++)
467
			{
468
				if (field > 0)
B
Hi, all  
Bruce Momjian 已提交
469 470
					appendPQExpBuffer(q, ",");
				appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
471
			}
B
Hi, all  
Bruce Momjian 已提交
472
			appendPQExpBuffer(q, ") ");
B
Bruce Momjian 已提交
473
			archprintf(fout, "%s", q->data);
474
		}
B
Bruce Momjian 已提交
475
		archprintf(fout, "VALUES (");
476
		for (field = 0; field < PQnfields(res); field++)
477
		{
478
			if (field > 0)
B
Bruce Momjian 已提交
479
				archprintf(fout, ",");
480
			if (PQgetisnull(res, tuple, field))
481
			{
B
Bruce Momjian 已提交
482
				archprintf(fout, "NULL");
483 484 485
				continue;
			}
			switch (PQftype(res, field))
486
			{
487 488
				case INT2OID:
				case INT4OID:
489
				case OIDOID:	/* int types */
490
				case FLOAT4OID:
491
				case FLOAT8OID:/* float types */
492
					/* These types are printed without quotes */
B
Bruce Momjian 已提交
493
					archprintf(fout, "%s",
494 495
							PQgetvalue(res, tuple, field));
					break;
496 497 498 499 500
				case ZPBITOID:
				case VARBITOID:
					archprintf(fout, "B'%s'",
							   PQgetvalue(res, tuple, field));
					break;
501
				default:
502

503 504
					/*
					 * All other types are printed as string literals,
505
					 * with appropriate escaping of special characters.
506
					 */
507 508 509
					resetPQExpBuffer(q);
					formatStringLiteral(q, PQgetvalue(res, tuple, field));
					archprintf(fout, "%s", q->data);
510
					break;
511
			}
512
		}
B
Bruce Momjian 已提交
513
		archprintf(fout, ");\n");
514 515
	}
	PQclear(res);
B
Bruce Momjian 已提交
516
	return 1;
517 518
}

519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
/*
 * 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
formatStringLiteral(PQExpBuffer buf, const char *str)
{
	appendPQExpBufferChar(buf, '\'');
	while (*str)
	{
		char	ch = *str++;

		if (ch == '\\' || ch == '\'')
		{
			appendPQExpBufferChar(buf, ch);	/* double these */
			appendPQExpBufferChar(buf, ch);
		}
		else if ((unsigned char) ch < (unsigned char) ' ' &&
				 ch != '\n' && ch != '\t')
		{
			/* generate octal escape for control chars other than whitespace */
			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, '\'');
}

554 555
/*
 * DumpClasses -
556
 *	  dump the contents of all the classes.
557 558
 */
static void
B
Bruce Momjian 已提交
559
dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
560
			const char *onlytable, const bool oids, const bool force_quotes)
561 562
{

B
Bruce Momjian 已提交
563 564 565 566
	int				i;
	char	   		*all_only;
	DataDumperPtr	dumpFn;
	DumpContext		*dumpCtx;
567 568 569
	char			*oidsPart;
	char			copyBuf[512];
	char			*copyStmt;
570

571
	if (onlytable == NULL || (strlen(onlytable) == 0) )
572 573
		all_only = "all";
	else
574
		all_only = "only";
575

576 577 578 579 580 581
	if (oids == true)
		oidsPart = "WITH OIDS ";
	else
		oidsPart = "";


582
	if (g_verbose)
583
		fprintf(stderr, "%s preparing to dump out the contents of %s %d table%s/sequence%s %s\n",
584
				g_comment_start, all_only,
585 586 587
				(onlytable == NULL || (strlen(onlytable) == 0)) ? numTables : 1,
				(onlytable == NULL || (strlen(onlytable) == 0)) ? "s" : "", 
				(onlytable == NULL || (strlen(onlytable) == 0)) ? "s" : "",
588
				g_comment_end);
589

V
Vadim B. Mikheev 已提交
590 591 592 593 594 595 596
	/* Dump SEQUENCEs first (if dataOnly) */
	if (dataOnly)
	{
		for (i = 0; i < numTables; i++)
		{
			if (!(tblinfo[i].sequence))
				continue;
597
			if (!onlytable || (strcmp(tblinfo[i].relname, onlytable) == 0) || (strlen(onlytable) == 0) )
V
Vadim B. Mikheev 已提交
598 599
			{
				if (g_verbose)
600
					fprintf(stderr, "%s dumping out schema of sequence '%s' %s\n",
601
					 g_comment_start, tblinfo[i].relname, g_comment_end);
B
Bruce Momjian 已提交
602
				/* becomeUser(fout, tblinfo[i].usename); */
V
Vadim B. Mikheev 已提交
603 604 605 606
				dumpSequence(fout, tblinfo[i]);
			}
		}
	}
607 608 609

	for (i = 0; i < numTables; i++)
	{
610
		const char *classname = tblinfo[i].relname;
611 612

		/* Skip VIEW relations */
613
		if (tblinfo[i].viewdef != NULL)
614
			continue;
615 616

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

619
		if (!onlytable || (strcmp(classname, onlytable) == 0) || (strlen(onlytable) == 0))
620 621
		{
			if (g_verbose)
622
				fprintf(stderr, "%s preparing to dump out the contents of Table '%s' %s\n",
623 624
						g_comment_start, classname, g_comment_end);

B
Bruce Momjian 已提交
625 626 627 628 629 630
			/* becomeUser(fout, tblinfo[i].usename); */

			dumpCtx = (DumpContext*)malloc(sizeof(DumpContext));
			dumpCtx->tblinfo = (TableInfo*)tblinfo;
			dumpCtx->tblidx = i;
			dumpCtx->oids = oids;
631

632 633
			if (!dumpData) /* Dump/restore using COPY */
			{
B
Bruce Momjian 已提交
634 635
				dumpFn = dumpClasses_nodumpData;
				/* dumpClasses_nodumpData(fout, classname, oids); */
636 637 638 639 640 641
				sprintf(copyBuf, "COPY %s %s FROM stdin;\n", fmtId(tblinfo[i].relname, force_quotes),
						oidsPart);
				copyStmt = copyBuf;
			}
			else /* Restore using INSERT */
			{
B
Bruce Momjian 已提交
642 643
				dumpFn = dumpClasses_dumpData;
				/* dumpClasses_dumpData(fout, classname); */
644 645
				copyStmt = NULL;
			}
B
Bruce Momjian 已提交
646 647

			ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
648
							"TABLE DATA", NULL, "", "", copyStmt, tblinfo[i].usename,
B
Bruce Momjian 已提交
649
							dumpFn, dumpCtx);
650
		}
651
	}
652 653
}

654
int
655
main(int argc, char **argv)
656
{
B
Bruce Momjian 已提交
657 658 659
	int			c;
	const char *progname;
	const char *filename = NULL;
B
Bruce Momjian 已提交
660
	const char *format = "p";
B
Bruce Momjian 已提交
661 662 663 664
	const char *dbname = NULL;
	const char *pghost = NULL;
	const char *pgport = NULL;
	char	   *tablename = NULL;
665
	bool		oids = false;
B
Bruce Momjian 已提交
666 667
	TableInfo  *tblinfo;
	int			numTables;
668
	bool		use_password = false;
B
Bruce Momjian 已提交
669
	int			compressLevel = -1;
670
	bool		ignore_version = false;
671 672
	int			plainText = 0;
	int			outputClean = 0;
673
	int			outputCreate = 0;
674
	int			outputBlobs = 0;
675 676 677
	int			outputNoOwner = 0;
	int			outputNoReconnect = 0;
	char		*outputSuperuser = NULL;
678

B
Bruce Momjian 已提交
679
	RestoreOptions	*ropt;
680

B
Hi,  
Bruce Momjian 已提交
681 682 683
#ifdef HAVE_GETOPT_LONG
	static struct option long_options[] = {
		{"data-only", no_argument, NULL, 'a'},
684
		{"blobs", no_argument, NULL, 'b' },
B
Hi,  
Bruce Momjian 已提交
685
		{"clean", no_argument, NULL, 'c'},
686
		{"create", no_argument, NULL, 'C'},
B
Bruce Momjian 已提交
687 688
		{"file", required_argument, NULL, 'f'},
		{"format", required_argument, NULL, 'F'},
689
		{"inserts", no_argument, NULL, 'd'},
690
		{"attribute-inserts", no_argument, NULL, 'D'},
B
Hi,  
Bruce Momjian 已提交
691
		{"host", required_argument, NULL, 'h'},
692
		{"ignore-version", no_argument, NULL, 'i'},
693
		{"no-reconnect", no_argument, NULL, 'R'},
B
Hi,  
Bruce Momjian 已提交
694 695
		{"no-quotes", no_argument, NULL, 'n'},
		{"quotes", no_argument, NULL, 'N'},
696
		{"oids", no_argument, NULL, 'o'},
697
		{"no-owner", no_argument, NULL, 'O'},
B
Hi,  
Bruce Momjian 已提交
698 699
		{"port", required_argument, NULL, 'p'},
		{"schema-only", no_argument, NULL, 's'},
700
		{"superuser", required_argument, NULL, 'S'},
B
Hi,  
Bruce Momjian 已提交
701 702 703 704
		{"table", required_argument, NULL, 't'},
		{"password", no_argument, NULL, 'u'},
		{"verbose", no_argument, NULL, 'v'},
		{"no-acl", no_argument, NULL, 'x'},
B
Bruce Momjian 已提交
705
		{"compress", required_argument, NULL, 'Z'},
B
Hi,  
Bruce Momjian 已提交
706
		{"help", no_argument, NULL, '?'},
707
		{"version", no_argument, NULL, 'V'}
708
	};
709 710
	int			optindex;

B
Hi,  
Bruce Momjian 已提交
711 712
#endif

713
	g_verbose = false;
714
	force_quotes = true;
715 716 717 718 719

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

720
	dataOnly = schemaOnly = dumpData = attrNames = false;
721

722 723 724 725
	if (!strrchr(argv[0], SEP_CHAR))
		progname = argv[0];
	else
		progname = strrchr(argv[0], SEP_CHAR) + 1;
726

727 728 729 730
	/* Set defaulty options based on progname */
	if (strcmp(progname, "pg_backup") == 0)
	{
		format = "c";
P
Philip Warner 已提交
731
		outputBlobs = true;
732
	}
733

734 735 736 737 738 739 740 741 742 743 744 745 746 747
	if (argc > 1)
	{
		if (strcmp(argv[1], "--help")==0 || strcmp(argv[1], "-?")==0)
		{
			help(progname);
			exit(0);
		}
		if (strcmp(argv[1], "--version")==0 || strcmp(argv[1], "-V")==0)
		{
			version();
			exit(0);
		}
	}

B
Hi,  
Bruce Momjian 已提交
748
#ifdef HAVE_GETOPT_LONG
749
	while ((c = getopt_long(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uvxzZ:V?", long_options, &optindex)) != -1)
B
Hi,  
Bruce Momjian 已提交
750
#else
751
	while ((c = getopt(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uvxzZ:V?-")) != -1)
B
Hi,  
Bruce Momjian 已提交
752
#endif
753

754 755 756
	{
		switch (c)
		{
757
			case 'a':			/* Dump data only */
758
				dataOnly = true;
759
				break;
760

761 762 763 764
			case 'b':			/* Dump blobs */
				outputBlobs = true;
				break;

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

				outputCreate = 1;
				break;

775
			case 'd':			/* dump data as proper insert strings */
776
				dumpData = true;
777
				break;
778

779 780
			case 'D':			/* dump data as proper insert strings with
								 * attr names */
781 782
				dumpData = true;
				attrNames = true;
783
				break;
784

785
			case 'f':
786 787
				filename = optarg;
				break;
788

B
Bruce Momjian 已提交
789 790 791
			case 'F':
				format = optarg;
				break;
792

B
Bruce Momjian 已提交
793
			case 'h':			/* server host */
794 795
				pghost = optarg;
				break;
796

797 798 799
			case 'i':			/* ignore database version mismatch */
				ignore_version = true;
				break;
800

B
Bruce Momjian 已提交
801 802
			case 'n':			/* Do not force double-quotes on
								 * identifiers */
803
				force_quotes = false;
804
				break;
805

806
			case 'N':			/* Force double-quotes on identifiers */
807
				force_quotes = true;
808
				break;
809

810
			case 'o':			/* Dump oids */
811
				oids = true;
812
				break;
813 814


815 816 817
			case 'O':			/* Don't reconnect to match owner */
				outputNoOwner = 1;
				break;
818

819 820 821
			case 'p':			/* server port */
				pgport = optarg;
				break;
822

823 824 825
			case 'R':			/* No reconnect */
				outputNoReconnect = 1;
				break;
826

827
			case 's':			/* dump schema only */
828
				schemaOnly = true;
829
				break;
830

831 832 833
			case 'S':			/* Username for superuser in plain text output */
				outputSuperuser = strdup(optarg);
				break;
834

835
			case 't':			/* Dump data for this table only */
836
				{
837
					int			i;
838 839

					tablename = strdup(optarg);
B
Bruce Momjian 已提交
840 841 842 843 844

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

						/* '*' is a special case meaning ALL tables, but only if unquoted */
						if (strcmp(tablename,"*") == 0)
							tablename[0] = '\0';

862
					}
863
				}
864
				break;
865

866 867 868
			case 'u':
				use_password = true;
				break;
869

870 871
			case 'v':			/* verbose */
				g_verbose = true;
872
				break;
873

874 875
			case 'x':			/* skip ACL dump */
				aclsSkip = true;
876
				break;
877

B
Bruce Momjian 已提交
878 879 880
			case 'Z':			/* Compression Level */
				compressLevel = atoi(optarg);
				break;
881

882 883 884 885
			case 'V':
				version();
				exit(0);
				break;
886

887 888 889
#ifndef HAVE_GETOPT_LONG
			case '-':
				fprintf(stderr, "%s was compiled without support for long options.\n"
890
				   "Use --help for help on invocation options.\n", progname);
891 892 893
				exit(1);
				break;
#endif
894
			default:
895
				fprintf(stderr, "Try '%s --help' for more information.\n", progname);
896
				exit(1);
897 898 899
		}
	}

P
Philip Warner 已提交
900 901 902
	if (optind < (argc - 1)) {
		fprintf(stderr,
				"%s: extra parameters found on command line after '%s' (first is '%s').\n"
903
			    "Please respecify command.\nUse --help for help on invocation options.\n",
P
Philip Warner 已提交
904 905 906 907
				progname, argv[optind], argv[optind+1]);
		exit(1);
	}

B
Bruce Momjian 已提交
908 909 910 911 912 913 914 915
	if (dataOnly && schemaOnly)
	{
		fprintf(stderr,
				"%s: 'Schema Only' and 'Data Only' are incompatible options.\n",
				progname);
		exit(1);
	}

916
	if (outputBlobs && tablename != NULL && strlen(tablename) > 0 )
917 918
	{
		fprintf(stderr,
919
				"%s: BLOB output is not supported for a single table. Use all tables or a full dump instead.\n",
920 921 922 923
				progname);
		exit(1);
	}

924 925 926
	if (dumpData == true && oids == true)
	{
		fprintf(stderr,
927
				"%s: INSERT's can not set oids, so INSERT and OID options can not be used together.\n",
928
				progname);
929
		exit(1);
930
	}
931

P
Philip Warner 已提交
932 933 934 935 936 937 938 939
	if (outputBlobs == true && (format[0] == 'p' || format[0] == 'P') )
	{
		fprintf(stderr,
			"%s: BLOB output is not supported for plain text dump files. Use a different output format.\n",
			progname);
		exit(1);
	}

940
	/* open the output file */
B
Bruce Momjian 已提交
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
	switch (format[0]) {

		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;
956 957 958 959 960 961
			g_fout = CreateArchive(filename, archNull, 0);
			break;

		case 't':
		case 'T':
			g_fout = CreateArchive(filename, archTar, compressLevel);
B
Bruce Momjian 已提交
962 963 964
			break;

		default:
965
			fprintf(stderr,
B
Bruce Momjian 已提交
966 967 968 969 970 971 972 973 974 975
				"%s: invalid output format '%s' specified\n", progname, format);
		    exit(1);	
	}

	if (g_fout == NULL)
	{
		fprintf(stderr,
			 "%s: could not open output file named %s for writing\n",
				progname, filename);
		exit(1);
976 977
	}

978 979
	/* Let the archiver know how noisy to be */
	g_fout->verbose = g_verbose;
980

981
	dbname = argv[optind];
982

983
	/* Open the database using the Archiver, so it knows about it. Errors mean death */
984
	g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, use_password, ignore_version);
985

986 987 988 989 990 991 992 993
	/*
	 * Start serializable transaction to dump consistent data
	 */
	{
		PGresult   *res;

		res = PQexec(g_conn, "begin");
		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
994 995 996
		    exit_horribly(g_fout, "BEGIN command failed. Explanation from backend: '%s'.\n",
				PQerrorMessage(g_conn));

997 998 999
		PQclear(res);
		res = PQexec(g_conn, "set transaction isolation level serializable");
		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
1000 1001 1002
		    exit_horribly(g_fout, "SET TRANSACTION command failed. Explanation from backend: '%s'.\n",
				PQerrorMessage(g_conn));

1003 1004 1005
		PQclear(res);
	}

1006
	g_last_builtin_oid = findLastBuiltinOid(dbname);
1007

1008 1009 1010 1011
	/* Dump the database definition */
	if (!dataOnly)
		dumpDatabase(g_fout);

1012
	if (oids == true)
1013
		setMaxOid(g_fout);
B
Bruce Momjian 已提交
1014 1015

	if (g_verbose)
1016
			fprintf(stderr, "%s last builtin oid is %u %s\n",
1017
					g_comment_start, g_last_builtin_oid, g_comment_end);
B
Bruce Momjian 已提交
1018
	tblinfo = dumpSchema(g_fout, &numTables, tablename, aclsSkip, oids, schemaOnly, dataOnly);
1019

1020
	if (!schemaOnly)
1021 1022 1023 1024 1025 1026
	{
	    dumpClasses(tblinfo, numTables, g_fout, tablename, oids, force_quotes);
	}

	if (outputBlobs)
		ArchiveEntry(g_fout, "0", "BLOBS", "BLOBS", NULL, "", "", "", "", dumpBlobs, 0); 
1027

1028 1029
	if (!dataOnly)				/* dump indexes and triggers at the end
								 * for performance */
V
Vadim B. Mikheev 已提交
1030 1031
	{
		dumpTriggers(g_fout, tablename, tblinfo, numTables);
1032
		dumpRules(g_fout, tablename, tblinfo, numTables);
V
Vadim B. Mikheev 已提交
1033
	}
1034

1035 1036
	/* Now sort the output nicely */
	SortTocByOID(g_fout);
1037
	MoveToStart(g_fout, "DATABASE");
1038 1039 1040
	MoveToEnd(g_fout, "TABLE DATA");
	MoveToEnd(g_fout, "BLOBS");
	MoveToEnd(g_fout, "INDEX");
1041
	MoveToEnd(g_fout, "CONSTRAINT");
1042 1043
	MoveToEnd(g_fout, "TRIGGER");
	MoveToEnd(g_fout, "RULE");
1044
	MoveToEnd(g_fout, "SEQUENCE SET");
1045

B
Bruce Momjian 已提交
1046 1047 1048 1049 1050 1051
	if (plainText) 
	{
		ropt = NewRestoreOptions();
		ropt->filename = (char*)filename;
		ropt->dropSchema = outputClean;
		ropt->aclsSkip = aclsSkip;
1052 1053 1054 1055 1056 1057 1058 1059 1060
		ropt->superuser = outputSuperuser;
		ropt->create = outputCreate;
		ropt->noOwner = outputNoOwner;
		ropt->noReconnect = outputNoReconnect;

		if (outputSuperuser)
			ropt->superuser = outputSuperuser;
		else
			ropt->superuser = PQuser(g_conn);
B
Bruce Momjian 已提交
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070

		if (compressLevel == -1)
		    ropt->compression = 0;
		else
		    ropt->compression = compressLevel;

		RestoreArchive(g_fout, ropt);
	}

	CloseArchive(g_fout);
1071

1072 1073 1074
	clearTableInfo(tblinfo, numTables);
	PQfinish(g_conn);
	exit(0);
1075 1076
}

1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
/*
 * dumpDatabase:
 *	dump the database definition
 *
 */
static int 
dumpDatabase(Archive *AH)
{
	PQExpBuffer		dbQry = createPQExpBuffer();
	PQExpBuffer		delQry = createPQExpBuffer();
	PQExpBuffer		creaQry = createPQExpBuffer();
	PGresult		*res;
	int				ntups;
	int				i_dba;

	if (g_verbose)
		fprintf(stderr, "%s saving database definition\n", g_comment_start);

	/* Get the dba */
1096
	appendPQExpBuffer(dbQry, "select (select usename from pg_user where datdba = usesysid) as dba from pg_database"
1097 1098
							" where datname = ");
	formatStringLiteral(dbQry, PQdb(g_conn));
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131

	res = PQexec(g_conn, dbQry->data);
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
		fprintf(stderr, "getDatabase(): SELECT failed.  Explanation from backend: '%s'.\n", 
						PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	if (ntups != 1)
	{
		fprintf(stderr, "getDatabase(): SELECT returned %d databases.\n", ntups);
		exit_nicely(g_conn);
	}

	appendPQExpBuffer(creaQry, "Create Database \"%s\";\n", PQdb(g_conn));
	appendPQExpBuffer(delQry, "Drop Database \"%s\";\n", PQdb(g_conn));
	i_dba = PQfnumber(res, "dba");

	ArchiveEntry(AH, "0" /* OID */, PQdb(g_conn) /* Name */, "DATABASE", NULL, 
						creaQry->data /* Create */, delQry->data /*Del*/,
						"" /* Copy */, PQgetvalue(res, 0, i_dba) /*Owner*/, 
						NULL /* Dumper */, NULL /* Dumper Arg */);	

	PQclear(res);

	return 1;
}


1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
/*
 * dumpBlobs:
 *	dump all blobs
 *
 */

#define loBufSize 16384 
#define loFetchSize 1000

static int 
dumpBlobs(Archive *AH, char* junkOid, void *junkVal)
{
	PQExpBuffer		oidQry = createPQExpBuffer();
	PQExpBuffer		oidFetchQry = createPQExpBuffer();
	PGresult		*res;
	int				i;
	int				loFd;
	char			buf[loBufSize];
	int				cnt;
	int				blobOid;

	if (g_verbose)
		fprintf(stderr, "%s saving BLOBs\n", g_comment_start);

	/* Cursor to get all BLOB tables */
1157
    appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject");
1158 1159 1160 1161

	res = PQexec(g_conn, oidQry->data);
	if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
	{
1162 1163
		fprintf(stderr, "dumpBlobs(): Declare Cursor failed.  Explanation from backend: '%s'.\n", 
										PQerrorMessage(g_conn));
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
		exit_nicely(g_conn);
	}

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

	do {
		/* Do a fetch */
		PQclear(res);
		res = PQexec(g_conn, oidFetchQry->data);

		if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
		{
		    fprintf(stderr, "dumpBlobs(): Fetch Cursor failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
		    exit_nicely(g_conn);
		}

		/* Process the tuples, if any */
		for (i = 0; i < PQntuples(res); i++)
		{
			blobOid = atoi(PQgetvalue(res, i, 0));
			/* Open the BLOB */
			loFd = lo_open(g_conn, blobOid, INV_READ);
			if (loFd == -1)
			{
				fprintf(stderr, "dumpBlobs(): Could not open large object.  "
									"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
				exit_nicely(g_conn);
			}

			StartBlob(AH, blobOid);

			/* Now read it in chunks, sending data to archive */
			do {
				cnt = lo_read(g_conn, loFd, buf, loBufSize);
				if (cnt < 0) {
					fprintf(stderr, "dumpBlobs(): Error reading large object. "
								" Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
					exit_nicely(g_conn);
				}

				WriteData(AH, buf, cnt); 

			} while (cnt > 0);

			lo_close(g_conn, loFd);

			EndBlob(AH, blobOid);

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

	return 1;
}

1219
/*
1220 1221
 * getTypes:
 *	  read all base types in the system catalogs and return them in the
1222 1223
 * TypeInfo* structure
 *
1224
 *	numTypes is set to the number of types read in
1225 1226
 *
 */
1227
TypeInfo   *
1228 1229
getTypes(int *numTypes)
{
B
Bruce Momjian 已提交
1230
	PGresult   *res;
1231 1232
	int			ntups;
	int			i;
1233
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1234
	TypeInfo   *tinfo;
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250

	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;
	int			i_typbyval;
	int			i_usename;
1251
	int			i_typedefn;
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263

	/* find all base types */

	/*
	 * we include even the built-in types because those may be used as
	 * array elements by user-defined types
	 */

	/*
	 * we filter out the built-in types when we dump out the types
	 */

B
Hi, all  
Bruce Momjian 已提交
1264
	appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
1265 1266 1267 1268 1269
		"typinput, typoutput, typreceive, typsend, typelem, typdelim, "
		"typdefault, typrelid, typbyval, "
		"(select usename from pg_user where typowner = usesysid) as usename, "
		"format_type(pg_type.oid, NULL) as typedefn "
		"from pg_type" );
1270

B
Hi, all  
Bruce Momjian 已提交
1271
	res = PQexec(g_conn, query->data);
1272 1273 1274
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1275
		fprintf(stderr, "getTypes(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
		exit_nicely(g_conn);
	}

	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");
	i_typbyval = PQfnumber(res, "typbyval");
	i_usename = PQfnumber(res, "usename");
1298
	i_typedefn = PQfnumber(res, "typedefn");
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315

	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));
		tinfo[i].typdefault = strdup(PQgetvalue(res, i, i_typdefault));
		tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
		tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1316
		tinfo[i].typedefn = strdup(PQgetvalue(res, i, i_typedefn));
1317

1318 1319 1320
		if (strlen(tinfo[i].usename) == 0)
			fprintf(stderr, "WARNING: owner of type '%s' appears to be invalid\n",tinfo[i].typname);

1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
		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;
	}

	*numTypes = ntups;

	PQclear(res);

	return tinfo;
1341 1342 1343 1344
}

/*
 * getOperators:
1345
 *	  read all operators in the system catalogs and return them in the
1346 1347
 * OprInfo* structure
 *
1348 1349
 *	numOprs is set to the number of operators read in
 *
1350 1351
 *
 */
1352
OprInfo    *
1353 1354
getOperators(int *numOprs)
{
1355
	PGresult   *res;
1356 1357
	int			ntups;
	int			i;
1358
	PQExpBuffer query = createPQExpBuffer();
1359

B
Bruce Momjian 已提交
1360
	OprInfo    *oprinfo;
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375

	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;
1376 1377 1378 1379 1380 1381

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

B
Hi, all  
Bruce Momjian 已提交
1382
	appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
1383
			   "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
1384 1385 1386
					"oprcanhash, oprlsortop, oprrsortop, "
					"(select usename from pg_user where oprowner = usesysid) as usename "
					"from pg_operator");
1387

B
Hi, all  
Bruce Momjian 已提交
1388
	res = PQexec(g_conn, query->data);
1389 1390 1391
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1392
		fprintf(stderr, "getOperators(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
		exit_nicely(g_conn);
	}

	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));
1432 1433 1434 1435 1436

		if (strlen(oprinfo[i].usename) == 0)
			fprintf(stderr, "WARNING: owner of operator '%s' appears to be invalid\n",
						oprinfo[i].oprname);

1437 1438 1439 1440 1441
	}

	PQclear(res);

	return oprinfo;
1442 1443
}

1444
void
1445
clearTypeInfo(TypeInfo *tp, int numTypes)
1446
{
1447
	int			i;
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480

	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);
		if (tp[i].usename)
			free(tp[i].usename);
	}
	free(tp);
1481 1482 1483
}

void
1484
clearFuncInfo(FuncInfo *fun, int numFuncs)
1485
{
1486 1487
	int			i,
				a;
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498

	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);
1499
		for (a = 0; a < FUNC_MAX_ARGS; ++a)
1500 1501 1502 1503 1504 1505 1506 1507 1508 1509
			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);
1510 1511
}

1512
static void
1513
clearTableInfo(TableInfo *tblinfo, int numTables)
1514
{
1515 1516
	int			i,
				j;
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536

	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++)
		{
B
Bruce,  
Bruce Momjian 已提交
1537 1538
			if (tblinfo[i].attoids[j])
				free(tblinfo[i].attoids[j]);
1539 1540 1541 1542 1543
			if (tblinfo[i].attnames[j])
				free(tblinfo[i].attnames[j]);
			if (tblinfo[i].typnames[j])
				free(tblinfo[i].typnames[j]);
		}
B
Bruce Momjian 已提交
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559

		if (tblinfo[i].triggers) {
			for (j = 0; j < tblinfo[i].ntrig ; j++)
			{
				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);
		}

1560 1561
		if (tblinfo[i].atttypmod)
			free((int *) tblinfo[i].atttypmod);
1562 1563 1564 1565
		if (tblinfo[i].inhAttrs)
			free((int *) tblinfo[i].inhAttrs);
		if (tblinfo[i].attnames)
			free(tblinfo[i].attnames);
1566 1567
		if (tblinfo[i].atttypedefns)
			free(tblinfo[i].atttypedefns);
1568 1569 1570 1571
		if (tblinfo[i].typnames)
			free(tblinfo[i].typnames);
		if (tblinfo[i].notnull)
			free(tblinfo[i].notnull);
1572 1573
		if (tblinfo[i].primary_key_name)
			free(tblinfo[i].primary_key_name);
1574 1575
	}
	free(tblinfo);
1576 1577
}

1578
void
1579
clearInhInfo(InhInfo *inh, int numInherits)
1580
{
1581
	int			i;
1582 1583 1584 1585 1586

	if (!inh)
		return;
	for (i = 0; i < numInherits; ++i)
	{
1587 1588
		if (inh[i].inhrelid)
			free(inh[i].inhrelid);
1589 1590 1591 1592
		if (inh[i].inhparent)
			free(inh[i].inhparent);
	}
	free(inh);
1593 1594 1595
}

void
1596
clearOprInfo(OprInfo *opr, int numOprs)
1597
{
1598
	int			i;
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633

	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);
1634 1635 1636
}

void
1637
clearIndInfo(IndInfo *ind, int numIndices)
1638
{
1639 1640
	int			i,
				a;
1641 1642 1643 1644 1645

	if (!ind)
		return;
	for (i = 0; i < numIndices; ++i)
	{
B
Bruce,  
Bruce Momjian 已提交
1646 1647
		if (ind[i].indoid)
			free(ind[i].indoid);
1648 1649 1650 1651 1652 1653 1654 1655 1656 1657
		if (ind[i].indexrelname)
			free(ind[i].indexrelname);
		if (ind[i].indrelname)
			free(ind[i].indrelname);
		if (ind[i].indamname)
			free(ind[i].indamname);
		if (ind[i].indproc)
			free(ind[i].indproc);
		if (ind[i].indisunique)
			free(ind[i].indisunique);
1658 1659
		if (ind[i].indisprimary)
			free(ind[i].indisprimary);
1660 1661 1662 1663 1664 1665 1666 1667 1668
		for (a = 0; a < INDEX_MAX_KEYS; ++a)
		{
			if (ind[i].indkey[a])
				free(ind[i].indkey[a]);
			if (ind[i].indclass[a])
				free(ind[i].indclass[a]);
		}
	}
	free(ind);
1669 1670 1671
}

void
B
Bruce Momjian 已提交
1672
clearAggInfo(AggInfo *agginfo, int numArgs)
1673
{
1674
	int			i;
1675 1676 1677 1678 1679 1680 1681 1682 1683

	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);
1684 1685
		if (agginfo[i].aggtransfn)
			free(agginfo[i].aggtransfn);
1686 1687
		if (agginfo[i].aggfinalfn)
			free(agginfo[i].aggfinalfn);
1688 1689
		if (agginfo[i].aggtranstype)
			free(agginfo[i].aggtranstype);
1690 1691
		if (agginfo[i].aggbasetype)
			free(agginfo[i].aggbasetype);
1692 1693
		if (agginfo[i].agginitval)
			free(agginfo[i].agginitval);
1694 1695 1696 1697
		if (agginfo[i].usename)
			free(agginfo[i].usename);
	}
	free(agginfo);
1698
}
1699 1700 1701

/*
 * getAggregates:
1702
 *	  read all the user-defined aggregates in the system catalogs and
1703 1704
 * return them in the AggInfo* structure
 *
1705 1706
 * numAggs is set to the number of aggregates read in
 *
1707 1708
 *
 */
1709
AggInfo    *
1710 1711
getAggregates(int *numAggs)
{
B
Bruce Momjian 已提交
1712
	PGresult   *res;
1713 1714
	int			ntups;
	int			i;
1715
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1716
	AggInfo    *agginfo;
1717 1718 1719

	int			i_oid;
	int			i_aggname;
1720
	int			i_aggtransfn;
1721
	int			i_aggfinalfn;
1722
	int			i_aggtranstype;
1723
	int			i_aggbasetype;
1724
	int			i_agginitval;
1725
	int			i_usename;
1726 1727 1728

	/* find all user-defined aggregates */

B
Hi, all  
Bruce Momjian 已提交
1729
	appendPQExpBuffer(query,
1730 1731 1732 1733 1734
						"SELECT pg_aggregate.oid, aggname, aggtransfn, "
						"aggfinalfn, aggtranstype, aggbasetype, "
						"agginitval, "
						"(select usename from pg_user where aggowner = usesysid) as usename "
						"from pg_aggregate" );
1735

B
Hi, all  
Bruce Momjian 已提交
1736
	res = PQexec(g_conn, query->data);
1737 1738 1739
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1740 1741
		fprintf(stderr, "getAggregates(): SELECT failed.  Explanation from backend: '%s'.\n",
					PQerrorMessage(g_conn));
1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
		exit_nicely(g_conn);
	}

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

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

	i_oid = PQfnumber(res, "oid");
	i_aggname = PQfnumber(res, "aggname");
1752
	i_aggtransfn = PQfnumber(res, "aggtransfn");
1753
	i_aggfinalfn = PQfnumber(res, "aggfinalfn");
1754
	i_aggtranstype = PQfnumber(res, "aggtranstype");
1755
	i_aggbasetype = PQfnumber(res, "aggbasetype");
1756
	i_agginitval = PQfnumber(res, "agginitval");
1757 1758 1759 1760 1761 1762
	i_usename = PQfnumber(res, "usename");

	for (i = 0; i < ntups; i++)
	{
		agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
		agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
1763
		agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
1764
		agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
1765
		agginfo[i].aggtranstype = strdup(PQgetvalue(res, i, i_aggtranstype));
1766
		agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
1767
		agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
1768
		agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1769 1770 1771 1772
		if (strlen(agginfo[i].usename) == 0)
			fprintf(stderr, "WARNING: owner of aggregate '%s' appears to be invalid\n",
						agginfo[i].aggname);

1773 1774 1775 1776 1777
	}

	PQclear(res);

	return agginfo;
1778 1779 1780 1781
}

/*
 * getFuncs:
1782
 *	  read all the user-defined functions in the system catalogs and
1783 1784
 * return them in the FuncInfo* structure
 *
1785 1786
 * numFuncs is set to the number of functions read in
 *
1787 1788
 *
 */
1789
FuncInfo   *
1790 1791
getFuncs(int *numFuncs)
{
1792
	PGresult   *res;
1793 1794
	int			ntups;
	int			i;
1795 1796
	PQExpBuffer query = createPQExpBuffer();
	FuncInfo   *finfo;
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806

	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;
1807
	int			i_iscachable;
1808
	int			i_isstrict;
1809
	int			i_usename;
1810 1811 1812

	/* find all user-defined funcs */

B
Hi, all  
Bruce Momjian 已提交
1813
	appendPQExpBuffer(query,
1814
		   "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
1815 1816
					  "proretset, proargtypes, prosrc, probin, "
					  "(select usename from pg_user where proowner = usesysid) as usename, "
1817
					  "proiscachable, proisstrict "
1818 1819
					  "from pg_proc "
				 "where pg_proc.oid > '%u'::oid",
1820
					  g_last_builtin_oid);
1821

B
Hi, all  
Bruce Momjian 已提交
1822
	res = PQexec(g_conn, query->data);
1823 1824 1825
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1826 1827
		fprintf(stderr, "getFuncs(): SELECT failed.  Explanation from backend: '%s'.\n", 
					PQerrorMessage(g_conn));
1828 1829 1830 1831 1832 1833 1834 1835 1836
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numFuncs = ntups;

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

1837 1838
	memset((char *) finfo, 0, ntups * sizeof(FuncInfo));

1839 1840 1841 1842 1843 1844 1845 1846 1847
	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");
1848
	i_iscachable = PQfnumber(res, "proiscachable");
1849
	i_isstrict = PQfnumber(res, "proisstrict");
1850 1851 1852 1853 1854 1855 1856
	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));

1857
		finfo[i].prosrc = strdup(PQgetvalue(res, i, i_prosrc));
1858 1859 1860 1861 1862
		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));
1863
		finfo[i].lang = atoi(PQgetvalue(res, i, i_prolang));
1864
		finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1865
		finfo[i].iscachable = (strcmp(PQgetvalue(res, i, i_iscachable),"t") == 0);
1866
		finfo[i].isstrict = (strcmp(PQgetvalue(res, i, i_isstrict),"t") == 0);
1867 1868 1869 1870 1871

		if (strlen(finfo[i].usename) == 0)
			fprintf(stderr, "WARNING: owner of function '%s' appears to be invalid\n",
						finfo[i].proname);

1872 1873 1874 1875
		if (finfo[i].nargs < 0 || finfo[i].nargs > FUNC_MAX_ARGS)
		{
			fprintf(stderr, "failed sanity check: %s has %d args\n",
					finfo[i].proname, finfo[i].nargs);
1876
			exit(1);
1877 1878 1879 1880
		}
		parseNumericArray(PQgetvalue(res, i, i_proargtypes),
						  finfo[i].argtypes,
						  finfo[i].nargs);
1881 1882 1883 1884 1885 1886
		finfo[i].dumped = 0;
	}

	PQclear(res);

	return finfo;
1887 1888 1889 1890 1891

}

/*
 * getTables
1892
 *	  read all the user-defined tables (no indices, no catalogs)
1893 1894
 * in the system catalogs return them in the TableInfo* structure
 *
1895 1896
 * numTables is set to the number of tables read in
 *
1897 1898
 *
 */
1899
TableInfo  *
V
Vadim B. Mikheev 已提交
1900
getTables(int *numTables, FuncInfo *finfo, int numFuncs)
1901
{
1902
	PGresult   *res;
1903 1904
	int			ntups;
	int			i;
1905
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1906
	PQExpBuffer delqry = createPQExpBuffer();
1907
	TableInfo  *tblinfo;
1908

B
Bruce Momjian 已提交
1909
	int			i_reloid;
1910 1911 1912 1913
	int			i_relname;
	int			i_relkind;
	int			i_relacl;
	int			i_usename;
V
Vadim B. Mikheev 已提交
1914 1915
	int			i_relchecks;
	int			i_reltriggers;
1916
	int			i_relhasindex;
1917 1918 1919 1920 1921

	char		relkindview[2];

	relkindview[0] = RELKIND_VIEW;
	relkindview[1] = '\0';
1922 1923 1924 1925 1926 1927

	/*
	 * find all the user-defined tables (no indices and no catalogs),
	 * ordering by oid is important so that we always process the parent
	 * tables before the child tables when traversing the tblinfo*
	 *
1928
	 * we ignore tables that are not type 'r' (ordinary relation) or 'S'
1929
	 * (sequence) or 'v' (view).
1930 1931
	 */

B
Hi, all  
Bruce Momjian 已提交
1932
	appendPQExpBuffer(query,
1933 1934
			   "SELECT pg_class.oid, relname, relkind, relacl, "
					  "(select usename from pg_user where relowner = usesysid) as usename, "
1935
					  "relchecks, reltriggers, relhasindex "
1936 1937
					  "from pg_class "
					  "where relname !~ '^pg_' "
1938 1939 1940
					  "and relkind in ('%c', '%c', '%c') "
					  "order by oid",
				RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
1941

B
Hi, all  
Bruce Momjian 已提交
1942
	res = PQexec(g_conn, query->data);
1943 1944 1945
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1946 1947
		fprintf(stderr, "getTables(): SELECT failed.  Explanation from backend: '%s'.\n", 
					PQerrorMessage(g_conn));
1948 1949 1950 1951 1952 1953 1954 1955 1956
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numTables = ntups;

	tblinfo = (TableInfo *) malloc(ntups * sizeof(TableInfo));

B
Bruce Momjian 已提交
1957
	i_reloid = PQfnumber(res, "oid");
1958 1959 1960 1961
	i_relname = PQfnumber(res, "relname");
	i_relkind = PQfnumber(res, "relkind");
	i_relacl = PQfnumber(res, "relacl");
	i_usename = PQfnumber(res, "usename");
V
Vadim B. Mikheev 已提交
1962 1963
	i_relchecks = PQfnumber(res, "relchecks");
	i_reltriggers = PQfnumber(res, "reltriggers");
B
Hi, all  
Bruce Momjian 已提交
1964
	i_relhasindex = PQfnumber(res, "relhasindex");
1965 1966 1967

	for (i = 0; i < ntups; i++)
	{
B
Bruce Momjian 已提交
1968
		tblinfo[i].oid = strdup(PQgetvalue(res, i, i_reloid));
1969 1970 1971 1972
		tblinfo[i].relname = strdup(PQgetvalue(res, i, i_relname));
		tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
		tblinfo[i].sequence = (strcmp(PQgetvalue(res, i, i_relkind), "S") == 0);
		tblinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
V
Vadim B. Mikheev 已提交
1973 1974
		tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
		tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
1975

1976 1977 1978 1979
		if (strlen(tblinfo[i].usename) == 0)
			fprintf(stderr, "WARNING: owner of table '%s' appears to be invalid\n",
						tblinfo[i].relname);

1980 1981 1982 1983 1984 1985
		/* Get view definition */
		if (strcmp(PQgetvalue(res, i, i_relkind), relkindview) == 0)
		{
			PGresult   *res2;

			resetPQExpBuffer(query);
1986 1987 1988
			appendPQExpBuffer(query, "SELECT pg_get_viewdef(");
			formatStringLiteral(query, tblinfo[i].relname);
			appendPQExpBuffer(query, ") as viewdef");
1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022
			res2 = PQexec(g_conn, query->data);
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
				fprintf(stderr, "getTables(): SELECT (for VIEW DEFINITION) failed.  "
							"Explanation from backend: %s",
							PQerrorMessage(g_conn));
				exit_nicely(g_conn);
			}

			if (PQntuples(res2) != 1) 
			{
				if (PQntuples(res2) < 1)
				{
					fprintf(stderr, "getTables(): SELECT (for VIEW %s) returned no definitions",
								tblinfo[i].relname);
				} else {
					fprintf(stderr, "getTables(): SELECT (for VIEW %s) returned more than 1 definition",
								tblinfo[i].relname);
				}
				exit_nicely(g_conn);
			}

			tblinfo[i].viewdef = strdup(PQgetvalue(res2, 0, 0));

			if (strlen(tblinfo[i].viewdef) == 0) 
			{
				fprintf(stderr, "getTables(): SELECT (for VIEW %s) returned empty definition",
							tblinfo[i].relname);
				exit_nicely(g_conn);
			}
		}
		else
			tblinfo[i].viewdef = NULL;

B
Bruce Momjian 已提交
2023 2024 2025
		/*
		 * Exclude inherited CHECKs from CHECK constraints total. If a
		 * constraint matches by name and condition with a constraint
2026 2027 2028 2029
		 * belonging to a parent class, we assume it was inherited.
		 */
		if (tblinfo[i].ncheck > 0)
		{
B
Bruce Momjian 已提交
2030
			PGresult   *res2;
2031 2032
			int			ntups2;

B
Bruce Momjian 已提交
2033
			if (g_verbose)
2034 2035 2036 2037 2038 2039
				fprintf(stderr, "%s excluding inherited CHECK constraints "
						"for relation: '%s' %s\n",
						g_comment_start,
						tblinfo[i].relname,
						g_comment_end);

B
Hi, all  
Bruce Momjian 已提交
2040 2041
			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "SELECT rcname from pg_relcheck, pg_inherits as i "
2042 2043 2044 2045 2046 2047 2048 2049
							  "where rcrelid = '%s'::oid "
							  " and rcrelid = i.inhrelid"
							  " and exists "
							  "  (select * from pg_relcheck as c "
							  "    where c.rcname = pg_relcheck.rcname "
							  "      and c.rcsrc = pg_relcheck.rcsrc "
							  "      and c.rcrelid = i.inhparent) ",
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2050
			res2 = PQexec(g_conn, query->data);
2051 2052 2053
			if (!res2 ||
				PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
2054 2055
				fprintf(stderr, "getTables(): SELECT (for inherited CHECK) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070
				exit_nicely(g_conn);
			}
			ntups2 = PQntuples(res2);
			tblinfo[i].ncheck -= ntups2;
			if (tblinfo[i].ncheck < 0)
			{
				fprintf(stderr, "getTables(): found more inherited CHECKs than total for "
						"relation %s\n",
						tblinfo[i].relname);
				exit_nicely(g_conn);
			}
			PQclear(res2);
		}

		/* Get non-inherited CHECK constraints, if any */
V
Vadim B. Mikheev 已提交
2071 2072 2073
		if (tblinfo[i].ncheck > 0)
		{
			PGresult   *res2;
2074 2075
			int			i_rcname,
						i_rcsrc;
V
Vadim B. Mikheev 已提交
2076 2077
			int			ntups2;
			int			i2;
2078

V
Vadim B. Mikheev 已提交
2079
			if (g_verbose)
2080
				fprintf(stderr, "%s finding CHECK constraints for relation: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2081 2082 2083
						g_comment_start,
						tblinfo[i].relname,
						g_comment_end);
2084

B
Hi, all  
Bruce Momjian 已提交
2085 2086
			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
2087 2088 2089 2090 2091 2092 2093 2094
							  "where rcrelid = '%s'::oid "
							  "   and not exists "
				   "  (select * from pg_relcheck as c, pg_inherits as i "
							  "   where i.inhrelid = pg_relcheck.rcrelid "
							  "     and c.rcname = pg_relcheck.rcname "
							  "     and c.rcsrc = pg_relcheck.rcsrc "
							  "     and c.rcrelid = i.inhparent) ",
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2095
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2096
			if (!res2 ||
2097
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2098
			{
B
Bruce Momjian 已提交
2099 2100
				fprintf(stderr, "getTables(): SELECT (for CHECK) failed.  "
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2101 2102 2103 2104 2105
				exit_nicely(g_conn);
			}
			ntups2 = PQntuples(res2);
			if (ntups2 != tblinfo[i].ncheck)
			{
2106
				fprintf(stderr, "getTables(): relation '%s': %d CHECKs were expected, but got %d\n",
2107
						tblinfo[i].relname, tblinfo[i].ncheck, ntups2);
V
Vadim B. Mikheev 已提交
2108 2109 2110 2111
				exit_nicely(g_conn);
			}
			i_rcname = PQfnumber(res2, "rcname");
			i_rcsrc = PQfnumber(res2, "rcsrc");
2112
			tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
V
Vadim B. Mikheev 已提交
2113 2114
			for (i2 = 0; i2 < ntups2; i2++)
			{
B
Bruce Momjian 已提交
2115 2116
				const char *name = PQgetvalue(res2, i2, i_rcname);
				const char *expr = PQgetvalue(res2, i2, i_rcsrc);
2117

B
Hi, all  
Bruce Momjian 已提交
2118
				resetPQExpBuffer(query);
2119 2120
				if (name[0] != '$')
				{
2121 2122
					appendPQExpBuffer(query, "CONSTRAINT %s ",
									  fmtId(name, force_quotes));
B
Bruce Momjian 已提交
2123
				}
2124
				appendPQExpBuffer(query, "CHECK (%s)", expr);
B
Hi, all  
Bruce Momjian 已提交
2125
				tblinfo[i].check_expr[i2] = strdup(query->data);
V
Vadim B. Mikheev 已提交
2126 2127 2128 2129 2130
			}
			PQclear(res2);
		}
		else
			tblinfo[i].check_expr = NULL;
2131

2132 2133
		/* Get primary key */
		if (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0)
2134
		{
2135
			PGresult   *res2;
B
Bruce Momjian 已提交
2136

B
Hi, all  
Bruce Momjian 已提交
2137
			resetPQExpBuffer(query);
B
Bruce Momjian 已提交
2138
			appendPQExpBuffer(query,
2139
							  "SELECT Oid FROM pg_index i WHERE i.indisprimary AND i.indrelid = %s ",
2140
							  tblinfo[i].oid);
2141
			res2 = PQexec(g_conn, query->data);
B
Bruce Momjian 已提交
2142 2143
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
2144
				fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY) failed.  Explanation from backend: %s\n",
2145
						PQerrorMessage(g_conn));
B
Bruce Momjian 已提交
2146 2147
				exit_nicely(g_conn);
			}
2148

2149 2150 2151
			if (PQntuples(res2) > 1) {
				fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY) produced more than one row.\n");
				exit_nicely(g_conn);
2152 2153
			}

2154 2155 2156 2157
			if (PQntuples(res2) == 1) {
				tblinfo[i].pkIndexOid = strdup(PQgetvalue(res2, 0, 0));
			} else {
				tblinfo[i].pkIndexOid = NULL;
2158
			}
2159

2160
		}
2161
		else
2162
			tblinfo[i].pkIndexOid = NULL;
B
Bruce Momjian 已提交
2163

2164
		/* Get primary key name (if primary key exist) */
2165
		if (tblinfo[i].pkIndexOid != NULL)
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206
		{
			PGresult   *res2;
			int		   n;

			resetPQExpBuffer(query);
			appendPQExpBuffer(query,
							  "SELECT c.relname "
							  "FROM pg_index i, pg_class c "
							  "WHERE i.indrelid = %s"
							  "AND   i.indisprimary "
							  "AND   c.oid = i.indexrelid ",
							  tblinfo[i].oid);
			res2 = PQexec(g_conn, query->data);
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
				fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY NAME) failed.  Explanation from backend: %s",
						PQerrorMessage(g_conn));
				exit_nicely(g_conn);
			}

			n = PQntuples(res2);
			if (n != 1)
			{
				fprintf(stderr,
						"getTables(): SELECT (for PRIMARY KEY NAME) failed. This is impossible but object with OID == %s have %d primary keys.\n",
						tblinfo[i].oid,
						n);
				exit_nicely(g_conn);
			}

			tblinfo[i].primary_key_name =
				strdup(fmtId(PQgetvalue(res2, 0, 0), force_quotes));
			if (tblinfo[i].primary_key_name == NULL)
			{
				perror("strdup");
				exit(1);
			}
		}
		else
			tblinfo[i].primary_key_name = NULL;

V
Vadim B. Mikheev 已提交
2207 2208 2209 2210
		/* Get Triggers */
		if (tblinfo[i].ntrig > 0)
		{
			PGresult   *res2;
B
Bruce,  
Bruce Momjian 已提交
2211
			int			i_tgoid,
2212
						i_tgname,
2213 2214 2215
						i_tgfoid,
						i_tgtype,
						i_tgnargs,
2216 2217 2218 2219 2220
						i_tgargs,
						i_tgisconstraint,
						i_tgconstrname,
						i_tgdeferrable,
						i_tginitdeferred;
V
Vadim B. Mikheev 已提交
2221 2222
			int			ntups2;
			int			i2;
2223

V
Vadim B. Mikheev 已提交
2224
			if (g_verbose)
2225
				fprintf(stderr, "%s finding Triggers for relation: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2226 2227 2228
						g_comment_start,
						tblinfo[i].relname,
						g_comment_end);
2229

B
Hi, all  
Bruce Momjian 已提交
2230
			resetPQExpBuffer(query);
2231
			appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, tgisconstraint, tgconstrname, tgdeferrable, tginitdeferred, oid "
2232 2233 2234
							  "from pg_trigger "
							  "where tgrelid = '%s'::oid ",
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2235
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2236
			if (!res2 ||
2237
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2238
			{
B
Bruce Momjian 已提交
2239 2240
				fprintf(stderr, "getTables(): SELECT (for TRIGGER) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2241 2242 2243 2244 2245
				exit_nicely(g_conn);
			}
			ntups2 = PQntuples(res2);
			if (ntups2 != tblinfo[i].ntrig)
			{
2246
				fprintf(stderr, "getTables(): relation '%s': %d Triggers were expected, but got %d\n",
2247
						tblinfo[i].relname, tblinfo[i].ntrig, ntups2);
V
Vadim B. Mikheev 已提交
2248 2249 2250 2251 2252 2253 2254
				exit_nicely(g_conn);
			}
			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 已提交
2255
			i_tgoid = PQfnumber(res2, "oid");
2256 2257 2258 2259 2260
			i_tgisconstraint = PQfnumber(res2, "tgisconstraint");
			i_tgconstrname = PQfnumber(res2, "tgconstrname");
			i_tgdeferrable = PQfnumber(res2, "tgdeferrable");
			i_tginitdeferred = PQfnumber(res2, "tginitdeferred");

B
Bruce Momjian 已提交
2261
			tblinfo[i].triggers = (TrigInfo*) malloc(ntups2 * sizeof(TrigInfo));
B
Hi, all  
Bruce Momjian 已提交
2262 2263
			resetPQExpBuffer(query);
			for (i2 = 0; i2 < ntups2; i2++)
V
Vadim B. Mikheev 已提交
2264
			{
2265
				const char *tgfuncoid = PQgetvalue(res2, i2, i_tgfoid);
2266
				char	   *tgfunc = NULL;
2267 2268
				int2		tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
				int			tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
B
Bruce Momjian 已提交
2269
				const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
2270 2271 2272
				int			tgisconstraint;
				int			tgdeferrable;
				int			tginitdeferred;
B
Bruce Momjian 已提交
2273
				const char *p;
2274 2275
				int			findx;

2276
				if (strcmp(PQgetvalue(res2, i2, i_tgisconstraint), "f") == 0)
2277
					tgisconstraint = 0;
2278
				else
2279
					tgisconstraint = 1;
2280 2281

				if (strcmp(PQgetvalue(res2, i2, i_tgdeferrable), "f") == 0)
2282
					tgdeferrable = 0;
2283
				else
2284
					tgdeferrable = 1;
2285 2286

				if (strcmp(PQgetvalue(res2, i2, i_tginitdeferred), "f") == 0)
2287
					tginitdeferred = 0;
2288
				else
2289
					tginitdeferred = 1;
2290

V
Vadim B. Mikheev 已提交
2291 2292
				for (findx = 0; findx < numFuncs; findx++)
				{
2293
					if (strcmp(finfo[findx].oid, tgfuncoid) == 0 &&
2294
						finfo[findx].nargs == 0 &&
V
Vadim B. Mikheev 已提交
2295 2296 2297
						strcmp(finfo[findx].prorettype, "0") == 0)
						break;
				}
2298

V
Vadim B. Mikheev 已提交
2299 2300
				if (findx == numFuncs)
				{
2301
					PGresult   *r;
2302
					int			numFuncs;
2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319

					/*
					 * 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)
					{
2320 2321 2322 2323 2324 2325 2326 2327 2328 2329
						fprintf(stderr, "getTables(): SELECT (funcname) failed for trigger %s.  Explanation from backend: '%s'.\n", 
									PQgetvalue(res2, i2, i_tgname), PQerrorMessage(g_conn));
						exit_nicely(g_conn);
					}

					/* Sanity: Check we got only one tuple */
					numFuncs = PQntuples(r);
					if (numFuncs != 1) {
						fprintf(stderr, "getTables(): SELECT (funcname) for trigger %s returned %d tuples. Expected 1.\n", 
									PQgetvalue(res2, i2, i_tgname), numFuncs);
2330 2331
						exit_nicely(g_conn);
					}
2332

2333
					tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
2334
					PQclear(r);
2335
				}
2336
				else
2337
					tgfunc = strdup(finfo[findx].proname);
B
Bruce Momjian 已提交
2338 2339

				appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
2340
									fmtId(PQgetvalue(res2, i2, i_tgname),
B
Bruce Momjian 已提交
2341 2342 2343
									force_quotes));
				appendPQExpBuffer(delqry, "ON %s;\n",
									fmtId(tblinfo[i].relname, force_quotes));
2344

B
Hi, all  
Bruce Momjian 已提交
2345
				resetPQExpBuffer(query);
2346 2347 2348 2349 2350
				if (tgisconstraint)
				{
					appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgconstrname), force_quotes));
				}
2351 2352
				else
				{
2353 2354 2355
					appendPQExpBuffer(query, "CREATE TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
				}
B
Bruce Momjian 已提交
2356
				appendPQExpBufferChar(query, ' ');
V
Vadim B. Mikheev 已提交
2357 2358 2359
				/* Trigger type */
				findx = 0;
				if (TRIGGER_FOR_BEFORE(tgtype))
B
Hi, all  
Bruce Momjian 已提交
2360
					appendPQExpBuffer(query, "BEFORE");
V
Vadim B. Mikheev 已提交
2361
				else
B
Hi, all  
Bruce Momjian 已提交
2362
					appendPQExpBuffer(query, "AFTER");
V
Vadim B. Mikheev 已提交
2363 2364
				if (TRIGGER_FOR_INSERT(tgtype))
				{
B
Hi, all  
Bruce Momjian 已提交
2365
					appendPQExpBuffer(query, " INSERT");
V
Vadim B. Mikheev 已提交
2366 2367 2368 2369 2370
					findx++;
				}
				if (TRIGGER_FOR_DELETE(tgtype))
				{
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2371
						appendPQExpBuffer(query, " OR DELETE");
V
Vadim B. Mikheev 已提交
2372
					else
B
Hi, all  
Bruce Momjian 已提交
2373
						appendPQExpBuffer(query, " DELETE");
V
Vadim B. Mikheev 已提交
2374 2375 2376
					findx++;
				}
				if (TRIGGER_FOR_UPDATE(tgtype))
2377
				{
V
Vadim B. Mikheev 已提交
2378
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2379
						appendPQExpBuffer(query, " OR UPDATE");
V
Vadim B. Mikheev 已提交
2380
					else
B
Hi, all  
Bruce Momjian 已提交
2381
						appendPQExpBuffer(query, " UPDATE");
2382
				}
2383 2384
				appendPQExpBuffer(query, " ON %s ", fmtId(tblinfo[i].relname, force_quotes));

2385
				if (tgisconstraint)
2386
				{
2387
					if (!tgdeferrable)
2388 2389 2390 2391
						appendPQExpBuffer(query, " NOT");
					appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
					if (tginitdeferred)
						appendPQExpBuffer(query, "DEFERRED");
2392
					else
2393
						appendPQExpBuffer(query, "IMMEDIATE");
2394

2395 2396 2397
				}

				appendPQExpBuffer(query, " FOR EACH ROW");
2398 2399
				appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
								  fmtId(tgfunc, force_quotes));
V
Vadim B. Mikheev 已提交
2400 2401
				for (findx = 0; findx < tgnargs; findx++)
				{
2402
					const char *s;
2403 2404

					for (p = tgargs;;)
V
Vadim B. Mikheev 已提交
2405
					{
2406
						p = strchr(p, '\\');
V
Vadim B. Mikheev 已提交
2407 2408
						if (p == NULL)
						{
B
Bruce Momjian 已提交
2409 2410
							fprintf(stderr, "getTables(): relation '%s': bad argument "
									"string (%s) for trigger '%s'\n",
2411 2412 2413
									tblinfo[i].relname,
									PQgetvalue(res2, i2, i_tgargs),
									PQgetvalue(res2, i2, i_tgname));
V
Vadim B. Mikheev 已提交
2414 2415 2416 2417 2418 2419 2420 2421
							exit_nicely(g_conn);
						}
						p++;
						if (*p == '\\')
						{
							p++;
							continue;
						}
2422
						if (p[0] == '0' && p[1] == '0' && p[2] == '0')
V
Vadim B. Mikheev 已提交
2423 2424 2425
							break;
					}
					p--;
2426
					appendPQExpBufferChar(query, '\'');
B
Bruce Momjian 已提交
2427
					for (s = tgargs; s < p;)
V
Vadim B. Mikheev 已提交
2428 2429
					{
						if (*s == '\'')
2430 2431
							appendPQExpBufferChar(query, '\\');
						appendPQExpBufferChar(query, *s++);
V
Vadim B. Mikheev 已提交
2432
					}
B
Bruce Momjian 已提交
2433 2434
					appendPQExpBufferChar(query, '\'');
					appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
V
Vadim B. Mikheev 已提交
2435 2436
					tgargs = p + 4;
				}
B
Hi, all  
Bruce Momjian 已提交
2437
				appendPQExpBuffer(query, ");\n");
2438

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

				/*** Initialize trcomments and troids ***/
2442

B
Bruce,  
Bruce Momjian 已提交
2443
				resetPQExpBuffer(query);
2444 2445
				appendPQExpBuffer(query, "TRIGGER %s ",
					fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
B
Bruce,  
Bruce Momjian 已提交
2446
				appendPQExpBuffer(query, "ON %s",
2447
								fmtId(tblinfo[i].relname, force_quotes));
B
Bruce Momjian 已提交
2448 2449 2450 2451
				tblinfo[i].triggers[i2].tgcomment = strdup(query->data);
				tblinfo[i].triggers[i2].oid = strdup(PQgetvalue(res2, i2, i_tgoid));
				tblinfo[i].triggers[i2].tgname = strdup(fmtId(PQgetvalue(res2, i2, i_tgname),false));
				tblinfo[i].triggers[i2].tgdel = strdup(delqry->data);
B
Bruce,  
Bruce Momjian 已提交
2452

2453 2454
				if (tgfunc)
					free(tgfunc);
V
Vadim B. Mikheev 已提交
2455 2456 2457 2458
			}
			PQclear(res2);
		}
		else
B
Bruce,  
Bruce Momjian 已提交
2459
		{
V
Vadim B. Mikheev 已提交
2460
			tblinfo[i].triggers = NULL;
B
Bruce,  
Bruce Momjian 已提交
2461
		}
2462

2463 2464 2465 2466 2467
	}

	PQclear(res);

	return tblinfo;
2468 2469 2470 2471 2472

}

/*
 * getInherits
2473
 *	  read all the inheritance information
2474 2475
 * from the system catalogs return them in the InhInfo* structure
 *
2476 2477
 * numInherits is set to the number of tables read in
 *
2478 2479
 *
 */
2480
InhInfo    *
2481 2482
getInherits(int *numInherits)
{
2483
	PGresult   *res;
2484 2485
	int			ntups;
	int			i;
2486 2487
	PQExpBuffer query = createPQExpBuffer();
	InhInfo    *inhinfo;
2488

2489
	int			i_inhrelid;
2490
	int			i_inhparent;
2491 2492 2493

	/* find all the inheritance information */

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

B
Hi, all  
Bruce Momjian 已提交
2496
	res = PQexec(g_conn, query->data);
2497 2498 2499
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2500 2501
		fprintf(stderr, "getInherits(): SELECT failed.  Explanation from backend: '%s'.\n", 
				PQerrorMessage(g_conn));
2502 2503 2504 2505 2506 2507 2508 2509 2510
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numInherits = ntups;

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

2511
	i_inhrelid = PQfnumber(res, "inhrelid");
2512 2513 2514 2515
	i_inhparent = PQfnumber(res, "inhparent");

	for (i = 0; i < ntups; i++)
	{
2516
		inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
2517 2518 2519 2520 2521
		inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
	}

	PQclear(res);
	return inhinfo;
2522 2523 2524 2525
}

/*
 * getTableAttrs -
2526 2527
 *	  for each table in tblinfo, read its attributes types and names
 *
2528
 * this is implemented in a very inefficient way right now, looping
2529
 * through the tblinfo and doing a join per table to find the attrs and their
2530 2531
 * types
 *
2532
 *	modifies tblinfo
2533 2534
 */
void
2535
getTableAttrs(TableInfo *tblinfo, int numTables)
2536
{
2537 2538
	int			i,
				j;
2539
	PQExpBuffer q = createPQExpBuffer();
2540 2541
	int			i_attname;
	int			i_typname;
2542
	int			i_atttypmod;
2543
	int			i_attnotnull;
V
Vadim B. Mikheev 已提交
2544
	int			i_atthasdef;
2545
	int			i_attoid;
2546
	int			i_atttypedefn;
2547
	PGresult   *res;
2548
	int			ntups;
2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563

	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)
2564
			fprintf(stderr, "%s finding the attrs and types for table: '%s' %s\n",
2565 2566 2567 2568
					g_comment_start,
					tblinfo[i].relname,
					g_comment_end);

B
Hi, all  
Bruce Momjian 已提交
2569
		resetPQExpBuffer(q);
B
Bruce,  
Bruce Momjian 已提交
2570
		appendPQExpBuffer(q, "SELECT a.oid as attoid, a.attnum, a.attname, t.typname, a.atttypmod, "
2571
						  "a.attnotnull, a.atthasdef, format_type(a.atttypid, a.atttypmod) as atttypedefn "
2572 2573 2574 2575
						  "from pg_attribute a, pg_type t "
				   "where a.attrelid = '%s'::oid and a.atttypid = t.oid "
						  "and a.attnum > 0 order by attnum",
						  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2576
		res = PQexec(g_conn, q->data);
2577 2578 2579
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
B
Bruce Momjian 已提交
2580 2581
			fprintf(stderr, "getTableAttrs(): SELECT failed.  "
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2582 2583 2584 2585 2586
			exit_nicely(g_conn);
		}

		ntups = PQntuples(res);

B
Bruce,  
Bruce Momjian 已提交
2587
		i_attoid = PQfnumber(res, "attoid");
2588 2589
		i_attname = PQfnumber(res, "attname");
		i_typname = PQfnumber(res, "typname");
2590
		i_atttypmod = PQfnumber(res, "atttypmod");
2591
		i_attnotnull = PQfnumber(res, "attnotnull");
V
Vadim B. Mikheev 已提交
2592
		i_atthasdef = PQfnumber(res, "atthasdef");
2593
		i_atttypedefn = PQfnumber(res, "atttypedefn");
2594 2595

		tblinfo[i].numatts = ntups;
B
Bruce,  
Bruce Momjian 已提交
2596
		tblinfo[i].attoids = (char **) malloc(ntups * sizeof(char *));
2597
		tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
2598
		tblinfo[i].atttypedefns = (char **) malloc(ntups * sizeof(char *));
2599
		tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
2600
		tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
2601 2602
		tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
		tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
V
Vadim B. Mikheev 已提交
2603
		tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
2604 2605 2606 2607
		tblinfo[i].parentRels = NULL;
		tblinfo[i].numParents = 0;
		for (j = 0; j < ntups; j++)
		{
B
Bruce,  
Bruce Momjian 已提交
2608
			tblinfo[i].attoids[j] = strdup(PQgetvalue(res, j, i_attoid));
2609
			tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
2610
			tblinfo[i].atttypedefns[j] = strdup(PQgetvalue(res, j, i_atttypedefn));
2611
			tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
2612
			tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
2613 2614 2615
			tblinfo[i].inhAttrs[j] = 0; /* this flag is set in
										 * flagInhAttrs() */
			tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't') ? true : false;
V
Vadim B. Mikheev 已提交
2616 2617 2618
			if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
			{
				PGresult   *res2;
2619
				int			numAttr;
2620

V
Vadim B. Mikheev 已提交
2621
				if (g_verbose)
2622
					fprintf(stderr, "%s finding DEFAULT expression for attr: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2623 2624 2625
							g_comment_start,
							tblinfo[i].attnames[j],
							g_comment_end);
2626

B
Hi, all  
Bruce Momjian 已提交
2627 2628
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
2629 2630
							 "where adrelid = '%s'::oid and adnum = %d ",
								  tblinfo[i].oid, j + 1);
B
Hi, all  
Bruce Momjian 已提交
2631
				res2 = PQexec(g_conn, q->data);
V
Vadim B. Mikheev 已提交
2632
				if (!res2 ||
2633
					PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2634
				{
B
Bruce Momjian 已提交
2635 2636
					fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2637 2638
					exit_nicely(g_conn);
				}
2639 2640 2641 2642 2643 2644 2645 2646 2647

				/* Sanity: Check we got only one tuple */
				numAttr = PQntuples(res2);
				if (numAttr != 1) {
					fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) for attr %s returned %d tuples. Expected 1.\n", 
										tblinfo[i].attnames[j], numAttr);
					exit_nicely(g_conn);
				}

V
Vadim B. Mikheev 已提交
2648 2649 2650 2651 2652
				tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
				PQclear(res2);
			}
			else
				tblinfo[i].adef_expr[j] = NULL;
2653 2654 2655
		}
		PQclear(res);
	}
2656 2657 2658 2659 2660
}


/*
 * getIndices
2661
 *	  read all the user-defined indices information
2662 2663
 * from the system catalogs return them in the InhInfo* structure
 *
2664 2665
 * numIndices is set to the number of indices read in
 *
2666 2667
 *
 */
2668
IndInfo    *
2669 2670
getIndices(int *numIndices)
{
2671
	int			i;
2672
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2673
	PGresult   *res;
2674
	int			ntups;
B
Bruce Momjian 已提交
2675
	IndInfo    *indinfo;
2676 2677 2678 2679 2680 2681 2682 2683

	int			i_indexrelname;
	int			i_indrelname;
	int			i_indamname;
	int			i_indproc;
	int			i_indkey;
	int			i_indclass;
	int			i_indisunique;
2684
	int			i_indoid;
2685 2686
	int			i_oid;
	int			i_indisprimary;
2687 2688 2689 2690 2691

	/*
	 * find all the user-defined indices. We do not handle partial
	 * indices.
	 *
2692
	 * Notice we skip indices on system classes
2693 2694 2695 2696
	 *
	 * this is a 4-way join !!
	 */

B
Hi, all  
Bruce Momjian 已提交
2697
	appendPQExpBuffer(query,
2698
					  "SELECT i.oid, t1.oid as indoid, t1.relname as indexrelname, t2.relname as indrelname, "
2699
					  "i.indproc, i.indkey, i.indclass, "
2700
					  "a.amname as indamname, i.indisunique, i.indisprimary "
2701 2702 2703
					"from pg_index i, pg_class t1, pg_class t2, pg_am a "
				   "WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid "
					  "and t1.relam = a.oid and i.indexrelid > '%u'::oid "
2704
					  "and t2.relname !~ '^pg_' ",
2705
					  g_last_builtin_oid);
2706

B
Hi, all  
Bruce Momjian 已提交
2707
	res = PQexec(g_conn, query->data);
2708 2709 2710
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2711 2712
		fprintf(stderr, "getIndices(): SELECT failed.  "
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2713 2714 2715 2716 2717 2718 2719 2720 2721
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numIndices = ntups;

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

2722 2723
	memset((char *) indinfo, 0, ntups * sizeof(IndInfo));

2724
	i_oid = PQfnumber(res, "oid");
B
Bruce,  
Bruce Momjian 已提交
2725
	i_indoid = PQfnumber(res, "indoid");
2726 2727 2728 2729 2730 2731 2732
	i_indexrelname = PQfnumber(res, "indexrelname");
	i_indrelname = PQfnumber(res, "indrelname");
	i_indamname = PQfnumber(res, "indamname");
	i_indproc = PQfnumber(res, "indproc");
	i_indkey = PQfnumber(res, "indkey");
	i_indclass = PQfnumber(res, "indclass");
	i_indisunique = PQfnumber(res, "indisunique");
2733
	i_indisprimary = PQfnumber(res, "indisprimary");
2734 2735 2736

	for (i = 0; i < ntups; i++)
	{
2737
		indinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
B
Bruce,  
Bruce Momjian 已提交
2738
		indinfo[i].indoid = strdup(PQgetvalue(res, i, i_indoid));
2739 2740 2741 2742
		indinfo[i].indexrelname = strdup(PQgetvalue(res, i, i_indexrelname));
		indinfo[i].indrelname = strdup(PQgetvalue(res, i, i_indrelname));
		indinfo[i].indamname = strdup(PQgetvalue(res, i, i_indamname));
		indinfo[i].indproc = strdup(PQgetvalue(res, i, i_indproc));
2743 2744 2745 2746 2747 2748
		parseNumericArray(PQgetvalue(res, i, i_indkey),
						  indinfo[i].indkey,
						  INDEX_MAX_KEYS);
		parseNumericArray(PQgetvalue(res, i, i_indclass),
						  indinfo[i].indclass,
						  INDEX_MAX_KEYS);
2749
		indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
2750
		indinfo[i].indisprimary = strdup(PQgetvalue(res, i, i_indisprimary));
2751 2752 2753
	}
	PQclear(res);
	return indinfo;
2754 2755
}

B
Bruce,  
Bruce Momjian 已提交
2756
/*------------------------------------------------------------------
2757
 * dumpComments --
B
Bruce,  
Bruce Momjian 已提交
2758
 *
2759
 * This routine is used to dump any comments associated with the
B
Bruce,  
Bruce Momjian 已提交
2760 2761 2762 2763
 * oid handed to this routine. The routine takes a constant character
 * string for the target part of the object and the oid of the object
 * whose comments are to be dumped. It is perfectly acceptable
 * to hand an oid to this routine which has not been commented. In
2764
 * addition, the routine takes the stdio FILE handle to which the
B
Bruce,  
Bruce Momjian 已提交
2765 2766 2767 2768
 * output should be written.
 *------------------------------------------------------------------
*/

T
Tom Lane 已提交
2769
static void
B
Bruce Momjian 已提交
2770
dumpComment(Archive *fout, const char *target, const char *oid)
2771
{
B
Bruce,  
Bruce Momjian 已提交
2772

2773
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
2774
	PQExpBuffer query;
2775
	int			i_description;
B
Bruce,  
Bruce Momjian 已提交
2776 2777 2778 2779 2780 2781 2782 2783 2784 2785

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

	query = createPQExpBuffer();
	appendPQExpBuffer(query, "SELECT description FROM pg_description WHERE objoid = ");
	appendPQExpBuffer(query, oid);

	/*** Execute query ***/

	res = PQexec(g_conn, query->data);
2786 2787
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce,  
Bruce Momjian 已提交
2788 2789 2790 2791 2792 2793 2794
		fprintf(stderr, "DumpComment: SELECT failed: '%s'.\n",
				PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

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

2795 2796
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2797
		i_description = PQfnumber(res, "description");
B
Bruce Momjian 已提交
2798
		resetPQExpBuffer(query);
2799 2800 2801
		appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
		formatStringLiteral(query, PQgetvalue(res, 0, i_description));
		appendPQExpBuffer(query, ";\n");
B
Bruce Momjian 已提交
2802 2803

		ArchiveEntry(fout, oid, target, "COMMENT", NULL, query->data, "" /*Del*/,
2804
					   "" /* Copy */, "" /*Owner*/, NULL, NULL);	
B
Bruce Momjian 已提交
2805

B
Bruce,  
Bruce Momjian 已提交
2806 2807 2808 2809 2810
	}

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

	PQclear(res);
2811

B
Bruce,  
Bruce Momjian 已提交
2812 2813 2814
}

/*------------------------------------------------------------------
2815
 * dumpDBComment --
B
Bruce,  
Bruce Momjian 已提交
2816
 *
2817 2818
 * 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 已提交
2819 2820 2821 2822 2823
 * to dump the schema of the database, then this is the first
 * statement issued.
 *------------------------------------------------------------------
*/

2824
void
B
Bruce Momjian 已提交
2825
dumpDBComment(Archive *fout)
2826
{
B
Bruce,  
Bruce Momjian 已提交
2827

2828
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
2829
	PQExpBuffer query;
2830
	int			i_oid;
B
Bruce,  
Bruce Momjian 已提交
2831 2832 2833 2834

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

	query = createPQExpBuffer();
2835 2836
	appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = ");
	formatStringLiteral(query, PQdb(g_conn));
B
Bruce,  
Bruce Momjian 已提交
2837 2838 2839 2840

	/*** Execute query ***/

	res = PQexec(g_conn, query->data);
2841 2842
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce,  
Bruce Momjian 已提交
2843 2844 2845 2846 2847 2848 2849
		fprintf(stderr, "dumpDBComment: SELECT failed: '%s'.\n",
				PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

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

2850 2851
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2852 2853 2854 2855 2856 2857 2858 2859 2860
		i_oid = PQfnumber(res, "oid");
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "DATABASE %s", fmtId(PQdb(g_conn), force_quotes));
		dumpComment(fout, query->data, PQgetvalue(res, 0, i_oid));
	}

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

	PQclear(res);
2861

B
Bruce,  
Bruce Momjian 已提交
2862 2863
}

2864 2865
/*
 * dumpTypes
2866
 *	  writes out to fout the queries to recreate all the user-defined types
2867 2868 2869
 *
 */
void
B
Bruce Momjian 已提交
2870
dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
2871
		  TypeInfo *tinfo, int numTypes)
2872
{
2873
	int			i;
2874
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
2875
	PQExpBuffer	delq = createPQExpBuffer();
2876
	int			funcInd;
2877 2878 2879 2880 2881

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

		/* skip all the builtin types */
2882
		if (atooid(tinfo[i].oid) <= g_last_builtin_oid)
2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905
			continue;

		/* skip relation types */
		if (atoi(tinfo[i].typrelid) != 0)
			continue;

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

		/*
		 * 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)
			dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);

		funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
		if (funcInd != -1)
			dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);

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

B
Hi, all  
Bruce Momjian 已提交
2908 2909
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
2910
						  "CREATE TYPE %s "
2911
						  "( internallength = %s, externallength = %s,",
2912 2913
						  fmtId(tinfo[i].typname, force_quotes),
						  tinfo[i].typlen,
2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924
						  tinfo[i].typprtlen);
		/* 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));
		appendPQExpBuffer(q, " receive = %s, default = ",
						  fmtId(tinfo[i].typreceive, force_quotes));
		formatStringLiteral(q, tinfo[i].typdefault);
2925 2926 2927

		if (tinfo[i].isArray)
		{
2928
			char	   *elemType;
2929

2930
			elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
2931 2932
			appendPQExpBuffer(q, ", element = %s, delimiter = ", elemType);
			formatStringLiteral(q, tinfo[i].typdelim);
2933 2934
		}
		if (tinfo[i].passedbyvalue)
B
Hi, all  
Bruce Momjian 已提交
2935
			appendPQExpBuffer(q, ",passedbyvalue);\n");
2936
		else
B
Hi, all  
Bruce Momjian 已提交
2937
			appendPQExpBuffer(q, ");\n");
2938

B
Bruce Momjian 已提交
2939
		ArchiveEntry(fout, tinfo[i].oid, fmtId(tinfo[i].typname, force_quotes), "TYPE", NULL,
2940
						q->data, delq->data, "", tinfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
2941 2942 2943 2944

		/*** Dump Type Comments ***/

		resetPQExpBuffer(q);
B
Bruce Momjian 已提交
2945 2946
		resetPQExpBuffer(delq);

B
Bruce,  
Bruce Momjian 已提交
2947 2948 2949
		appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo[i].typname, force_quotes));
		dumpComment(fout, q->data, tinfo[i].oid);

B
Bruce Momjian 已提交
2950
		resetPQExpBuffer(q);
2951
	}
2952 2953
}

2954 2955
/*
 * dumpProcLangs
B
Bruce Momjian 已提交
2956
 *		  writes out to fout the queries to recreate user-defined procedural languages
2957 2958 2959
 *
 */
void
B
Bruce Momjian 已提交
2960
dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
B
Bruce Momjian 已提交
2961
			  TypeInfo *tinfo, int numTypes)
2962
{
2963 2964
	PGresult   *res;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2965 2966
	PQExpBuffer defqry = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
2967
	int			ntups;
B
Bruce Momjian 已提交
2968
	int			i_oid;
2969 2970 2971 2972
	int			i_lanname;
	int			i_lanpltrusted;
	int			i_lanplcallfoid;
	int			i_lancompiler;
2973
	Oid			lanoid;
2974 2975 2976
	char	   *lanname;
	char	   *lancompiler;
	const char *lanplcallfoid;
2977 2978 2979
	int			i,
				fidx;

B
Bruce Momjian 已提交
2980
	appendPQExpBuffer(query, "SELECT oid, * FROM pg_language "
2981 2982
					  "WHERE lanispl "
					  "ORDER BY oid");
B
Hi, all  
Bruce Momjian 已提交
2983
	res = PQexec(g_conn, query->data);
2984 2985 2986
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2987
		fprintf(stderr, "dumpProcLangs(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2988 2989 2990 2991
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);

B
Bruce Momjian 已提交
2992 2993 2994 2995
	i_lanname = PQfnumber(res, "lanname");
	i_lanpltrusted = PQfnumber(res, "lanpltrusted");
	i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
	i_lancompiler = PQfnumber(res, "lancompiler");
B
Bruce Momjian 已提交
2996
	i_oid = PQfnumber(res, "oid");
2997

B
Bruce Momjian 已提交
2998 2999
	for (i = 0; i < ntups; i++)
	{
3000
		lanoid = atooid(PQgetvalue(res, i, i_oid));
3001 3002 3003
		if (lanoid <= g_last_builtin_oid)
			continue;

3004
		lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
3005 3006


3007 3008 3009 3010 3011 3012 3013
		for (fidx = 0; fidx < numFuncs; fidx++)
		{
			if (!strcmp(finfo[fidx].oid, lanplcallfoid))
				break;
		}
		if (fidx >= numFuncs)
		{
B
Bruce Momjian 已提交
3014 3015
			fprintf(stderr, "dumpProcLangs(): handler procedure for "
						"language %s not found\n", PQgetvalue(res, i, i_lanname));
3016 3017 3018 3019 3020
			exit_nicely(g_conn);
		}

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

3021 3022
		lanname = PQgetvalue(res, i, i_lanname);
		lancompiler = PQgetvalue(res, i, i_lancompiler);
3023

3024 3025 3026
		appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE ");
		formatStringLiteral(delqry, lanname);
		appendPQExpBuffer(delqry, ";\n");
3027

3028 3029 3030 3031 3032 3033 3034 3035
		appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE ",
						  (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
						  "TRUSTED " : "");
		formatStringLiteral(defqry, lanname);
		appendPQExpBuffer(defqry, " HANDLER %s LANCOMPILER ",
						  fmtId(finfo[fidx].proname, force_quotes));
		formatStringLiteral(defqry, lancompiler);
		appendPQExpBuffer(defqry, ";\n");
3036

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

3040 3041
		resetPQExpBuffer(defqry);
		resetPQExpBuffer(delqry);
3042 3043 3044 3045 3046 3047
	}

	PQclear(res);

}

3048 3049
/*
 * dumpFuncs
3050
 *	  writes out to fout the queries to recreate all the user-defined functions
3051 3052 3053
 *
 */
void
B
Bruce Momjian 已提交
3054
dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs,
3055
		  TypeInfo *tinfo, int numTypes)
3056
{
3057
	int			i;
3058 3059 3060

	for (i = 0; i < numFuncs; i++)
		dumpOneFunc(fout, finfo, i, tinfo, numTypes);
3061 3062 3063 3064
}

/*
 * dumpOneFunc:
3065 3066
 *	  dump out only one function,  the index of which is given in the third
 *	argument
3067 3068 3069
 *
 */

3070
static void
B
Bruce Momjian 已提交
3071
dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
3072
			TypeInfo *tinfo, int numTypes)
3073
{
3074
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3075 3076
	PQExpBuffer fn = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
B
Bruce,  
Bruce Momjian 已提交
3077
	PQExpBuffer fnlist = createPQExpBuffer();
B
Bruce Momjian 已提交
3078
	int			j;
3079
	PQExpBuffer asPart = createPQExpBuffer();
3080
	char		func_lang[NAMEDATALEN + 1];
3081 3082 3083 3084
	PGresult   *res;
	int			nlangs;
	int			i_lanname;
	char		query[256];
3085

3086 3087 3088 3089
	char		*listSep;
	char		*listSepComma = ",";
	char		*listSepNone = "";

3090 3091 3092 3093 3094
	if (finfo[i].dumped)
		return;
	else
		finfo[i].dumped = 1;

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

3097 3098 3099 3100 3101
	sprintf(query, "SELECT lanname FROM pg_language WHERE oid = %u",
			finfo[i].lang);
	res = PQexec(g_conn, query);
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
B
Bruce Momjian 已提交
3102
  	{
3103 3104
		fprintf(stderr, "dumpOneFunc(): SELECT for procedural language failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
		exit_nicely(g_conn);
B
Bruce Momjian 已提交
3105
  	}
3106 3107 3108
	nlangs = PQntuples(res);

	if (nlangs != 1)
B
Bruce Momjian 已提交
3109
  	{
3110 3111
		fprintf(stderr, "dumpOneFunc(): procedural language for function %s not found\n", finfo[i].proname);
		exit_nicely(g_conn);
B
Bruce Momjian 已提交
3112 3113
  	}
  
3114
	i_lanname = PQfnumber(res, "lanname");
3115

3116
	/*
3117 3118 3119 3120 3121
	 * See backend/commands/define.c for details of how the 'AS' clause
	 * is used.
	 */
	if (strcmp(finfo[i].probin, "-") != 0)
	{
3122 3123
		appendPQExpBuffer(asPart, "AS ");
		formatStringLiteral(asPart, finfo[i].probin);
3124
		if (strcmp(finfo[i].prosrc, "-") != 0)
3125 3126 3127 3128
		{
			appendPQExpBuffer(asPart, ", ");
			formatStringLiteral(asPart, finfo[i].prosrc);
		}
3129 3130 3131 3132
	}
	else
	{
		if (strcmp(finfo[i].prosrc, "-") != 0)
3133 3134 3135 3136
		{
			appendPQExpBuffer(asPart, "AS ");
			formatStringLiteral(asPart, finfo[i].prosrc);
		}
3137 3138
	}

3139
	strcpy(func_lang, PQgetvalue(res, 0, i_lanname));
B
Bruce Momjian 已提交
3140
  
3141
	PQclear(res);
B
Bruce Momjian 已提交
3142 3143 3144
 
	resetPQExpBuffer(fn);
	appendPQExpBuffer(fn, "%s (", fmtId(finfo[i].proname, force_quotes));
3145 3146
	for (j = 0; j < finfo[i].nargs; j++)
	{
B
Bruce Momjian 已提交
3147
		char			*typname;
3148

3149 3150 3151 3152
		typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j], zeroAsOpaque);
		appendPQExpBuffer(fn, "%s%s", 
							(j > 0) ? "," : "", 
							typname);
B
Bruce,  
Bruce Momjian 已提交
3153
		appendPQExpBuffer(fnlist, "%s%s",
3154 3155
							(j > 0) ? "," : "", 
							typname );
3156
	}
B
Bruce Momjian 已提交
3157 3158 3159 3160 3161 3162 3163
	appendPQExpBuffer(fn, ")");

	resetPQExpBuffer(delqry);
	appendPQExpBuffer(delqry, "DROP FUNCTION %s;\n", fn->data );

	resetPQExpBuffer(q);
	appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data );
3164 3165
	appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ",
					  (finfo[i].retset) ? "SETOF " : "",
3166
					  findTypeByOid(tinfo, numTypes, finfo[i].prorettype, zeroAsOpaque),
3167 3168
					  asPart->data);
	formatStringLiteral(q, func_lang);
3169

3170
	if (finfo[i].iscachable || finfo[i].isstrict) /* OR in new attrs here */
3171
	{
3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184
		appendPQExpBuffer(q, " WITH (");
		listSep = listSepNone;

		if (finfo[i].iscachable) {
			appendPQExpBuffer(q, "%s iscachable", listSep);
			listSep = listSepComma;
		}

		if (finfo[i].isstrict) {
			appendPQExpBuffer(q, "%s isstrict", listSep);
			listSep = listSepComma;
		}
		appendPQExpBuffer(q, " )");
3185 3186 3187 3188
	}

	appendPQExpBuffer(q, ";\n");

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

B
Bruce,  
Bruce Momjian 已提交
3192 3193 3194 3195 3196 3197 3198 3199
	/*** Dump Function Comments ***/

	resetPQExpBuffer(q);
	appendPQExpBuffer(q, "FUNCTION %s ",
					  fmtId(finfo[i].proname, force_quotes));
	appendPQExpBuffer(q, "( %s )", fnlist->data);
	dumpComment(fout, q->data, finfo[i].oid);

3200 3201 3202 3203
}

/*
 * dumpOprs
3204
 *	  writes out to fout the queries to recreate all the user-defined operators
3205 3206
 *
 */
3207
void
B
Bruce Momjian 已提交
3208
dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
3209
		 TypeInfo *tinfo, int numTypes)
3210
{
B
Bruce Momjian 已提交
3211
	int			i;
3212
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3213
	PQExpBuffer delq = createPQExpBuffer();
3214 3215 3216 3217 3218 3219 3220 3221
	PQExpBuffer leftarg = createPQExpBuffer();
	PQExpBuffer rightarg = createPQExpBuffer();
	PQExpBuffer commutator = createPQExpBuffer();
	PQExpBuffer negator = createPQExpBuffer();
	PQExpBuffer restrictor = createPQExpBuffer();
	PQExpBuffer join = createPQExpBuffer();
	PQExpBuffer sort1 = createPQExpBuffer();
	PQExpBuffer sort2 = createPQExpBuffer();
3222 3223 3224 3225

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

B
Hi, all  
Bruce Momjian 已提交
3226 3227 3228 3229 3230 3231 3232 3233 3234
		resetPQExpBuffer(leftarg);
		resetPQExpBuffer(rightarg);
		resetPQExpBuffer(commutator);
		resetPQExpBuffer(negator);
		resetPQExpBuffer(restrictor);
		resetPQExpBuffer(join);
		resetPQExpBuffer(sort1);
		resetPQExpBuffer(sort2);

3235
		/* skip all the builtin oids */
3236
		if (atooid(oprinfo[i].oid) <= g_last_builtin_oid)
3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252
			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
Hi, all  
Bruce Momjian 已提交
3253
			appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ",
3254
								findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft, zeroAsOpaque) );
3255 3256 3257 3258
		}
		if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
			strcmp(oprinfo[i].oprkind, "b") == 0)
		{
B
Hi, all  
Bruce Momjian 已提交
3259
			appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ",
3260
							  findTypeByOid(tinfo, numTypes, oprinfo[i].oprright, zeroAsOpaque) );
3261
		}
B
Hi, all  
Bruce Momjian 已提交
3262 3263
		if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
			appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ",
3264 3265
				 findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom));

B
Hi, all  
Bruce Momjian 已提交
3266 3267
		if (!(strcmp(oprinfo[i].oprnegate, "0") == 0))
			appendPQExpBuffer(negator, ",\n\tNEGATOR = %s ",
3268 3269
			  findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate));

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

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

B
Hi, all  
Bruce Momjian 已提交
3276 3277
		if (!(strcmp(oprinfo[i].oprlsortop, "0") == 0))
			appendPQExpBuffer(sort1, ",\n\tSORT1 = %s ",
B
Bruce Momjian 已提交
3278
			 findOprByOid(oprinfo, numOperators, oprinfo[i].oprlsortop));
3279

B
Hi, all  
Bruce Momjian 已提交
3280 3281
		if (!(strcmp(oprinfo[i].oprrsortop, "0") == 0))
			appendPQExpBuffer(sort2, ",\n\tSORT2 = %s ",
B
Bruce Momjian 已提交
3282
			 findOprByOid(oprinfo, numOperators, oprinfo[i].oprrsortop));
3283

B
Bruce Momjian 已提交
3284 3285
		resetPQExpBuffer(delq);
		appendPQExpBuffer(delq, "DROP OPERATOR %s (%s", oprinfo[i].oprname,
3286
				findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft, zeroAsOpaque) );
B
Bruce Momjian 已提交
3287
		appendPQExpBuffer(delq, ", %s);\n",
3288
					findTypeByOid(tinfo, numTypes, oprinfo[i].oprright, zeroAsOpaque) );
3289

B
Hi, all  
Bruce Momjian 已提交
3290 3291
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
3292 3293 3294 3295 3296 3297 3298 3299 3300
						  "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 已提交
3301
						(strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
3302 3303 3304
						  join->data,
						  sort1->data,
						  sort2->data);
3305

B
Bruce Momjian 已提交
3306
		ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
3307
						q->data, delq->data, "", oprinfo[i].usename, NULL, NULL);
3308
	}
3309 3310 3311 3312
}

/*
 * dumpAggs
3313
 *	  writes out to fout the queries to create all the user-defined aggregates
3314 3315 3316
 *
 */
void
B
Bruce Momjian 已提交
3317
dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
3318
		 TypeInfo *tinfo, int numTypes)
3319
{
B
Bruce Momjian 已提交
3320
	int			i;
3321
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3322 3323
	PQExpBuffer delq = createPQExpBuffer();
	PQExpBuffer aggSig = createPQExpBuffer();
3324
	PQExpBuffer details = createPQExpBuffer();
3325 3326 3327

	for (i = 0; i < numAggs; i++)
	{
3328
		resetPQExpBuffer(details);
B
Hi, all  
Bruce Momjian 已提交
3329

3330
		/* skip all the builtin oids */
3331
		if (atooid(agginfo[i].oid) <= g_last_builtin_oid)
3332
			continue;
3333

3334
		appendPQExpBuffer(details,
3335
						  "BASETYPE = %s, ",
3336
						  findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsAny + useBaseTypeName));
3337

3338 3339 3340
		appendPQExpBuffer(details,
						  "SFUNC = %s, STYPE = %s",
						  agginfo[i].aggtransfn,
3341
						  findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype, zeroAsOpaque + useBaseTypeName));
3342

3343
		if (agginfo[i].agginitval)
3344 3345 3346 3347
		{
			appendPQExpBuffer(details, ", INITCOND = ");
			formatStringLiteral(details, agginfo[i].agginitval);
		}
3348

B
Hi, all  
Bruce Momjian 已提交
3349
		if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
3350 3351
			appendPQExpBuffer(details, ", FINALFUNC = %s",
							  agginfo[i].aggfinalfn);
3352

B
Bruce Momjian 已提交
3353 3354
		resetPQExpBuffer(aggSig);
		appendPQExpBuffer(aggSig, "%s %s", agginfo[i].aggname,
3355
							findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsOpaque + useBaseTypeName));
3356

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

B
Hi, all  
Bruce Momjian 已提交
3360
		resetPQExpBuffer(q);
3361
		appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
3362
						  agginfo[i].aggname,
3363
						  details->data);
3364

B
Bruce Momjian 已提交
3365
		ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
3366
						q->data, delq->data, "", agginfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
3367 3368 3369 3370

		/*** Dump Aggregate Comments ***/

		resetPQExpBuffer(q);
3371
		appendPQExpBuffer(q, "AGGREGATE %s %s", agginfo[i].aggname,
3372
						  findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsOpaque + useBaseTypeName));
B
Bruce,  
Bruce Momjian 已提交
3373 3374
		dumpComment(fout, q->data, agginfo[i].oid);

3375
	}
3376 3377
}

3378 3379 3380 3381 3382
/*
 * These are some support functions to fix the acl problem of pg_dump
 *
 * Matthew C. Aycock 12/02/97
 */
3383 3384 3385

/* Append a keyword to a keyword list, inserting comma if needed.
 * Caller must make aclbuf big enough for all possible keywords.
3386
 */
3387
static void
B
Bruce Momjian 已提交
3388
AddAcl(char *aclbuf, const char *keyword)
3389
{
3390 3391 3392
	if (*aclbuf)
		strcat(aclbuf, ",");
	strcat(aclbuf, keyword);
3393
}
3394

3395
/*
3396
 * This will take a string of 'arwR' and return a malloced,
3397 3398
 * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
 */
V
Vadim B. Mikheev 已提交
3399
static char *
3400
GetPrivileges(const char *s)
3401
{
3402
	char		aclbuf[100];
3403

3404
	aclbuf[0] = '\0';
3405

B
Bruce Momjian 已提交
3406
	if (strchr(s, 'a'))
3407
		AddAcl(aclbuf, "INSERT");
3408

B
Bruce Momjian 已提交
3409
	if (strchr(s, 'w'))
3410
		AddAcl(aclbuf, "UPDATE,DELETE");
B
Bruce Momjian 已提交
3411 3412

	if (strchr(s, 'r'))
3413
		AddAcl(aclbuf, "SELECT");
3414

3415
	if (strchr(s, 'R'))
3416
		AddAcl(aclbuf, "RULE");
3417

3418 3419 3420
	/* Special-case when they're all there */
	if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
		return strdup("ALL");
3421

3422
	return strdup(aclbuf);
3423
}
3424

B
Bruce Momjian 已提交
3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440
/*
 * The name says it all; a function to append a string is the dest 
 * is big enough. If not, it does a realloc.
 */
static void strcatalloc(char **dest, int *dSize, char *src)
{
    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 已提交
3441 3442
/*
 * dumpACL:
3443 3444
 *	  Write out grant/revoke information
 *	  Called for sequences and tables
B
Bruce Momjian 已提交
3445 3446
 */

3447
static void
B
Bruce Momjian 已提交
3448
dumpACL(Archive *fout, TableInfo tbinfo)
B
Bruce Momjian 已提交
3449
{
B
Bruce Momjian 已提交
3450 3451
	const char 	*acls = tbinfo.relacl;
	char	   	*aclbuf,
B
Bruce Momjian 已提交
3452 3453 3454
			   *tok,
			   *eqpos,
			   *priv;
B
Bruce Momjian 已提交
3455 3456 3457
	char		*sql;
	char		tmp[1024];
	int		sSize = 4096;
3458 3459 3460 3461

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

B
Bruce Momjian 已提交
3462 3463 3464 3465 3466
	/*
	 * Allocate a larginsh buffer for the output SQL.
	 */
	sql = (char*)malloc(sSize);

B
Bruce Momjian 已提交
3467 3468 3469
	/*
	 * Revoke Default permissions for PUBLIC. Is this actually necessary,
	 * or is it just a waste of time?
3470
	 */
B
Bruce Momjian 已提交
3471
	sprintf(sql,	"REVOKE ALL on %s from PUBLIC;\n",
3472
			fmtId(tbinfo.relname, force_quotes));
3473 3474 3475

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

3477 3478
	/* Scan comma-separated ACL items */
	for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
3479
	{
3480

B
Bruce Momjian 已提交
3481 3482 3483
		/*
		 * Token may start with '{' and/or '"'.  Actually only the start
		 * of the string should have '{', but we don't verify that.
3484 3485 3486 3487 3488 3489 3490 3491
		 */
		if (*tok == '{')
			tok++;
		if (*tok == '"')
			tok++;

		/* User name is string up to = in tok */
		eqpos = strchr(tok, '=');
B
Bruce Momjian 已提交
3492
		if (!eqpos)
B
Bruce Momjian 已提交
3493
		{
3494 3495
			fprintf(stderr, "Could not parse ACL list ('%s') for '%s'...Exiting!\n",
					acls, tbinfo.relname);
B
Bruce Momjian 已提交
3496 3497 3498
			exit_nicely(g_conn);
		}

B
Bruce Momjian 已提交
3499 3500 3501 3502
		/*
		 * Parse the privileges (right-hand side).	Skip if there are
		 * none.
		 */
3503 3504
		priv = GetPrivileges(eqpos + 1);
		if (*priv)
3505
		{
B
Bruce Momjian 已提交
3506
			sprintf(tmp,	"GRANT %s on %s to ",
3507
					priv, fmtId(tbinfo.relname, force_quotes));
B
Bruce Momjian 已提交
3508
			strcatalloc(&sql, &sSize, tmp);
B
Bruce Momjian 已提交
3509 3510 3511

			/*
			 * Note: fmtId() can only be called once per printf, so don't
3512 3513 3514 3515 3516
			 * try to merge printing of username into the above printf.
			 */
			if (eqpos == tok)
			{
				/* Empty left-hand side means "PUBLIC" */
B
Bruce Momjian 已提交
3517
				strcatalloc(&sql, &sSize, "PUBLIC;\n");
3518
			}
3519
			else
3520 3521
			{
				*eqpos = '\0';	/* it's ok to clobber aclbuf */
3522
				if (strncmp(tok, "group ", strlen("group ")) == 0)
B
Bruce Momjian 已提交
3523
					sprintf(tmp, "GROUP %s;\n",
3524 3525
							fmtId(tok + strlen("group "), force_quotes));
				else
B
Bruce Momjian 已提交
3526 3527
					sprintf(tmp, "%s;\n", fmtId(tok, force_quotes));
				strcatalloc(&sql, &sSize, tmp);
3528
			}
3529
		}
3530
		free(priv);
B
Bruce Momjian 已提交
3531
	}
3532 3533

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

3535
	ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "ACL", NULL, sql, "", "", "", NULL, NULL);
B
Bruce Momjian 已提交
3536

B
Bruce Momjian 已提交
3537 3538
}

3539

3540 3541
/*
 * dumpTables:
3542
 *	  write out to fout all the user-define tables
3543
 */
3544

3545
void
B
Bruce Momjian 已提交
3546
dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
3547
		   IndInfo *indinfo, int numIndices,
3548 3549
		   InhInfo *inhinfo, int numInherits,
		   TypeInfo *tinfo, int numTypes, const char *tablename,
B
Bruce Momjian 已提交
3550 3551
		   const bool aclsSkip, const bool oids,
		   const bool schemaOnly, const bool dataOnly)
3552
{
3553 3554
	int			i,
				j,
B
Bruce Momjian 已提交
3555
				k;
3556
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3557
	PQExpBuffer delq = createPQExpBuffer();
3558
	char	   *serialSeq = NULL;		/* implicit sequence name created
B
Bruce Momjian 已提交
3559 3560 3561 3562
										 * by SERIAL datatype */
	const char *serialSeqSuffix = "_id_seq";	/* suffix for implicit
												 * SERIAL sequences */
	char	  **parentRels;		/* list of names of parent relations */
3563
	int			numParents;
B
Bruce Momjian 已提交
3564
	int			actual_atts;	/* number of attrs in this CREATE statment */
3565
	char	   *reltypename;
3566

V
Vadim B. Mikheev 已提交
3567
	/* First - dump SEQUENCEs */
3568
	if (tablename && strlen(tablename) > 0)
B
Bruce Momjian 已提交
3569 3570 3571 3572 3573
	{
		serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
		strcpy(serialSeq, tablename);
		strcat(serialSeq, serialSeqSuffix);
	}
V
Vadim B. Mikheev 已提交
3574 3575 3576 3577
	for (i = 0; i < numTables; i++)
	{
		if (!(tblinfo[i].sequence))
			continue;
B
Bruce Momjian 已提交
3578
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
B
Bruce Momjian 已提交
3579
			|| (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
V
Vadim B. Mikheev 已提交
3580
		{
B
Bruce Momjian 已提交
3581
			/* becomeUser(fout, tblinfo[i].usename); */
V
Vadim B. Mikheev 已提交
3582
			dumpSequence(fout, tblinfo[i]);
3583
			if (!aclsSkip)
B
Bruce Momjian 已提交
3584
				dumpACL(fout, tblinfo[i]);
V
Vadim B. Mikheev 已提交
3585 3586
		}
	}
B
Bruce Momjian 已提交
3587
	if (tablename)
B
Bruce Momjian 已提交
3588
		free(serialSeq);
3589

3590 3591
	for (i = 0; i < numTables; i++)
	{
3592
		if (tblinfo[i].sequence)/* already dumped */
V
Vadim B. Mikheev 已提交
3593
			continue;
3594

3595
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename)) || (strlen(tablename) == 0))
3596 3597
		{

3598 3599
			resetPQExpBuffer(delq);
			resetPQExpBuffer(q);
3600

3601 3602 3603 3604
			/* Use the view definition if there is one */
			if (tblinfo[i].viewdef != NULL)
			{
				reltypename = "VIEW";
3605

3606 3607
				appendPQExpBuffer(delq, "DROP VIEW %s;\n", fmtId(tblinfo[i].relname, force_quotes));
				appendPQExpBuffer(q, "CREATE VIEW %s as %s", fmtId(tblinfo[i].relname, force_quotes), tblinfo[i].viewdef);
3608

3609 3610
			}
			else
3611
			{
3612
				reltypename = "TABLE";
3613

3614 3615
				parentRels = tblinfo[i].parentRels;
				numParents = tblinfo[i].numParents;
B
Bruce Momjian 已提交
3616

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

3619 3620 3621 3622 3623 3624
				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)
3625
					{
3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637
						/* Format properly if not first attr */
						if (actual_atts > 0)
							appendPQExpBuffer(q, ",\n\t");

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

						/* Default value */
						if (tblinfo[i].adef_expr[j] != NULL)
							appendPQExpBuffer(q, " DEFAULT %s",
3638
										  tblinfo[i].adef_expr[j]);
3639 3640 3641 3642 3643 3644 3645

						/* Not Null constraint */
						if (tblinfo[i].notnull[j])
							appendPQExpBuffer(q, " NOT NULL");

						actual_atts++;
					}
3646
				}
B
Hi all  
Bruce Momjian 已提交
3647

3648 3649


3650 3651 3652 3653 3654 3655 3656
				/* put the CONSTRAINTS inside the table def */
				for (k = 0; k < tblinfo[i].ncheck; k++)
				{
					if (actual_atts + k > 0)
						appendPQExpBuffer(q, ",\n\t");

					appendPQExpBuffer(q, "%s",
3657
								  tblinfo[i].check_expr[k]);
3658
				}
3659

3660 3661
				/* Primary Key */
				if (tblinfo[i].pkIndexOid != NULL)
3662
				{
3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681
					PQExpBuffer	consDef;

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

					if (k >= numIndices)
					{
						fprintf(stderr, "dumpTables(): failed sanity check, could not find index (%s) for PK constraint\n",
									tblinfo[i].pkIndexOid);
						exit_nicely(g_conn);
					}

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

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

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

					destroyPQExpBuffer(consDef);
3687
				}
B
Bruce Momjian 已提交
3688

3689

3690
				appendPQExpBuffer(q, "\n)");
3691

3692
				if (numParents > 0)
B
Hi all  
Bruce Momjian 已提交
3693
				{
3694 3695 3696 3697
					appendPQExpBuffer(q, "\ninherits (");
					for (k = 0; k < numParents; k++)
					{
						appendPQExpBuffer(q, "%s%s",
3698 3699
									  (k > 0) ? ", " : "",
									  fmtId(parentRels[k], force_quotes));
3700 3701
					}
					appendPQExpBuffer(q, ")");
B
Hi all  
Bruce Momjian 已提交
3702 3703
				}

3704 3705
				appendPQExpBuffer(q, ";\n");
			}
B
Bruce Momjian 已提交
3706 3707

			if (!dataOnly) {
3708 3709

				ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
3710
								reltypename, NULL, q->data, delq->data, "", tblinfo[i].usename,
B
Bruce Momjian 已提交
3711 3712
								NULL, NULL);

3713 3714 3715 3716
				if (!aclsSkip)
					dumpACL(fout, tblinfo[i]);

			}
3717

3718
			/* Dump Field Comments */
B
Bruce,  
Bruce Momjian 已提交
3719

3720 3721
			for (j = 0; j < tblinfo[i].numatts; j++)
			{
B
Bruce,  
Bruce Momjian 已提交
3722 3723 3724 3725 3726 3727
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "COLUMN %s", fmtId(tblinfo[i].relname, force_quotes));
				appendPQExpBuffer(q, ".");
				appendPQExpBuffer(q, "%s", fmtId(tblinfo[i].attnames[j], force_quotes));
				dumpComment(fout, q->data, tblinfo[i].attoids[j]);
			}
3728

B
Bruce,  
Bruce Momjian 已提交
3729
			/* Dump Table Comments */
3730

B
Bruce,  
Bruce Momjian 已提交
3731
			resetPQExpBuffer(q);
3732
			appendPQExpBuffer(q, "%s %s", reltypename, fmtId(tblinfo[i].relname, force_quotes));
B
Bruce,  
Bruce Momjian 已提交
3733
			dumpComment(fout, q->data, tblinfo[i].oid);
3734

3735 3736
		}
	}
3737 3738
}

3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773
static PQExpBuffer getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo)
{
	PQExpBuffer 	pkBuf = createPQExpBuffer();
	int				k;
	int				indkey;

   	resetPQExpBuffer(pkBuf);

	appendPQExpBuffer(pkBuf, "Constraint %s Primary Key (",
						tblInfo->primary_key_name);


	for (k = 0; k < INDEX_MAX_KEYS; k++)
	{
		char	   *attname;

		indkey = atoi(indInfo->indkey[k]);
		if (indkey == InvalidAttrNumber)
			break;
		indkey--;
		if (indkey == ObjectIdAttributeNumber - 1)
			attname = "oid";
		else
			attname = tblInfo->attnames[indkey];

		appendPQExpBuffer(pkBuf, "%s%s",
							(k == 0) ? "" : ", ", 
							fmtId(attname, force_quotes));
	}

	appendPQExpBuffer(pkBuf, ")");

	return pkBuf;
}

3774 3775
/*
 * dumpIndices:
3776
 *	  write out to fout all the user-define indices
3777
 */
3778
void
B
Bruce Momjian 已提交
3779
dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
3780
			TableInfo *tblinfo, int numTables, const char *tablename)
3781
{
3782 3783 3784
	int			i,
				k;
	int			tableInd;
3785
	PQExpBuffer attlist = createPQExpBuffer();
B
Bruce Momjian 已提交
3786 3787 3788
	char	   *classname[INDEX_MAX_KEYS];
	char	   *funcname;		/* the name of the function to comput the
								 * index key from */
3789 3790 3791
	int			indkey,
				indclass;
	int			nclass;
3792

3793
	PQExpBuffer q = createPQExpBuffer(),
B
Bruce Momjian 已提交
3794
				delq = createPQExpBuffer(),
B
Hi, all  
Bruce Momjian 已提交
3795 3796
				id1 = createPQExpBuffer(),
				id2 = createPQExpBuffer();
3797
	PGresult   *res;
3798 3799 3800 3801

	for (i = 0; i < numIndices; i++)
	{
		tableInd = findTableByName(tblinfo, numTables,
3802 3803 3804 3805 3806
								   indinfo[i].indrelname);
		if (tableInd < 0)
		{
			fprintf(stderr, "failed sanity check, table %s was not found\n",
					indinfo[i].indrelname);
3807
			exit(1);
3808
		}
3809

3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834
		/* Handle PK indexes */
		if (strcmp(indinfo[i].indisprimary, "t") == 0)
		{
/*
 *			***PK: Enable this code when ALTER TABLE supports PK constraints. ***
 *
 *			PQExpBuffer	consDef = getPKconstraint(&tblinfo[tableInd], &indinfo[i]);
 *
 *			resetPQExpBuffer(attlist);
 *
 *			appendPQExpBuffer(attlist, "Alter Table %s Add %s;", 
 *								fmtId(tblinfo[tableInd].relname, force_quotes),
 *								consDef->data);
 *
 *			ArchiveEntry(fout, indinfo[i].oid, tblinfo[tableInd].primary_key_name, "CONSTRAINT", NULL, 
 *							attlist->data, "",
 *							"", tblinfo[tableInd].usename, NULL, NULL);
 *
 *			destroyPQExpBuffer(consDef);
 */
			/* Don't need to do anything else for this system-generated index */
			continue;
		}


3835 3836 3837 3838
		if (strcmp(indinfo[i].indproc, "0") == 0)
			funcname = NULL;
		else
		{
3839
			int		numFuncs;
3840 3841 3842 3843 3844 3845 3846

			/*
			 * 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*
			 */
B
Hi, all  
Bruce Momjian 已提交
3847 3848
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
3849 3850 3851
							  "SELECT proname from pg_proc "
							  "where pg_proc.oid = '%s'::oid",
							  indinfo[i].indproc);
B
Hi, all  
Bruce Momjian 已提交
3852
			res = PQexec(g_conn, q->data);
3853 3854
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
3855 3856
				fprintf(stderr, "dumpIndices(): SELECT (funcname) failed.  "
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3857 3858
				exit_nicely(g_conn);
			}
3859 3860 3861 3862 3863 3864 3865 3866 3867

			/* Sanity: Check we got only one tuple */
			numFuncs = PQntuples(res);
			if (numFuncs != 1) {
				fprintf(stderr, "dumpIndices(): SELECT (funcname) for index %s returned %d tuples. Expected 1.\n", 
								indinfo[i].indrelname, numFuncs);
				exit_nicely(g_conn);
			}

B
Bruce Momjian 已提交
3868
			funcname = strdup(PQgetvalue(res, 0, PQfnumber(res, "proname")));
3869 3870 3871 3872 3873 3874
			PQclear(res);
		}

		/* convert opclass oid(s) into names */
		for (nclass = 0; nclass < INDEX_MAX_KEYS; nclass++)
		{
3875 3876
			int		numRows;

3877 3878 3879
			indclass = atoi(indinfo[i].indclass[nclass]);
			if (indclass == 0)
				break;
B
Hi, all  
Bruce Momjian 已提交
3880 3881
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
3882 3883 3884
							  "SELECT opcname from pg_opclass "
							  "where pg_opclass.oid = '%u'::oid",
							  indclass);
B
Hi, all  
Bruce Momjian 已提交
3885
			res = PQexec(g_conn, q->data);
3886 3887
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
3888 3889
				fprintf(stderr, "dumpIndices(): SELECT (classname) failed.  "
									"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3890 3891
				exit_nicely(g_conn);
			}
3892 3893 3894 3895 3896 3897 3898 3899 3900

			/* Sanity: Check we got only one tuple */
			numRows = PQntuples(res);
			if (numRows != 1) {
				fprintf(stderr, "dumpIndices(): SELECT (classname) for index %s returned %d tuples. Expected 1.\n", 
									indinfo[i].indrelname, numRows);
				exit_nicely(g_conn);
			}

B
Bruce Momjian 已提交
3901
			classname[nclass] = strdup(PQgetvalue(res, 0, PQfnumber(res, "opcname")));
3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912
			PQclear(res);
		}

		if (funcname && nclass != 1)
		{
			fprintf(stderr, "dumpIndices(): Must be exactly one OpClass "
					"for functional index %s\n", indinfo[i].indexrelname);
			exit_nicely(g_conn);
		}

		/* convert attribute numbers into attribute list */
B
Hi, all  
Bruce Momjian 已提交
3913 3914
		resetPQExpBuffer(attlist);
		for (k = 0; k < INDEX_MAX_KEYS; k++)
3915
		{
3916
			char	   *attname;
3917 3918

			indkey = atoi(indinfo[i].indkey[k]);
B
Bruce Momjian 已提交
3919
			if (indkey == InvalidAttrNumber)
3920 3921 3922 3923 3924 3925 3926
				break;
			indkey--;
			if (indkey == ObjectIdAttributeNumber - 1)
				attname = "oid";
			else
				attname = tblinfo[tableInd].attnames[indkey];
			if (funcname)
B
Hi, all  
Bruce Momjian 已提交
3927
				appendPQExpBuffer(attlist, "%s%s",
B
Bruce Momjian 已提交
3928
					 (k == 0) ? "" : ", ", fmtId(attname, force_quotes));
3929 3930 3931 3932 3933
			else
			{
				if (k >= nclass)
				{
					fprintf(stderr, "dumpIndices(): OpClass not found for "
3934
							"attribute '%s' of index '%s'\n",
3935 3936 3937
							attname, indinfo[i].indexrelname);
					exit_nicely(g_conn);
				}
B
Hi, all  
Bruce Momjian 已提交
3938 3939 3940 3941 3942
				resetPQExpBuffer(id1);
				resetPQExpBuffer(id2);
				appendPQExpBuffer(id1, fmtId(attname, force_quotes));
				appendPQExpBuffer(id2, fmtId(classname[k], force_quotes));
				appendPQExpBuffer(attlist, "%s%s %s",
3943
							 (k == 0) ? "" : ", ", id1->data, id2->data);
3944 3945 3946 3947
				free(classname[k]);
			}
		}

3948
		if (!tablename || (strcmp(indinfo[i].indrelname, tablename) == 0) || (strlen(tablename) == 0) )
3949
		{
B
Bruce Momjian 已提交
3950 3951 3952 3953 3954

			/*
			 * 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.
3955
			 */
3956

B
Hi, all  
Bruce Momjian 已提交
3957 3958 3959 3960
			resetPQExpBuffer(id1);
			resetPQExpBuffer(id2);
			appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
			appendPQExpBuffer(id2, fmtId(indinfo[i].indrelname, force_quotes));
3961

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

B
Bruce Momjian 已提交
3965 3966 3967
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "CREATE %s INDEX %s on %s using %s (",
					(strcmp(indinfo[i].indisunique, "t") == 0) ? "UNIQUE" : "",
B
Hi, all  
Bruce Momjian 已提交
3968 3969
					id1->data,
					id2->data,
3970 3971 3972
					indinfo[i].indamname);
			if (funcname)
			{
3973
				/* need 2 printf's here cuz fmtId has static return area */
B
Bruce Momjian 已提交
3974 3975 3976
				appendPQExpBuffer(q, " %s", fmtId(funcname, false));
				appendPQExpBuffer(q, " (%s) %s );\n", attlist->data, 
									fmtId(classname[0], force_quotes));
3977 3978 3979 3980
				free(funcname);
				free(classname[0]);
			}
			else
B
Bruce Momjian 已提交
3981
				appendPQExpBuffer(q, " %s );\n", attlist->data);
B
Bruce,  
Bruce Momjian 已提交
3982 3983 3984

			/* Dump Index Comments */

B
Bruce Momjian 已提交
3985
			ArchiveEntry(fout, tblinfo[tableInd].oid, id1->data, "INDEX", NULL, q->data, delq->data,
3986
							"", tblinfo[tableInd].usename, NULL, NULL);
B
Bruce Momjian 已提交
3987

B
Bruce,  
Bruce Momjian 已提交
3988 3989 3990
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "INDEX %s", id1->data);
			dumpComment(fout, q->data, indinfo[i].indoid);
3991

3992 3993
		}
	}
3994 3995

}
3996

3997
/*
B
Bruce Momjian 已提交
3998
 * dumpTuples
3999 4000 4001 4002 4003
 *	  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
4004
 *	  in PostgreSQL.
4005 4006 4007 4008
 *
 * the attrmap passed in tells how to map the attributes copied in to the
 * attributes copied out
 */
4009
#ifdef NOT_USED
4010
void
4011
dumpTuples(PGresult *res, FILE *fout, int *attrmap)
4012
{
4013 4014 4015 4016
	int			j,
				k;
	int			m,
				n;
B
Bruce Momjian 已提交
4017
	char	  **outVals = NULL; /* values to copy out */
4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036

	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++)
			{
4037
				char	   *pval = outVals[k];
4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057

				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);
	}
4058
}
4059

4060
#endif
4061

4062 4063 4064 4065
/*
 * setMaxOid -
 * find the maximum oid and generate a COPY statement to set it
*/
4066

4067
static void
B
Bruce Momjian 已提交
4068
setMaxOid(Archive *fout)
4069
{
B
Bruce Momjian 已提交
4070 4071 4072 4073
	PGresult   	*res;
	Oid		max_oid;
	char		sql[1024];
	int		pos;
4074

4075
	res = PQexec(g_conn, "CREATE TEMPORARY TABLE pgdump_oid (dummy int4)");
4076 4077 4078
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4079
		fprintf(stderr, "Can not create pgdump_oid table.  "
B
Bruce Momjian 已提交
4080
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4081 4082 4083
		exit_nicely(g_conn);
	}
	PQclear(res);
4084
	res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
4085 4086 4087
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4088
		fprintf(stderr, "Can not insert into pgdump_oid table.  "
B
Bruce Momjian 已提交
4089
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4090 4091 4092 4093 4094 4095 4096 4097 4098
		exit_nicely(g_conn);
	}
	max_oid = atol(PQoidStatus(res));
	if (max_oid == 0)
	{
		fprintf(stderr, "Invalid max id in setMaxOid\n");
		exit_nicely(g_conn);
	}
	PQclear(res);
4099
	res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
4100 4101 4102
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4103
		fprintf(stderr, "Can not drop pgdump_oid table.  "
B
Bruce Momjian 已提交
4104
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4105 4106 4107 4108
		exit_nicely(g_conn);
	}
	PQclear(res);
	if (g_verbose)
4109
		fprintf(stderr, "%s maximum system oid is %u %s\n",
4110
				g_comment_start, max_oid, g_comment_end);
4111 4112
	pos = snprintf(sql, 1024, "CREATE TEMPORARY TABLE pgdump_oid (dummy int4);\n");
	pos = pos + snprintf(sql+pos, 1024-pos, "COPY pgdump_oid WITH OIDS FROM stdin;\n");
B
Bruce Momjian 已提交
4113 4114
	pos = pos + snprintf(sql+pos, 1024-pos, "%-d\t0\n", max_oid);
	pos = pos + snprintf(sql+pos, 1024-pos, "\\.\n");
4115
	pos = pos + snprintf(sql+pos, 1024-pos, "DROP TABLE pgdump_oid;\n");
B
Bruce Momjian 已提交
4116

4117
	ArchiveEntry(fout, "0", "Max OID", "<Init>", NULL, sql, "", "", "", NULL, NULL);
4118
}
4119 4120 4121

/*
 * findLastBuiltInOid -
4122
 * find the last built in oid
4123 4124
 * we do this by retrieving datlastsysoid from the pg_database entry for this database,
 */
4125

4126
static Oid
4127
findLastBuiltinOid(const char* dbname)
4128
{
B
Bruce Momjian 已提交
4129
	PGresult   *res;
4130
	int			ntups;
4131
	Oid			last_oid;
4132 4133 4134
	PQExpBuffer query = createPQExpBuffer();

	resetPQExpBuffer(query);
4135 4136
	appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
	formatStringLiteral(query, dbname);
4137

4138
	res = PQexec(g_conn, query->data);
4139 4140 4141
	if (res == NULL ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
4142
		fprintf(stderr, "pg_dump: error in finding the last system OID");
4143
		fprintf(stderr, "Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4144 4145 4146
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);
4147
	if (ntups < 1)
4148
	{
4149 4150
		fprintf(stderr, "pg_dump: couldn't find the pg_database entry.\n");
		fprintf(stderr, "There is no entry in the 'pg_database' table for this database.\n");
4151 4152 4153 4154
		exit_nicely(g_conn);
	}
	if (ntups > 1)
	{
4155 4156
		fprintf(stderr, "pg_dump: found more than one matching database.\n");
		fprintf(stderr, "There is more than one entry for this database in the 'pg_database' table\n");
4157 4158
		exit_nicely(g_conn);
	}
4159
	last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
4160 4161
	PQclear(res);
	return last_oid;
4162 4163 4164
}


4165
static void
B
Bruce Momjian 已提交
4166
dumpSequence(Archive *fout, TableInfo tbinfo)
4167
{
4168
	PGresult   *res;
B
Bruce Momjian 已提交
4169
	int4		last,
4170 4171 4172 4173
				incby,
				maxv,
				minv,
				cache;
B
Bruce Momjian 已提交
4174
	char		cycled,
B
Bruce Momjian 已提交
4175
				called;
4176 4177
	const char *t;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
4178
	PQExpBuffer delqry = createPQExpBuffer();
4179

B
Hi, all  
Bruce Momjian 已提交
4180
	appendPQExpBuffer(query,
4181
			"SELECT sequence_name, last_value, increment_by, max_value, "
4182 4183
				  "min_value, cache_value, is_cycled, is_called from %s",
					  fmtId(tbinfo.relname, force_quotes));
4184

B
Hi, all  
Bruce Momjian 已提交
4185
	res = PQexec(g_conn, query->data);
4186 4187
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
4188 4189
		fprintf(stderr, "dumpSequence(%s): SELECT failed.  "
					"Explanation from backend: '%s'.\n", tbinfo.relname, PQerrorMessage(g_conn));
4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220
		exit_nicely(g_conn);
	}

	if (PQntuples(res) != 1)
	{
		fprintf(stderr, "dumpSequence(%s): %d (!= 1) tuples returned by SELECT\n",
				tbinfo.relname, PQntuples(res));
		exit_nicely(g_conn);
	}

	if (strcmp(PQgetvalue(res, 0, 0), tbinfo.relname) != 0)
	{
		fprintf(stderr, "dumpSequence(%s): different sequence name "
				"returned by SELECT: %s\n",
				tbinfo.relname, PQgetvalue(res, 0, 0));
		exit_nicely(g_conn);
	}


	last = atoi(PQgetvalue(res, 0, 1));
	incby = atoi(PQgetvalue(res, 0, 2));
	maxv = atoi(PQgetvalue(res, 0, 3));
	minv = atoi(PQgetvalue(res, 0, 4));
	cache = atoi(PQgetvalue(res, 0, 5));
	t = PQgetvalue(res, 0, 6);
	cycled = *t;
	t = PQgetvalue(res, 0, 7);
	called = *t;

	PQclear(res);

B
Bruce Momjian 已提交
4221 4222
	resetPQExpBuffer(delqry);
	appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n", fmtId(tbinfo.relname, force_quotes));
4223

4224 4225 4226 4227 4228 4229
	/*
	 * The logic we use for restoring sequences is as follows:
	 *		- 	Add a basic CREATE SEQUENCE statement 
	 *			(use last_val for start if called == 'f', else use min_val for start_val).
	 *		-	Add a 'SETVAL(seq, last_val, iscalled)' at restore-time iff we load data
	 */
B
Hi, all  
Bruce Momjian 已提交
4230 4231
	resetPQExpBuffer(query);
	appendPQExpBuffer(query,
4232 4233
				  "CREATE SEQUENCE %s start %d increment %d maxvalue %d "
					  "minvalue %d  cache %d %s;\n",
4234 4235 4236
					fmtId(tbinfo.relname, force_quotes), 
					  (called == 't') ? minv : last,
					  incby, maxv, minv, cache,
4237
					  (cycled == 't') ? "cycle" : "");
4238

B
Bruce Momjian 已提交
4239
	ArchiveEntry(fout, tbinfo.oid, fmtId(tbinfo.relname, force_quotes), "SEQUENCE", NULL,
4240
					query->data, delqry->data, "", tbinfo.usename, NULL, NULL);
4241

4242 4243

	resetPQExpBuffer(query);
4244 4245 4246
	appendPQExpBuffer(query, "SELECT setval (");
	formatStringLiteral(query, fmtId(tbinfo.relname, force_quotes));
	appendPQExpBuffer(query, ", %d, '%c');\n", last, called);
4247 4248 4249 4250

	ArchiveEntry(fout, tbinfo.oid, fmtId(tbinfo.relname, force_quotes), "SEQUENCE SET", NULL,
					query->data, "" /* Del */, "", "", NULL, NULL);

B
Bruce,  
Bruce Momjian 已提交
4251 4252 4253 4254 4255 4256
	/* Dump Sequence Comments */

	resetPQExpBuffer(query);
	appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo.relname, force_quotes));
	dumpComment(fout, query->data, tbinfo.oid);

4257
}
V
Vadim B. Mikheev 已提交
4258 4259


4260
static void
B
Bruce Momjian 已提交
4261
dumpTriggers(Archive *fout, const char *tablename,
4262
			 TableInfo *tblinfo, int numTables)
V
Vadim B. Mikheev 已提交
4263
{
4264 4265 4266
	int			i,
				j;

V
Vadim B. Mikheev 已提交
4267 4268 4269
	if (g_verbose)
		fprintf(stderr, "%s dumping out triggers %s\n",
				g_comment_start, g_comment_end);
4270

V
Vadim B. Mikheev 已提交
4271 4272
	for (i = 0; i < numTables; i++)
	{
4273
		if (tablename && (strcmp(tblinfo[i].relname, tablename) != 0) && (strlen(tablename) > 0) )
V
Vadim B. Mikheev 已提交
4274
			continue;
4275

V
Vadim B. Mikheev 已提交
4276 4277
		for (j = 0; j < tblinfo[i].ntrig; j++)
		{
B
Bruce Momjian 已提交
4278
			ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
4279
						"TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "", "", 
B
Bruce Momjian 已提交
4280 4281
						tblinfo[i].usename, NULL, NULL);
			dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid);
V
Vadim B. Mikheev 已提交
4282 4283 4284
		}
	}
}
4285 4286


4287
static void
B
Bruce Momjian 已提交
4288
dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
4289
		  TableInfo *tblinfo, int numTables)
4290
{
B
Bruce Momjian 已提交
4291 4292 4293 4294
	PGresult   *res;
	int			nrules;
	int			i,
				t;
4295
	PQExpBuffer query = createPQExpBuffer();
4296

B
Bruce Momjian 已提交
4297
	int			i_definition;
4298
	int			i_oid;
4299
	int			i_owner;
4300
	int			i_rulename;
4301 4302 4303 4304 4305 4306 4307 4308 4309 4310

	if (g_verbose)
		fprintf(stderr, "%s dumping out rules %s\n",
				g_comment_start, g_comment_end);

	/*
	 * For each table we dump
	 */
	for (t = 0; t < numTables; t++)
	{
4311
		if (tablename && (strcmp(tblinfo[t].relname, tablename) != 0) && (strlen(tablename) > 0) )
4312 4313 4314 4315
			continue;

		/*
		 * Get all rules defined for this table
4316 4317
		 * We include pg_rules in the cross since it filters out
		 * all view rules (pjw 15-Sep-2000).
4318
		 */
B
Hi, all  
Bruce Momjian 已提交
4319
		resetPQExpBuffer(query);
4320
		appendPQExpBuffer(query, "SELECT definition,"
4321
						  "   (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
4322 4323
						  "   pg_rewrite.oid, pg_rewrite.rulename "
						  "FROM pg_rewrite, pg_class, pg_rules "
4324 4325 4326
						  "WHERE pg_class.relname = ");
		formatStringLiteral(query, tblinfo[t].relname);
		appendPQExpBuffer(query,
4327 4328 4329
						  "    AND pg_rewrite.ev_class = pg_class.oid "
						  "    AND pg_rules.tablename = pg_class.relname "
						  "    AND pg_rules.rulename = pg_rewrite.rulename "
4330
						  "ORDER BY pg_rewrite.oid");
B
Hi, all  
Bruce Momjian 已提交
4331
		res = PQexec(g_conn, query->data);
4332 4333 4334
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
4335
			fprintf(stderr, "dumpRules(): SELECT failed for rules associated with table \"%s\".\n\tExplanation from backend: '%s'.\n",
B
Bruce Momjian 已提交
4336
					tblinfo[t].relname, PQerrorMessage(g_conn));
4337 4338 4339 4340 4341
			exit_nicely(g_conn);
		}

		nrules = PQntuples(res);
		i_definition = PQfnumber(res, "definition");
4342
		i_owner = PQfnumber(res, "viewowner");
B
Bruce,  
Bruce Momjian 已提交
4343 4344
		i_oid = PQfnumber(res, "oid");
		i_rulename = PQfnumber(res, "rulename");
4345 4346 4347 4348

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

4350 4351
		for (i = 0; i < nrules; i++)
		{
B
Bruce Momjian 已提交
4352 4353
			ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
							"RULE", NULL, PQgetvalue(res, i, i_definition),
4354
							"", "", PQgetvalue(res, i, i_owner), NULL, NULL);
4355

B
Bruce,  
Bruce Momjian 已提交
4356 4357 4358 4359 4360
			/* Dump rule comments */

			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "RULE %s", fmtId(PQgetvalue(res, i, i_rulename), force_quotes));
			dumpComment(fout, query->data, PQgetvalue(res, i, i_oid));
4361

B
Bruce,  
Bruce Momjian 已提交
4362 4363
		}

4364 4365 4366 4367
		PQclear(res);
	}
}