pg_dump.c 112.3 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.182 2000/11/27 20:51:40 momjian 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
#include <unistd.h>				/* for getopt() */
103
#include <ctype.h>
104

105 106
#include "pg_backup.h"

107
#include "postgres.h"
108 109 110 111 112 113 114 115 116

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

#include "access/attnum.h"
117
#include "access/htup.h"
118
#include "catalog/pg_index.h"
119
#include "catalog/pg_language.h"
V
Vadim B. Mikheev 已提交
120
#include "catalog/pg_trigger.h"
121
#include "catalog/pg_type.h"
122

123
#include "libpq-fe.h"
124
#include <libpq/libpq-fs.h>
125
#ifndef HAVE_STRDUP
126 127
#include "strdup.h"
#endif
128 129

#include "pg_dump.h"
B
Bruce Momjian 已提交
130
#include "pg_backup.h"
131

132 133
#define atooid(x)  ((Oid) strtoul((x), NULL, 10))

B
Bruce Momjian 已提交
134 135 136 137
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,
138
			 TableInfo *tblinfo, int numTables);
B
Bruce Momjian 已提交
139
static void dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
140
		  TableInfo *tblinfo, int numTables);
141 142
static char *checkForQuote(const char *s);
static void clearTableInfo(TableInfo *, int);
B
Bruce Momjian 已提交
143
static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
144
			TypeInfo *tinfo, int numTypes);
145
static Oid	findLastBuiltinOid(const char*);
B
Bruce Momjian 已提交
146
static void setMaxOid(Archive *fout);
147

148 149
static void AddAcl(char *aclbuf, const char *keyword);
static char *GetPrivileges(const char *s);
V
Vadim B. Mikheev 已提交
150

151
static int dumpBlobs(Archive *AH, char*, void*);
152
static int dumpDatabase(Archive *AH);
153

B
Bruce Momjian 已提交
154
extern char *optarg;
155
extern int	optind,
B
Bruce Momjian 已提交
156
			opterr;
157 158

/* global decls */
159
bool		g_verbose;			/* User wants verbose narration of our
B
Bruce Momjian 已提交
160
								 * activities. */
161
Oid			g_last_builtin_oid; /* value of the last builtin oid */
B
Bruce Momjian 已提交
162
Archive	   *g_fout;				/* the script file */
B
Bruce Momjian 已提交
163 164 165
PGconn	   *g_conn;				/* the database connection */

bool		force_quotes;		/* User wants to suppress double-quotes */
166 167 168 169
bool		dumpData;			/* dump data using proper insert strings */
bool		attrNames;			/* put attr names into insert strings */
bool		schemaOnly;
bool		dataOnly;
170
bool		aclsSkip;
171

B
Bruce Momjian 已提交
172
char		g_opaque_type[10];	/* name for the opaque type */
173 174

/* placeholders for the delimiters for comments */
175 176
char		g_comment_start[10];
char		g_comment_end[10];
177 178


B
Bruce Momjian 已提交
179 180 181 182 183 184
typedef struct _dumpContext {
	TableInfo	*tblinfo;
	int		tblidx;
	bool		oids;
} DumpContext;

185
static void
186
help(const char *progname)
187
{
P
Peter Eisentraut 已提交
188
	printf("%s dumps a database as a text file.\n\n", progname);
189 190 191
	puts("Usage:");
	printf("  %s [options] dbname\n\n", progname);
	puts("Options:");
B
Hi,  
Bruce Momjian 已提交
192 193

#ifdef HAVE_GETOPT_LONG
194
	puts(
B
Bruce Momjian 已提交
195
		"  -a, --data-only          dump out only the data, not the schema\n"
196
		"  -b, --blobs				dump out blob data\n"
B
Bruce Momjian 已提交
197
	   	"  -c, --clean              clean (drop) schema prior to create\n"
198
		"  -C, --create             output commands to create database\n"
B
Bruce Momjian 已提交
199 200 201 202 203 204 205 206 207
		"  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"
		"  -D, --attribute-inserts  dump data as INSERT commands with attribute names\n"
		"  -f, --file               specify output file name\n"
		"  -F, --format {c|f|p}     output file format (custom, files, plain text)\n"
		"  -h, --host <hostname>    server host name\n"
		"  -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"
208
		"  -O, --no-owner           don't output \\connect commands in plain text format\n"
B
Bruce Momjian 已提交
209
		"  -p, --port <port>        server port number\n"
210
		"  -R, --no-reconnect       disable ALL reconnections to the database in plain text format\n"
B
Bruce Momjian 已提交
211
		"  -s, --schema-only        dump out only the schema, no data\n"
212
		"  -S, --superuser <name>   specify the superuser username to use in plain text format\n"
B
Bruce Momjian 已提交
213 214 215 216 217
		"  -t, --table <table>      dump for this table only\n"
		"  -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"
218
		);
B
Hi,  
Bruce Momjian 已提交
219
#else
220
	puts(
B
Bruce Momjian 已提交
221
		"  -a                       dump out only the data, no schema\n"
222
		"  -b                       dump out blob data\n"
B
Bruce Momjian 已提交
223
		"  -c                       clean (drop) schema prior to create\n"
224
		"  -C                       output commands to create database\n"
B
Bruce Momjian 已提交
225 226 227 228 229 230 231 232 233
		"  -d                       dump data as INSERT, rather than COPY, commands\n"
		"  -D                       dump data as INSERT commands with attribute names\n"
		"  -f                       specify output file name\n"
		"  -F {c|f|p}               output file format (custom, files, plain text)\n"
		"  -h <hostname>            server host name\n"
		"  -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"
234
		"  -O                       don't output \\connect commands in plain text format\n"
B
Bruce Momjian 已提交
235
		"  -p <port>                server port number\n"
236
		"  -R                       disable ALL reconnections to the database in plain text format\n"
B
Bruce Momjian 已提交
237
		"  -s                       dump out only the schema, no data\n"
238
		"  -S <name>                specify the superuser username to use in plain text format\n"
B
Bruce Momjian 已提交
239 240 241 242 243
		"  -t <table>               dump for this table only\n"
		"  -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"
244
		);
B
Hi,  
Bruce Momjian 已提交
245
#endif
246 247
	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>.");
248
}
249

250

251 252 253
static void
version(void)
{
254
	puts("pg_dump (PostgreSQL) " PG_VERSION);
255 256 257
	puts("Portions Copyright (c) 1996-2000, PostgreSQL, Inc");
	puts("Portions Copyright (C) 1996 Regents of the University of California");
	puts("Read the file COPYRIGHT to see the usage and distribution terms.");
258 259
}

260

261
static void
262
exit_nicely(PGconn *conn)
263
{
264 265
	PQfinish(conn);
	exit(1);
266 267 268
}


269 270
#define COPYBUFSIZ		8192

B
Bruce Momjian 已提交
271 272 273 274 275
/*
 *	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.
 */
276

B
Bruce Momjian 已提交
277 278
static int 
dumpClasses_nodumpData(Archive *fout, char* oid, void *dctxv)
279
{
B
Bruce Momjian 已提交
280 281 282
	const DumpContext	*dctx = (DumpContext*)dctxv; 	
	const char 	*classname = dctx->tblinfo[dctx->tblidx].relname;
	const bool	oids = dctx->oids;
283

284 285 286 287 288
	PGresult   *res;
	char		query[255];
	int			ret;
	bool		copydone;
	char		copybuf[COPYBUFSIZ];
289

290 291 292
    if (g_verbose)
        fprintf(stderr, "%s dumping out the contents of table %s\n", g_comment_start, classname);

293
	if (oids == true)
294
	{
295 296 297 298 299 300 301 302
		/* 
		 * 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)
		 *
		 */

303
		sprintf(query, "COPY %s WITH OIDS TO stdout;\n",
304
				fmtId(classname, force_quotes));
305 306 307
	}
	else
	{
308 309 310 311 312 313 314
		/* 
		 *archprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname, force_quotes));
		 *
		 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
		 *
		 */

315
		sprintf(query, "COPY %s TO stdout;\n", fmtId(classname, force_quotes));
316 317
	}
	res = PQexec(g_conn, query);
318 319
	if (!res ||
		PQresultStatus(res) == PGRES_FATAL_ERROR)
320
	{
321
		fprintf(stderr, "SQL query to dump the contents of Table '%s' "
322 323 324 325 326 327 328 329 330
				"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)
		{
331
			fprintf(stderr, "SQL query to dump the contents of Table '%s' "
332 333 334 335 336 337 338 339 340
					"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;
341

342 343
			while (!copydone)
			{
344
				ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
345 346 347 348 349 350 351 352 353

				if (copybuf[0] == '\\' &&
					copybuf[1] == '.' &&
					copybuf[2] == '\0')
				{
					copydone = true;	/* don't print this... */
				}
				else
				{
B
Bruce Momjian 已提交
354
					archputs(copybuf, fout);
355 356
					switch (ret)
					{
357 358 359 360
						case EOF:
							copydone = true;
							/* FALLTHROUGH */
						case 0:
B
Bruce Momjian 已提交
361
							archputc('\n', fout);
362 363 364
							break;
						case 1:
							break;
365 366
					}
				}
367 368 369 370 371 372 373 374 375 376 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

				/* 
				 * 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'.
				 */	
407
			}
B
Bruce Momjian 已提交
408
			archprintf(fout, "\\.\n");
409
		}
410
		ret = PQendcopy(g_conn);
411 412
		if (ret != 0)
		{
413
			fprintf(stderr, "SQL query to dump the contents of Table '%s' "
414 415 416 417 418
					"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 已提交
419
			PQclear(res);
420 421 422
			exit_nicely(g_conn);
		}
	}
423

B
Bruce Momjian 已提交
424
	return 1;
425 426
}

B
Bruce Momjian 已提交
427 428
static int
dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
429
{
B
Bruce Momjian 已提交
430 431 432
	const DumpContext	*dctx = (DumpContext*)dctxv;
	const char			*classname = dctx->tblinfo[dctx->tblidx].relname;

433 434
	PGresult   *res;
	PQExpBuffer q = createPQExpBuffer();
435 436
	int			tuple;
	int			field;
437
	const char *expsrc;
438

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

492 493
					/*
					 * All other types are printed as string literals,
494 495 496
					 * with appropriate escaping of special characters.
					 * Quote mark ' goes to '' per SQL standard, other
					 * stuff goes to \ sequences.
497
					 */
B
Bruce Momjian 已提交
498
					archputc('\'', fout);
499 500 501 502 503 504
					expsrc = PQgetvalue(res, tuple, field);
					while (*expsrc)
					{
						char		ch = *expsrc++;

						if (ch == '\\' || ch == '\'')
505
						{
B
Bruce Momjian 已提交
506 507
							archputc(ch, fout);			/* double these */
							archputc(ch, fout);
508
						}
509 510 511
						else if (ch < '\040')
						{
							/* generate octal escape for control chars */
B
Bruce Momjian 已提交
512 513 514 515
							archputc('\\', fout);
							archputc(((ch >> 6) & 3) + '0', fout);
							archputc(((ch >> 3) & 7) + '0', fout);
							archputc((ch & 7) + '0', fout);
516 517
						}
						else
B
Bruce Momjian 已提交
518
							archputc(ch, fout);
519
					}
B
Bruce Momjian 已提交
520
					archputc('\'', fout);
521
					break;
522
			}
523
		}
B
Bruce Momjian 已提交
524
		archprintf(fout, ");\n");
525 526
	}
	PQclear(res);
B
Bruce Momjian 已提交
527
	return 1;
528 529 530 531
}

/*
 * DumpClasses -
532
 *	  dump the contents of all the classes.
533 534
 */
static void
B
Bruce Momjian 已提交
535
dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
536
			const char *onlytable, const bool oids, const bool force_quotes)
537 538
{

B
Bruce Momjian 已提交
539 540 541 542
	int				i;
	char	   		*all_only;
	DataDumperPtr	dumpFn;
	DumpContext		*dumpCtx;
543 544 545
	char			*oidsPart;
	char			copyBuf[512];
	char			*copyStmt;
546 547 548 549

	if (onlytable == NULL)
		all_only = "all";
	else
550
		all_only = "only";
551

552 553 554 555 556 557
	if (oids == true)
		oidsPart = "WITH OIDS ";
	else
		oidsPart = "";


558
	if (g_verbose)
559
		fprintf(stderr, "%s preparing to dump out the contents of %s %d table%s/sequence%s %s\n",
560 561
				g_comment_start, all_only,
				(onlytable == NULL) ? numTables : 1,
562
		  (onlytable == NULL) ? "s" : "", (onlytable == NULL) ? "s" : "",
563
				g_comment_end);
564

V
Vadim B. Mikheev 已提交
565 566 567 568 569 570 571 572 573 574
	/* Dump SEQUENCEs first (if dataOnly) */
	if (dataOnly)
	{
		for (i = 0; i < numTables; i++)
		{
			if (!(tblinfo[i].sequence))
				continue;
			if (!onlytable || (!strcmp(tblinfo[i].relname, onlytable)))
			{
				if (g_verbose)
575
					fprintf(stderr, "%s dumping out schema of sequence '%s' %s\n",
576
					 g_comment_start, tblinfo[i].relname, g_comment_end);
B
Bruce Momjian 已提交
577
				/* becomeUser(fout, tblinfo[i].usename); */
V
Vadim B. Mikheev 已提交
578 579 580 581
				dumpSequence(fout, tblinfo[i]);
			}
		}
	}
582 583 584

	for (i = 0; i < numTables; i++)
	{
585
		const char *classname = tblinfo[i].relname;
586 587

		/* Skip VIEW relations */
588
		if (tblinfo[i].viewdef != NULL)
589
			continue;
590 591

		if (tblinfo[i].sequence)/* already dumped */
V
Vadim B. Mikheev 已提交
592
			continue;
593 594 595 596

		if (!onlytable || (!strcmp(classname, onlytable)))
		{
			if (g_verbose)
597
				fprintf(stderr, "%s preparing to dump out the contents of Table '%s' %s\n",
598 599
						g_comment_start, classname, g_comment_end);

B
Bruce Momjian 已提交
600 601 602 603 604 605
			/* becomeUser(fout, tblinfo[i].usename); */

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

607 608
			if (!dumpData) /* Dump/restore using COPY */
			{
B
Bruce Momjian 已提交
609 610
				dumpFn = dumpClasses_nodumpData;
				/* dumpClasses_nodumpData(fout, classname, oids); */
611 612 613 614 615 616
				sprintf(copyBuf, "COPY %s %s FROM stdin;\n", fmtId(tblinfo[i].relname, force_quotes),
						oidsPart);
				copyStmt = copyBuf;
			}
			else /* Restore using INSERT */
			{
B
Bruce Momjian 已提交
617 618
				dumpFn = dumpClasses_dumpData;
				/* dumpClasses_dumpData(fout, classname); */
619 620
				copyStmt = NULL;
			}
B
Bruce Momjian 已提交
621 622

			ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
623
							"TABLE DATA", NULL, "", "", copyStmt, tblinfo[i].usename,
B
Bruce Momjian 已提交
624
							dumpFn, dumpCtx);
625
		}
626
	}
627 628
}

629
int
630
main(int argc, char **argv)
631
{
B
Bruce Momjian 已提交
632 633 634
	int			c;
	const char *progname;
	const char *filename = NULL;
B
Bruce Momjian 已提交
635
	const char *format = "p";
B
Bruce Momjian 已提交
636 637 638 639
	const char *dbname = NULL;
	const char *pghost = NULL;
	const char *pgport = NULL;
	char	   *tablename = NULL;
640
	bool		oids = false;
B
Bruce Momjian 已提交
641 642
	TableInfo  *tblinfo;
	int			numTables;
643
	bool		use_password = false;
B
Bruce Momjian 已提交
644
	int			compressLevel = -1;
645
	bool		ignore_version = false;
646 647
	int			plainText = 0;
	int			outputClean = 0;
648
	int			outputCreate = 0;
649
	int			outputBlobs = 0;
650 651 652
	int			outputNoOwner = 0;
	int			outputNoReconnect = 0;
	char		*outputSuperuser = NULL;
653

B
Bruce Momjian 已提交
654
	RestoreOptions	*ropt;
655

B
Hi,  
Bruce Momjian 已提交
656 657 658
#ifdef HAVE_GETOPT_LONG
	static struct option long_options[] = {
		{"data-only", no_argument, NULL, 'a'},
659
		{"blobs", no_argument, NULL, 'b' },
B
Hi,  
Bruce Momjian 已提交
660
		{"clean", no_argument, NULL, 'c'},
661
		{"create", no_argument, NULL, 'C'},
B
Bruce Momjian 已提交
662 663
		{"file", required_argument, NULL, 'f'},
		{"format", required_argument, NULL, 'F'},
664
		{"inserts", no_argument, NULL, 'd'},
665
		{"attribute-inserts", no_argument, NULL, 'D'},
B
Hi,  
Bruce Momjian 已提交
666
		{"host", required_argument, NULL, 'h'},
667
		{"ignore-version", no_argument, NULL, 'i'},
668
		{"no-reconnect", no_argument, NULL, 'R'},
B
Hi,  
Bruce Momjian 已提交
669 670
		{"no-quotes", no_argument, NULL, 'n'},
		{"quotes", no_argument, NULL, 'N'},
671
		{"oids", no_argument, NULL, 'o'},
672
		{"no-owner", no_argument, NULL, 'O'},
B
Hi,  
Bruce Momjian 已提交
673 674
		{"port", required_argument, NULL, 'p'},
		{"schema-only", no_argument, NULL, 's'},
675
		{"superuser", required_argument, NULL, 'S'},
B
Hi,  
Bruce Momjian 已提交
676 677 678 679
		{"table", required_argument, NULL, 't'},
		{"password", no_argument, NULL, 'u'},
		{"verbose", no_argument, NULL, 'v'},
		{"no-acl", no_argument, NULL, 'x'},
B
Bruce Momjian 已提交
680
		{"compress", required_argument, NULL, 'Z'},
B
Hi,  
Bruce Momjian 已提交
681
		{"help", no_argument, NULL, '?'},
682
		{"version", no_argument, NULL, 'V'}
683
	};
684 685
	int			optindex;

B
Hi,  
Bruce Momjian 已提交
686 687
#endif

688
	g_verbose = false;
689
	force_quotes = true;
690 691 692 693 694

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

695
	dataOnly = schemaOnly = dumpData = attrNames = false;
696

697 698 699 700
	if (!strrchr(argv[0], SEP_CHAR))
		progname = argv[0];
	else
		progname = strrchr(argv[0], SEP_CHAR) + 1;
701

702 703 704 705
	/* Set defaulty options based on progname */
	if (strcmp(progname, "pg_backup") == 0)
	{
		format = "c";
P
Philip Warner 已提交
706
		outputBlobs = true;
707
	}
708

B
Hi,  
Bruce Momjian 已提交
709
#ifdef HAVE_GETOPT_LONG
710
	while ((c = getopt_long(argc, argv, "abcCdDf:F:h:inNoOp:sS:t:uvxzZ:V?", long_options, &optindex)) != -1)
B
Hi,  
Bruce Momjian 已提交
711
#else
712
	while ((c = getopt(argc, argv, "abcCdDf:F:h:inNoOp:sS:t:uvxzZ:V?-")) != -1)
B
Hi,  
Bruce Momjian 已提交
713
#endif
714

715 716 717
	{
		switch (c)
		{
718
			case 'a':			/* Dump data only */
719
				dataOnly = true;
720
				break;
721

722 723 724 725
			case 'b':			/* Dump blobs */
				outputBlobs = true;
				break;

B
Bruce Momjian 已提交
726
			case 'c':			/* clean (i.e., drop) schema prior to
B
Bruce Momjian 已提交
727 728 729 730
 								 * create */
				outputClean = 1;
 				break;
 
731 732 733 734 735
			case 'C':			/* Create DB */

				outputCreate = 1;
				break;

736
			case 'd':			/* dump data as proper insert strings */
737
				dumpData = true;
738
				break;
739

740 741
			case 'D':			/* dump data as proper insert strings with
								 * attr names */
742 743
				dumpData = true;
				attrNames = true;
744
				break;
745

746
			case 'f':
747 748
				filename = optarg;
				break;
749

B
Bruce Momjian 已提交
750 751 752
			case 'F':
				format = optarg;
				break;
753

B
Bruce Momjian 已提交
754
			case 'h':			/* server host */
755 756
				pghost = optarg;
				break;
757

758 759 760
			case 'i':			/* ignore database version mismatch */
				ignore_version = true;
				break;
761

B
Bruce Momjian 已提交
762 763
			case 'n':			/* Do not force double-quotes on
								 * identifiers */
764
				force_quotes = false;
765
				break;
766

767
			case 'N':			/* Force double-quotes on identifiers */
768
				force_quotes = true;
769
				break;
770

771
			case 'o':			/* Dump oids */
772
				oids = true;
773
				break;
774 775


776 777 778
			case 'O':			/* Don't reconnect to match owner */
				outputNoOwner = 1;
				break;
779

780 781 782
			case 'p':			/* server port */
				pgport = optarg;
				break;
783

784 785 786
			case 'R':			/* No reconnect */
				outputNoReconnect = 1;
				break;
787

788
			case 's':			/* dump schema only */
789
				schemaOnly = true;
790
				break;
791

792 793 794
			case 'S':			/* Username for superuser in plain text output */
				outputSuperuser = strdup(optarg);
				break;
795

796
			case 't':			/* Dump data for this table only */
797
				{
798
					int			i;
799 800

					tablename = strdup(optarg);
B
Bruce Momjian 已提交
801 802 803 804 805

					/*
					 * quoted string? Then strip quotes and preserve
					 * case...
					 */
806 807 808
					if (tablename[0] == '"')
					{
						strcpy(tablename, &tablename[1]);
B
Bruce Momjian 已提交
809 810
						if (*(tablename + strlen(tablename) - 1) == '"')
							*(tablename + strlen(tablename) - 1) = '\0';
811 812 813 814 815
					}
					/* otherwise, convert table name to lowercase... */
					else
					{
						for (i = 0; tablename[i]; i++)
816 817
							if (isascii((int) tablename[i]) &&
								isupper((int) tablename[i]))
818 819
								tablename[i] = tolower(tablename[i]);
					}
820
				}
821
				break;
822

823 824 825
			case 'u':
				use_password = true;
				break;
826

827 828
			case 'v':			/* verbose */
				g_verbose = true;
829
				break;
830

831 832
			case 'x':			/* skip ACL dump */
				aclsSkip = true;
833
				break;
834

B
Bruce Momjian 已提交
835 836 837
			case 'Z':			/* Compression Level */
				compressLevel = atoi(optarg);
				break;
838

839 840 841 842
			case 'V':
				version();
				exit(0);
				break;
843

844
			case '?':
845 846 847 848 849 850 851 852 853 854 855 856 857 858 859

				/*
				 * getopt returns '?' on unknown argument. That's not
				 * quite what we want
				 */
				if (strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0)
				{
					help(progname);
					exit(1);
				}
				else
				{
					fputs("Try -? for help.\n", stderr);
					exit(1);
				}
860
				break;
861 862 863
#ifndef HAVE_GETOPT_LONG
			case '-':
				fprintf(stderr, "%s was compiled without support for long options.\n"
864
				   "Use -? for help on invocation options.\n", progname);
865 866 867
				exit(1);
				break;
#endif
868
			default:
869 870
				fprintf(stderr, "%s: unknown option -%c\nTry -? for help.\n", progname, c);
				exit(1);
871 872 873
		}
	}

P
Philip Warner 已提交
874 875 876 877 878 879 880 881
	if (optind < (argc - 1)) {
		fprintf(stderr,
				"%s: extra parameters found on command line after '%s' (first is '%s').\n"
			    "Please respecify command.\nUse -? for help on invocation options.\n",
				progname, argv[optind], argv[optind+1]);
		exit(1);
	}

B
Bruce Momjian 已提交
882 883 884 885 886 887 888 889
	if (dataOnly && schemaOnly)
	{
		fprintf(stderr,
				"%s: 'Schema Only' and 'Data Only' are incompatible options.\n",
				progname);
		exit(1);
	}

890 891 892 893 894 895 896 897
	if (outputBlobs && (tablename != NULL) )
	{
		fprintf(stderr,
				"%s: BLOB output is not supported for a single table. Use a full dump instead.\n",
				progname);
		exit(1);
	}

898 899 900
	if (dumpData == true && oids == true)
	{
		fprintf(stderr,
901
				"%s: INSERT's can not set oids, so INSERT and OID options can not be used together.\n",
902
				progname);
903
		exit(1);
904
	}
905

P
Philip Warner 已提交
906 907 908 909 910 911 912 913
	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);
	}

914
	/* open the output file */
B
Bruce Momjian 已提交
915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
	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;
930 931 932 933 934 935
			g_fout = CreateArchive(filename, archNull, 0);
			break;

		case 't':
		case 'T':
			g_fout = CreateArchive(filename, archTar, compressLevel);
B
Bruce Momjian 已提交
936 937 938
			break;

		default:
939
			fprintf(stderr,
B
Bruce Momjian 已提交
940 941 942 943 944 945 946 947 948 949
				"%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);
950 951
	}

952 953
	/* Let the archiver know how noisy to be */
	g_fout->verbose = g_verbose;
954

955
	dbname = argv[optind];
956

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

960 961 962 963 964 965 966 967
	/*
	 * Start serializable transaction to dump consistent data
	 */
	{
		PGresult   *res;

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

971 972 973
		PQclear(res);
		res = PQexec(g_conn, "set transaction isolation level serializable");
		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
974 975 976
		    exit_horribly(g_fout, "SET TRANSACTION command failed. Explanation from backend: '%s'.\n",
				PQerrorMessage(g_conn));

977 978 979
		PQclear(res);
	}

980
	g_last_builtin_oid = findLastBuiltinOid(dbname);
981

982 983 984 985
	/* Dump the database definition */
	if (!dataOnly)
		dumpDatabase(g_fout);

986
	if (oids == true)
987
		setMaxOid(g_fout);
B
Bruce Momjian 已提交
988 989

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

994
	if (!schemaOnly)
995 996 997 998 999 1000
	{
	    dumpClasses(tblinfo, numTables, g_fout, tablename, oids, force_quotes);
	}

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

1002 1003
	if (!dataOnly)				/* dump indexes and triggers at the end
								 * for performance */
V
Vadim B. Mikheev 已提交
1004 1005 1006
	{
		dumpSchemaIdx(g_fout, tablename, tblinfo, numTables);
		dumpTriggers(g_fout, tablename, tblinfo, numTables);
1007
		dumpRules(g_fout, tablename, tblinfo, numTables);
V
Vadim B. Mikheev 已提交
1008
	}
1009

1010 1011
	/* Now sort the output nicely */
	SortTocByOID(g_fout);
1012
	MoveToStart(g_fout, "DATABASE");
1013 1014 1015 1016 1017
	MoveToEnd(g_fout, "TABLE DATA");
	MoveToEnd(g_fout, "BLOBS");
	MoveToEnd(g_fout, "INDEX");
	MoveToEnd(g_fout, "TRIGGER");
	MoveToEnd(g_fout, "RULE");
1018
	MoveToEnd(g_fout, "SEQUENCE SET");
1019

B
Bruce Momjian 已提交
1020 1021 1022 1023 1024 1025
	if (plainText) 
	{
		ropt = NewRestoreOptions();
		ropt->filename = (char*)filename;
		ropt->dropSchema = outputClean;
		ropt->aclsSkip = aclsSkip;
1026 1027 1028 1029 1030 1031 1032 1033 1034
		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 已提交
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044

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

		RestoreArchive(g_fout, ropt);
	}

	CloseArchive(g_fout);
1045

1046 1047 1048
	clearTableInfo(tblinfo, numTables);
	PQfinish(g_conn);
	exit(0);
1049 1050
}

1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
/*
 * 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 */
1070
	appendPQExpBuffer(dbQry, "select (select usename from pg_user where datdba = usesysid) as dba from pg_database"
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
							" where datname = '%s'", PQdb(g_conn));

	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;
}


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
/*
 * 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 */
1130
    appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject");
1131 1132 1133 1134

	res = PQexec(g_conn, oidQry->data);
	if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
	{
1135 1136
		fprintf(stderr, "dumpBlobs(): Declare Cursor failed.  Explanation from backend: '%s'.\n", 
										PQerrorMessage(g_conn));
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 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
		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;
}

1192
/*
1193 1194
 * getTypes:
 *	  read all base types in the system catalogs and return them in the
1195 1196
 * TypeInfo* structure
 *
1197
 *	numTypes is set to the number of types read in
1198 1199
 *
 */
1200
TypeInfo   *
1201 1202
getTypes(int *numTypes)
{
B
Bruce Momjian 已提交
1203
	PGresult   *res;
1204 1205
	int			ntups;
	int			i;
1206
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1207
	TypeInfo   *tinfo;
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223

	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;
1224
	int			i_typedefn;
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236

	/* 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 已提交
1237
	appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
1238 1239 1240 1241 1242
		"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" );
1243

B
Hi, all  
Bruce Momjian 已提交
1244
	res = PQexec(g_conn, query->data);
1245 1246 1247
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1248
		fprintf(stderr, "getTypes(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
		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");
1271
	i_typedefn = PQfnumber(res, "typedefn");
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288

	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));
1289
		tinfo[i].typedefn = strdup(PQgetvalue(res, i, i_typedefn));
1290

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

1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313
		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;
1314 1315 1316 1317
}

/*
 * getOperators:
1318
 *	  read all operators in the system catalogs and return them in the
1319 1320
 * OprInfo* structure
 *
1321 1322
 *	numOprs is set to the number of operators read in
 *
1323 1324
 *
 */
1325
OprInfo    *
1326 1327
getOperators(int *numOprs)
{
1328
	PGresult   *res;
1329 1330
	int			ntups;
	int			i;
1331
	PQExpBuffer query = createPQExpBuffer();
1332

B
Bruce Momjian 已提交
1333
	OprInfo    *oprinfo;
1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348

	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;
1349 1350 1351 1352 1353 1354

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

B
Hi, all  
Bruce Momjian 已提交
1355
	appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
1356
			   "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
1357 1358 1359
					"oprcanhash, oprlsortop, oprrsortop, "
					"(select usename from pg_user where oprowner = usesysid) as usename "
					"from pg_operator");
1360

B
Hi, all  
Bruce Momjian 已提交
1361
	res = PQexec(g_conn, query->data);
1362 1363 1364
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1365
		fprintf(stderr, "getOperators(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404
		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));
1405 1406 1407 1408 1409

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

1410 1411 1412 1413 1414
	}

	PQclear(res);

	return oprinfo;
1415 1416
}

1417
void
1418
clearTypeInfo(TypeInfo *tp, int numTypes)
1419
{
1420
	int			i;
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453

	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);
1454 1455 1456
}

void
1457
clearFuncInfo(FuncInfo *fun, int numFuncs)
1458
{
1459 1460
	int			i,
				a;
1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471

	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);
1472
		for (a = 0; a < FUNC_MAX_ARGS; ++a)
1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
			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);
1483 1484
}

1485
static void
1486
clearTableInfo(TableInfo *tblinfo, int numTables)
1487
{
1488 1489
	int			i,
				j;
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509

	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 已提交
1510 1511
			if (tblinfo[i].attoids[j])
				free(tblinfo[i].attoids[j]);
1512 1513 1514 1515 1516
			if (tblinfo[i].attnames[j])
				free(tblinfo[i].attnames[j]);
			if (tblinfo[i].typnames[j])
				free(tblinfo[i].typnames[j]);
		}
B
Bruce Momjian 已提交
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532

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

1533 1534
		if (tblinfo[i].atttypmod)
			free((int *) tblinfo[i].atttypmod);
1535 1536 1537 1538
		if (tblinfo[i].inhAttrs)
			free((int *) tblinfo[i].inhAttrs);
		if (tblinfo[i].attnames)
			free(tblinfo[i].attnames);
1539 1540
		if (tblinfo[i].atttypedefns)
			free(tblinfo[i].atttypedefns);
1541 1542 1543 1544
		if (tblinfo[i].typnames)
			free(tblinfo[i].typnames);
		if (tblinfo[i].notnull)
			free(tblinfo[i].notnull);
1545 1546
		if (tblinfo[i].primary_key)
			free(tblinfo[i].primary_key);
1547 1548
		if (tblinfo[i].primary_key_name)
			free(tblinfo[i].primary_key_name);
1549 1550
	}
	free(tblinfo);
1551 1552
}

1553
void
1554
clearInhInfo(InhInfo *inh, int numInherits)
1555
{
1556
	int			i;
1557 1558 1559 1560 1561

	if (!inh)
		return;
	for (i = 0; i < numInherits; ++i)
	{
1562 1563
		if (inh[i].inhrelid)
			free(inh[i].inhrelid);
1564 1565 1566 1567
		if (inh[i].inhparent)
			free(inh[i].inhparent);
	}
	free(inh);
1568 1569 1570
}

void
1571
clearOprInfo(OprInfo *opr, int numOprs)
1572
{
1573
	int			i;
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608

	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);
1609 1610 1611
}

void
1612
clearIndInfo(IndInfo *ind, int numIndices)
1613
{
1614 1615
	int			i,
				a;
1616 1617 1618 1619 1620

	if (!ind)
		return;
	for (i = 0; i < numIndices; ++i)
	{
B
Bruce,  
Bruce Momjian 已提交
1621 1622
		if (ind[i].indoid)
			free(ind[i].indoid);
1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641
		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);
		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);
1642 1643 1644
}

void
B
Bruce Momjian 已提交
1645
clearAggInfo(AggInfo *agginfo, int numArgs)
1646
{
1647
	int			i;
1648 1649 1650 1651 1652 1653 1654 1655 1656

	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);
1657 1658
		if (agginfo[i].aggtransfn)
			free(agginfo[i].aggtransfn);
1659 1660
		if (agginfo[i].aggfinalfn)
			free(agginfo[i].aggfinalfn);
1661 1662
		if (agginfo[i].aggtranstype)
			free(agginfo[i].aggtranstype);
1663 1664
		if (agginfo[i].aggbasetype)
			free(agginfo[i].aggbasetype);
1665 1666
		if (agginfo[i].agginitval)
			free(agginfo[i].agginitval);
1667 1668 1669 1670
		if (agginfo[i].usename)
			free(agginfo[i].usename);
	}
	free(agginfo);
1671
}
1672 1673 1674

/*
 * getAggregates:
1675
 *	  read all the user-defined aggregates in the system catalogs and
1676 1677
 * return them in the AggInfo* structure
 *
1678 1679
 * numAggs is set to the number of aggregates read in
 *
1680 1681
 *
 */
1682
AggInfo    *
1683 1684
getAggregates(int *numAggs)
{
B
Bruce Momjian 已提交
1685
	PGresult   *res;
1686 1687
	int			ntups;
	int			i;
1688
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1689
	AggInfo    *agginfo;
1690 1691 1692

	int			i_oid;
	int			i_aggname;
1693
	int			i_aggtransfn;
1694
	int			i_aggfinalfn;
1695
	int			i_aggtranstype;
1696
	int			i_aggbasetype;
1697
	int			i_agginitval;
1698
	int			i_usename;
1699 1700 1701

	/* find all user-defined aggregates */

B
Hi, all  
Bruce Momjian 已提交
1702
	appendPQExpBuffer(query,
1703 1704 1705 1706 1707
						"SELECT pg_aggregate.oid, aggname, aggtransfn, "
						"aggfinalfn, aggtranstype, aggbasetype, "
						"agginitval, "
						"(select usename from pg_user where aggowner = usesysid) as usename "
						"from pg_aggregate" );
1708

B
Hi, all  
Bruce Momjian 已提交
1709
	res = PQexec(g_conn, query->data);
1710 1711 1712
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1713 1714
		fprintf(stderr, "getAggregates(): SELECT failed.  Explanation from backend: '%s'.\n",
					PQerrorMessage(g_conn));
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
		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");
1725
	i_aggtransfn = PQfnumber(res, "aggtransfn");
1726
	i_aggfinalfn = PQfnumber(res, "aggfinalfn");
1727
	i_aggtranstype = PQfnumber(res, "aggtranstype");
1728
	i_aggbasetype = PQfnumber(res, "aggbasetype");
1729
	i_agginitval = PQfnumber(res, "agginitval");
1730 1731 1732 1733 1734 1735
	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));
1736
		agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
1737
		agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
1738
		agginfo[i].aggtranstype = strdup(PQgetvalue(res, i, i_aggtranstype));
1739
		agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
1740
		agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
1741
		agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1742 1743 1744 1745
		if (strlen(agginfo[i].usename) == 0)
			fprintf(stderr, "WARNING: owner of aggregate '%s' appears to be invalid\n",
						agginfo[i].aggname);

1746 1747 1748 1749 1750
	}

	PQclear(res);

	return agginfo;
1751 1752 1753 1754
}

/*
 * getFuncs:
1755
 *	  read all the user-defined functions in the system catalogs and
1756 1757
 * return them in the FuncInfo* structure
 *
1758 1759
 * numFuncs is set to the number of functions read in
 *
1760 1761
 *
 */
1762
FuncInfo   *
1763 1764
getFuncs(int *numFuncs)
{
1765
	PGresult   *res;
1766 1767
	int			ntups;
	int			i;
1768 1769
	PQExpBuffer query = createPQExpBuffer();
	FuncInfo   *finfo;
1770 1771 1772 1773 1774 1775 1776 1777 1778 1779

	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;
1780
	int			i_iscachable;
1781
	int			i_isstrict;
1782
	int			i_usename;
1783 1784 1785

	/* find all user-defined funcs */

B
Hi, all  
Bruce Momjian 已提交
1786
	appendPQExpBuffer(query,
1787
		   "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
1788 1789
					  "proretset, proargtypes, prosrc, probin, "
					  "(select usename from pg_user where proowner = usesysid) as usename, "
1790
					  "proiscachable, proisstrict "
1791 1792
					  "from pg_proc "
				 "where pg_proc.oid > '%u'::oid",
1793
					  g_last_builtin_oid);
1794

B
Hi, all  
Bruce Momjian 已提交
1795
	res = PQexec(g_conn, query->data);
1796 1797 1798
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1799 1800
		fprintf(stderr, "getFuncs(): SELECT failed.  Explanation from backend: '%s'.\n", 
					PQerrorMessage(g_conn));
1801 1802 1803 1804 1805 1806 1807 1808 1809
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numFuncs = ntups;

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

1810 1811
	memset((char *) finfo, 0, ntups * sizeof(FuncInfo));

1812 1813 1814 1815 1816 1817 1818 1819 1820
	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");
1821
	i_iscachable = PQfnumber(res, "proiscachable");
1822
	i_isstrict = PQfnumber(res, "proisstrict");
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835
	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));

		finfo[i].prosrc = checkForQuote(PQgetvalue(res, i, i_prosrc));
		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));
1836
		finfo[i].lang = atoi(PQgetvalue(res, i, i_prolang));
1837
		finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1838
		finfo[i].iscachable = (strcmp(PQgetvalue(res, i, i_iscachable),"t") == 0);
1839
		finfo[i].isstrict = (strcmp(PQgetvalue(res, i, i_isstrict),"t") == 0);
1840 1841 1842 1843 1844

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

1845 1846 1847 1848
		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);
1849
			exit(1);
1850 1851 1852 1853
		}
		parseNumericArray(PQgetvalue(res, i, i_proargtypes),
						  finfo[i].argtypes,
						  finfo[i].nargs);
1854 1855 1856 1857 1858 1859
		finfo[i].dumped = 0;
	}

	PQclear(res);

	return finfo;
1860 1861 1862 1863 1864

}

/*
 * getTables
1865
 *	  read all the user-defined tables (no indices, no catalogs)
1866 1867
 * in the system catalogs return them in the TableInfo* structure
 *
1868 1869
 * numTables is set to the number of tables read in
 *
1870 1871
 *
 */
1872
TableInfo  *
V
Vadim B. Mikheev 已提交
1873
getTables(int *numTables, FuncInfo *finfo, int numFuncs)
1874
{
1875
	PGresult   *res;
1876 1877
	int			ntups;
	int			i;
1878
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1879
	PQExpBuffer delqry = createPQExpBuffer();
1880
	TableInfo  *tblinfo;
1881

B
Bruce Momjian 已提交
1882
	int			i_reloid;
1883 1884 1885 1886
	int			i_relname;
	int			i_relkind;
	int			i_relacl;
	int			i_usename;
V
Vadim B. Mikheev 已提交
1887 1888
	int			i_relchecks;
	int			i_reltriggers;
1889
	int			i_relhasindex;
1890 1891 1892 1893 1894

	char		relkindview[2];

	relkindview[0] = RELKIND_VIEW;
	relkindview[1] = '\0';
1895 1896 1897 1898 1899 1900

	/*
	 * 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*
	 *
1901
	 * we ignore tables that are not type 'r' (ordinary relation) or 'S'
1902
	 * (sequence) or 'v' (view).
1903 1904
	 */

B
Hi, all  
Bruce Momjian 已提交
1905
	appendPQExpBuffer(query,
1906 1907
			   "SELECT pg_class.oid, relname, relkind, relacl, "
					  "(select usename from pg_user where relowner = usesysid) as usename, "
1908
					  "relchecks, reltriggers, relhasindex "
1909 1910
					  "from pg_class "
					  "where relname !~ '^pg_' "
1911 1912 1913
					  "and relkind in ('%c', '%c', '%c') "
					  "order by oid",
				RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
1914

B
Hi, all  
Bruce Momjian 已提交
1915
	res = PQexec(g_conn, query->data);
1916 1917 1918
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1919 1920
		fprintf(stderr, "getTables(): SELECT failed.  Explanation from backend: '%s'.\n", 
					PQerrorMessage(g_conn));
1921 1922 1923 1924 1925 1926 1927 1928 1929
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numTables = ntups;

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

B
Bruce Momjian 已提交
1930
	i_reloid = PQfnumber(res, "oid");
1931 1932 1933 1934
	i_relname = PQfnumber(res, "relname");
	i_relkind = PQfnumber(res, "relkind");
	i_relacl = PQfnumber(res, "relacl");
	i_usename = PQfnumber(res, "usename");
V
Vadim B. Mikheev 已提交
1935 1936
	i_relchecks = PQfnumber(res, "relchecks");
	i_reltriggers = PQfnumber(res, "reltriggers");
B
Hi, all  
Bruce Momjian 已提交
1937
	i_relhasindex = PQfnumber(res, "relhasindex");
1938 1939 1940

	for (i = 0; i < ntups; i++)
	{
B
Bruce Momjian 已提交
1941
		tblinfo[i].oid = strdup(PQgetvalue(res, i, i_reloid));
1942 1943 1944 1945
		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 已提交
1946 1947
		tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
		tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
1948

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

1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993
		/* Get view definition */
		if (strcmp(PQgetvalue(res, i, i_relkind), relkindview) == 0)
		{
			PGresult   *res2;

			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "SELECT pg_get_viewdef('%s') as viewdef ", tblinfo[i].relname);
			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 已提交
1994 1995 1996
		/*
		 * Exclude inherited CHECKs from CHECK constraints total. If a
		 * constraint matches by name and condition with a constraint
1997 1998 1999 2000
		 * belonging to a parent class, we assume it was inherited.
		 */
		if (tblinfo[i].ncheck > 0)
		{
B
Bruce Momjian 已提交
2001
			PGresult   *res2;
2002 2003
			int			ntups2;

B
Bruce Momjian 已提交
2004
			if (g_verbose)
2005 2006 2007 2008 2009 2010
				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 已提交
2011 2012
			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "SELECT rcname from pg_relcheck, pg_inherits as i "
2013 2014 2015 2016 2017 2018 2019 2020
							  "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 已提交
2021
			res2 = PQexec(g_conn, query->data);
2022 2023 2024
			if (!res2 ||
				PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
2025 2026
				fprintf(stderr, "getTables(): SELECT (for inherited CHECK) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
				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 已提交
2042 2043 2044
		if (tblinfo[i].ncheck > 0)
		{
			PGresult   *res2;
2045 2046
			int			i_rcname,
						i_rcsrc;
V
Vadim B. Mikheev 已提交
2047 2048
			int			ntups2;
			int			i2;
2049

V
Vadim B. Mikheev 已提交
2050
			if (g_verbose)
2051
				fprintf(stderr, "%s finding CHECK constraints for relation: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2052 2053 2054
						g_comment_start,
						tblinfo[i].relname,
						g_comment_end);
2055

B
Hi, all  
Bruce Momjian 已提交
2056 2057
			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
2058 2059 2060 2061 2062 2063 2064 2065
							  "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 已提交
2066
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2067
			if (!res2 ||
2068
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2069
			{
B
Bruce Momjian 已提交
2070 2071
				fprintf(stderr, "getTables(): SELECT (for CHECK) failed.  "
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2072 2073 2074 2075 2076
				exit_nicely(g_conn);
			}
			ntups2 = PQntuples(res2);
			if (ntups2 != tblinfo[i].ncheck)
			{
2077
				fprintf(stderr, "getTables(): relation '%s': %d CHECKs were expected, but got %d\n",
2078
						tblinfo[i].relname, tblinfo[i].ncheck, ntups2);
V
Vadim B. Mikheev 已提交
2079 2080 2081 2082
				exit_nicely(g_conn);
			}
			i_rcname = PQfnumber(res2, "rcname");
			i_rcsrc = PQfnumber(res2, "rcsrc");
2083
			tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
V
Vadim B. Mikheev 已提交
2084 2085
			for (i2 = 0; i2 < ntups2; i2++)
			{
B
Bruce Momjian 已提交
2086 2087
				const char *name = PQgetvalue(res2, i2, i_rcname);
				const char *expr = PQgetvalue(res2, i2, i_rcsrc);
2088

B
Hi, all  
Bruce Momjian 已提交
2089
				resetPQExpBuffer(query);
2090 2091
				if (name[0] != '$')
				{
2092 2093
					appendPQExpBuffer(query, "CONSTRAINT %s ",
									  fmtId(name, force_quotes));
B
Bruce Momjian 已提交
2094
				}
2095
				appendPQExpBuffer(query, "CHECK (%s)", expr);
B
Hi, all  
Bruce Momjian 已提交
2096
				tblinfo[i].check_expr[i2] = strdup(query->data);
V
Vadim B. Mikheev 已提交
2097 2098 2099 2100 2101
			}
			PQclear(res2);
		}
		else
			tblinfo[i].check_expr = NULL;
2102

2103 2104
		/* Get primary key */
		if (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0)
2105
		{
2106 2107 2108
			PGresult   *res2;
			char		str[INDEX_MAX_KEYS * (NAMEDATALEN * 2 + 4) + 1];
			int			j;
B
Bruce Momjian 已提交
2109

B
Hi, all  
Bruce Momjian 已提交
2110
			resetPQExpBuffer(query);
B
Bruce Momjian 已提交
2111
			appendPQExpBuffer(query,
2112 2113 2114 2115 2116 2117
							  "SELECT a.attname "
						   "FROM pg_index i, pg_class c, pg_attribute a "
							  "WHERE i.indisprimary AND i.indrelid = %s "
							  "  AND i.indexrelid = c.oid AND a.attnum > 0 AND a.attrelid = c.oid "
							  "ORDER BY a.attnum ",
							  tblinfo[i].oid);
2118
			res2 = PQexec(g_conn, query->data);
B
Bruce Momjian 已提交
2119 2120 2121
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
				fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY) failed.  Explanation from backend: %s",
2122
						PQerrorMessage(g_conn));
B
Bruce Momjian 已提交
2123 2124
				exit_nicely(g_conn);
			}
2125

2126 2127 2128
			str[0] = '\0';
			for (j = 0; j < PQntuples(res2); j++)
			{
2129
				if (strlen(str) > 0)
2130 2131 2132 2133
					strcat(str, ", ");
				strcat(str, fmtId(PQgetvalue(res2, j, 0), force_quotes));
			}

2134 2135
			if (strlen(str) > 0)
			{
2136
				tblinfo[i].primary_key = strdup(str);
2137 2138
				if (tblinfo[i].primary_key == NULL)
				{
2139 2140 2141 2142 2143 2144
					perror("strdup");
					exit(1);
				}
			}
			else
				tblinfo[i].primary_key = NULL;
2145
		}
2146 2147
		else
			tblinfo[i].primary_key = NULL;
B
Bruce Momjian 已提交
2148

2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 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
		/* Get primary key name (if primary key exist) */
		if (tblinfo[i].primary_key)
		{
			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 已提交
2192 2193 2194 2195
		/* Get Triggers */
		if (tblinfo[i].ntrig > 0)
		{
			PGresult   *res2;
B
Bruce,  
Bruce Momjian 已提交
2196
			int			i_tgoid,
2197
						i_tgname,
2198 2199 2200
						i_tgfoid,
						i_tgtype,
						i_tgnargs,
2201 2202 2203 2204 2205
						i_tgargs,
						i_tgisconstraint,
						i_tgconstrname,
						i_tgdeferrable,
						i_tginitdeferred;
V
Vadim B. Mikheev 已提交
2206 2207
			int			ntups2;
			int			i2;
2208

V
Vadim B. Mikheev 已提交
2209
			if (g_verbose)
2210
				fprintf(stderr, "%s finding Triggers for relation: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2211 2212 2213
						g_comment_start,
						tblinfo[i].relname,
						g_comment_end);
2214

B
Hi, all  
Bruce Momjian 已提交
2215
			resetPQExpBuffer(query);
2216
			appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, tgisconstraint, tgconstrname, tgdeferrable, tginitdeferred, oid "
2217 2218 2219
							  "from pg_trigger "
							  "where tgrelid = '%s'::oid ",
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2220
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2221
			if (!res2 ||
2222
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2223
			{
B
Bruce Momjian 已提交
2224 2225
				fprintf(stderr, "getTables(): SELECT (for TRIGGER) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2226 2227 2228 2229 2230
				exit_nicely(g_conn);
			}
			ntups2 = PQntuples(res2);
			if (ntups2 != tblinfo[i].ntrig)
			{
2231
				fprintf(stderr, "getTables(): relation '%s': %d Triggers were expected, but got %d\n",
2232
						tblinfo[i].relname, tblinfo[i].ntrig, ntups2);
V
Vadim B. Mikheev 已提交
2233 2234 2235 2236 2237 2238 2239
				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 已提交
2240
			i_tgoid = PQfnumber(res2, "oid");
2241 2242 2243 2244 2245
			i_tgisconstraint = PQfnumber(res2, "tgisconstraint");
			i_tgconstrname = PQfnumber(res2, "tgconstrname");
			i_tgdeferrable = PQfnumber(res2, "tgdeferrable");
			i_tginitdeferred = PQfnumber(res2, "tginitdeferred");

B
Bruce Momjian 已提交
2246
			tblinfo[i].triggers = (TrigInfo*) malloc(ntups2 * sizeof(TrigInfo));
B
Hi, all  
Bruce Momjian 已提交
2247 2248
			resetPQExpBuffer(query);
			for (i2 = 0; i2 < ntups2; i2++)
V
Vadim B. Mikheev 已提交
2249
			{
2250
				const char *tgfuncoid = PQgetvalue(res2, i2, i_tgfoid);
2251
				char	   *tgfunc = NULL;
2252 2253
				int2		tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
				int			tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
B
Bruce Momjian 已提交
2254
				const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
2255 2256 2257
				int			tgisconstraint;
				int			tgdeferrable;
				int			tginitdeferred;
B
Bruce Momjian 已提交
2258
				const char *p;
2259 2260
				int			findx;

2261
				if (strcmp(PQgetvalue(res2, i2, i_tgisconstraint), "f") == 0)
2262
					tgisconstraint = 0;
2263
				else
2264
					tgisconstraint = 1;
2265 2266

				if (strcmp(PQgetvalue(res2, i2, i_tgdeferrable), "f") == 0)
2267
					tgdeferrable = 0;
2268
				else
2269
					tgdeferrable = 1;
2270 2271

				if (strcmp(PQgetvalue(res2, i2, i_tginitdeferred), "f") == 0)
2272
					tginitdeferred = 0;
2273
				else
2274
					tginitdeferred = 1;
2275

V
Vadim B. Mikheev 已提交
2276 2277
				for (findx = 0; findx < numFuncs; findx++)
				{
2278
					if (strcmp(finfo[findx].oid, tgfuncoid) == 0 &&
2279
						finfo[findx].nargs == 0 &&
V
Vadim B. Mikheev 已提交
2280 2281 2282
						strcmp(finfo[findx].prorettype, "0") == 0)
						break;
				}
2283

V
Vadim B. Mikheev 已提交
2284 2285
				if (findx == numFuncs)
				{
2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306
					PGresult   *r;

					/*
					 * 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)
					{
						fprintf(stderr, "getTables(): SELECT (funcname) failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
						exit_nicely(g_conn);
					}
2307
					tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
2308
					PQclear(r);
2309
				}
2310
				else
2311
					tgfunc = strdup(finfo[findx].proname);
B
Bruce Momjian 已提交
2312 2313

				appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
2314
									fmtId(PQgetvalue(res2, i2, i_tgname),
B
Bruce Momjian 已提交
2315 2316 2317
									force_quotes));
				appendPQExpBuffer(delqry, "ON %s;\n",
									fmtId(tblinfo[i].relname, force_quotes));
2318

B
Hi, all  
Bruce Momjian 已提交
2319
				resetPQExpBuffer(query);
2320 2321 2322 2323 2324
				if (tgisconstraint)
				{
					appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgconstrname), force_quotes));
				}
2325 2326
				else
				{
2327 2328 2329
					appendPQExpBuffer(query, "CREATE TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
				}
B
Bruce Momjian 已提交
2330
				appendPQExpBufferChar(query, ' ');
V
Vadim B. Mikheev 已提交
2331 2332 2333
				/* Trigger type */
				findx = 0;
				if (TRIGGER_FOR_BEFORE(tgtype))
B
Hi, all  
Bruce Momjian 已提交
2334
					appendPQExpBuffer(query, "BEFORE");
V
Vadim B. Mikheev 已提交
2335
				else
B
Hi, all  
Bruce Momjian 已提交
2336
					appendPQExpBuffer(query, "AFTER");
V
Vadim B. Mikheev 已提交
2337 2338
				if (TRIGGER_FOR_INSERT(tgtype))
				{
B
Hi, all  
Bruce Momjian 已提交
2339
					appendPQExpBuffer(query, " INSERT");
V
Vadim B. Mikheev 已提交
2340 2341 2342 2343 2344
					findx++;
				}
				if (TRIGGER_FOR_DELETE(tgtype))
				{
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2345
						appendPQExpBuffer(query, " OR DELETE");
V
Vadim B. Mikheev 已提交
2346
					else
B
Hi, all  
Bruce Momjian 已提交
2347
						appendPQExpBuffer(query, " DELETE");
V
Vadim B. Mikheev 已提交
2348 2349 2350
					findx++;
				}
				if (TRIGGER_FOR_UPDATE(tgtype))
2351
				{
V
Vadim B. Mikheev 已提交
2352
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2353
						appendPQExpBuffer(query, " OR UPDATE");
V
Vadim B. Mikheev 已提交
2354
					else
B
Hi, all  
Bruce Momjian 已提交
2355
						appendPQExpBuffer(query, " UPDATE");
2356
				}
2357 2358
				appendPQExpBuffer(query, " ON %s ", fmtId(tblinfo[i].relname, force_quotes));

2359
				if (tgisconstraint)
2360
				{
2361
					if (!tgdeferrable)
2362 2363 2364 2365
						appendPQExpBuffer(query, " NOT");
					appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
					if (tginitdeferred)
						appendPQExpBuffer(query, "DEFERRED");
2366
					else
2367
						appendPQExpBuffer(query, "IMMEDIATE");
2368

2369 2370 2371
				}

				appendPQExpBuffer(query, " FOR EACH ROW");
2372 2373
				appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
								  fmtId(tgfunc, force_quotes));
V
Vadim B. Mikheev 已提交
2374 2375
				for (findx = 0; findx < tgnargs; findx++)
				{
2376
					const char *s;
2377 2378

					for (p = tgargs;;)
V
Vadim B. Mikheev 已提交
2379
					{
2380
						p = strchr(p, '\\');
V
Vadim B. Mikheev 已提交
2381 2382
						if (p == NULL)
						{
B
Bruce Momjian 已提交
2383 2384
							fprintf(stderr, "getTables(): relation '%s': bad argument "
									"string (%s) for trigger '%s'\n",
2385 2386 2387
									tblinfo[i].relname,
									PQgetvalue(res2, i2, i_tgargs),
									PQgetvalue(res2, i2, i_tgname));
V
Vadim B. Mikheev 已提交
2388 2389 2390 2391 2392 2393 2394 2395
							exit_nicely(g_conn);
						}
						p++;
						if (*p == '\\')
						{
							p++;
							continue;
						}
2396
						if (p[0] == '0' && p[1] == '0' && p[2] == '0')
V
Vadim B. Mikheev 已提交
2397 2398 2399
							break;
					}
					p--;
2400
					appendPQExpBufferChar(query, '\'');
B
Bruce Momjian 已提交
2401
					for (s = tgargs; s < p;)
V
Vadim B. Mikheev 已提交
2402 2403
					{
						if (*s == '\'')
2404 2405
							appendPQExpBufferChar(query, '\\');
						appendPQExpBufferChar(query, *s++);
V
Vadim B. Mikheev 已提交
2406
					}
B
Bruce Momjian 已提交
2407 2408
					appendPQExpBufferChar(query, '\'');
					appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
V
Vadim B. Mikheev 已提交
2409 2410
					tgargs = p + 4;
				}
B
Hi, all  
Bruce Momjian 已提交
2411
				appendPQExpBuffer(query, ");\n");
2412

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

				/*** Initialize trcomments and troids ***/
2416

B
Bruce,  
Bruce Momjian 已提交
2417
				resetPQExpBuffer(query);
2418 2419
				appendPQExpBuffer(query, "TRIGGER %s ",
					fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
B
Bruce,  
Bruce Momjian 已提交
2420
				appendPQExpBuffer(query, "ON %s",
2421
								fmtId(tblinfo[i].relname, force_quotes));
B
Bruce Momjian 已提交
2422 2423 2424 2425
				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 已提交
2426

2427 2428
				if (tgfunc)
					free(tgfunc);
V
Vadim B. Mikheev 已提交
2429 2430 2431 2432
			}
			PQclear(res2);
		}
		else
B
Bruce,  
Bruce Momjian 已提交
2433
		{
V
Vadim B. Mikheev 已提交
2434
			tblinfo[i].triggers = NULL;
B
Bruce,  
Bruce Momjian 已提交
2435
		}
2436

2437 2438 2439 2440 2441
	}

	PQclear(res);

	return tblinfo;
2442 2443 2444 2445 2446

}

/*
 * getInherits
2447
 *	  read all the inheritance information
2448 2449
 * from the system catalogs return them in the InhInfo* structure
 *
2450 2451
 * numInherits is set to the number of tables read in
 *
2452 2453
 *
 */
2454
InhInfo    *
2455 2456
getInherits(int *numInherits)
{
2457
	PGresult   *res;
2458 2459
	int			ntups;
	int			i;
2460 2461
	PQExpBuffer query = createPQExpBuffer();
	InhInfo    *inhinfo;
2462

2463
	int			i_inhrelid;
2464
	int			i_inhparent;
2465 2466 2467

	/* find all the inheritance information */

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

B
Hi, all  
Bruce Momjian 已提交
2470
	res = PQexec(g_conn, query->data);
2471 2472 2473
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2474 2475
		fprintf(stderr, "getInherits(): SELECT failed.  Explanation from backend: '%s'.\n", 
				PQerrorMessage(g_conn));
2476 2477 2478 2479 2480 2481 2482 2483 2484
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numInherits = ntups;

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

2485
	i_inhrelid = PQfnumber(res, "inhrelid");
2486 2487 2488 2489
	i_inhparent = PQfnumber(res, "inhparent");

	for (i = 0; i < ntups; i++)
	{
2490
		inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
2491 2492 2493 2494 2495
		inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
	}

	PQclear(res);
	return inhinfo;
2496 2497 2498 2499
}

/*
 * getTableAttrs -
2500 2501
 *	  for each table in tblinfo, read its attributes types and names
 *
2502
 * this is implemented in a very inefficient way right now, looping
2503
 * through the tblinfo and doing a join per table to find the attrs and their
2504 2505
 * types
 *
2506
 *	modifies tblinfo
2507 2508
 */
void
2509
getTableAttrs(TableInfo *tblinfo, int numTables)
2510
{
2511 2512
	int			i,
				j;
2513
	PQExpBuffer q = createPQExpBuffer();
2514 2515
	int			i_attname;
	int			i_typname;
2516
	int			i_atttypmod;
2517
	int			i_attnotnull;
V
Vadim B. Mikheev 已提交
2518
	int			i_atthasdef;
2519
	int			i_attoid;
2520
	int			i_atttypedefn;
2521
	PGresult   *res;
2522
	int			ntups;
2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537

	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)
2538
			fprintf(stderr, "%s finding the attrs and types for table: '%s' %s\n",
2539 2540 2541 2542
					g_comment_start,
					tblinfo[i].relname,
					g_comment_end);

B
Hi, all  
Bruce Momjian 已提交
2543
		resetPQExpBuffer(q);
B
Bruce,  
Bruce Momjian 已提交
2544
		appendPQExpBuffer(q, "SELECT a.oid as attoid, a.attnum, a.attname, t.typname, a.atttypmod, "
2545
						  "a.attnotnull, a.atthasdef, format_type(a.atttypid, a.atttypmod) as atttypedefn "
2546 2547 2548 2549
						  "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 已提交
2550
		res = PQexec(g_conn, q->data);
2551 2552 2553
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
B
Bruce Momjian 已提交
2554 2555
			fprintf(stderr, "getTableAttrs(): SELECT failed.  "
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2556 2557 2558 2559 2560
			exit_nicely(g_conn);
		}

		ntups = PQntuples(res);

B
Bruce,  
Bruce Momjian 已提交
2561
		i_attoid = PQfnumber(res, "attoid");
2562 2563
		i_attname = PQfnumber(res, "attname");
		i_typname = PQfnumber(res, "typname");
2564
		i_atttypmod = PQfnumber(res, "atttypmod");
2565
		i_attnotnull = PQfnumber(res, "attnotnull");
V
Vadim B. Mikheev 已提交
2566
		i_atthasdef = PQfnumber(res, "atthasdef");
2567
		i_atttypedefn = PQfnumber(res, "atttypedefn");
2568 2569

		tblinfo[i].numatts = ntups;
B
Bruce,  
Bruce Momjian 已提交
2570
		tblinfo[i].attoids = (char **) malloc(ntups * sizeof(char *));
2571
		tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
2572
		tblinfo[i].atttypedefns = (char **) malloc(ntups * sizeof(char *));
2573
		tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
2574
		tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
2575 2576
		tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
		tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
V
Vadim B. Mikheev 已提交
2577
		tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
2578 2579 2580 2581
		tblinfo[i].parentRels = NULL;
		tblinfo[i].numParents = 0;
		for (j = 0; j < ntups; j++)
		{
B
Bruce,  
Bruce Momjian 已提交
2582
			tblinfo[i].attoids[j] = strdup(PQgetvalue(res, j, i_attoid));
2583
			tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
2584
			tblinfo[i].atttypedefns[j] = strdup(PQgetvalue(res, j, i_atttypedefn));
2585
			tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
2586
			tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
2587 2588 2589
			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 已提交
2590 2591 2592
			if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
			{
				PGresult   *res2;
2593

V
Vadim B. Mikheev 已提交
2594
				if (g_verbose)
2595
					fprintf(stderr, "%s finding DEFAULT expression for attr: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2596 2597 2598
							g_comment_start,
							tblinfo[i].attnames[j],
							g_comment_end);
2599

B
Hi, all  
Bruce Momjian 已提交
2600 2601
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
2602 2603
							 "where adrelid = '%s'::oid and adnum = %d ",
								  tblinfo[i].oid, j + 1);
B
Hi, all  
Bruce Momjian 已提交
2604
				res2 = PQexec(g_conn, q->data);
V
Vadim B. Mikheev 已提交
2605
				if (!res2 ||
2606
					PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2607
				{
B
Bruce Momjian 已提交
2608 2609
					fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2610 2611 2612 2613 2614 2615 2616
					exit_nicely(g_conn);
				}
				tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
				PQclear(res2);
			}
			else
				tblinfo[i].adef_expr[j] = NULL;
2617 2618 2619
		}
		PQclear(res);
	}
2620 2621 2622 2623 2624
}


/*
 * getIndices
2625
 *	  read all the user-defined indices information
2626 2627
 * from the system catalogs return them in the InhInfo* structure
 *
2628 2629
 * numIndices is set to the number of indices read in
 *
2630 2631
 *
 */
2632
IndInfo    *
2633 2634
getIndices(int *numIndices)
{
2635
	int			i;
2636
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2637
	PGresult   *res;
2638
	int			ntups;
B
Bruce Momjian 已提交
2639
	IndInfo    *indinfo;
2640 2641 2642 2643 2644 2645 2646 2647

	int			i_indexrelname;
	int			i_indrelname;
	int			i_indamname;
	int			i_indproc;
	int			i_indkey;
	int			i_indclass;
	int			i_indisunique;
2648
	int			i_indoid;
2649 2650 2651 2652 2653

	/*
	 * find all the user-defined indices. We do not handle partial
	 * indices.
	 *
2654
	 * Notice we skip indices on system classes
2655 2656 2657 2658
	 *
	 * this is a 4-way join !!
	 */

B
Hi, all  
Bruce Momjian 已提交
2659
	appendPQExpBuffer(query,
2660 2661 2662 2663 2664 2665
					  "SELECT t1.oid as indoid, t1.relname as indexrelname, t2.relname as indrelname, "
					  "i.indproc, i.indkey, i.indclass, "
					  "a.amname as indamname, i.indisunique "
					"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 "
2666 2667
					  "and t2.relname !~ '^pg_' and not i.indisprimary",
					  g_last_builtin_oid);
2668

B
Hi, all  
Bruce Momjian 已提交
2669
	res = PQexec(g_conn, query->data);
2670 2671 2672
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2673 2674
		fprintf(stderr, "getIndices(): SELECT failed.  "
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2675 2676 2677 2678 2679 2680 2681 2682 2683
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numIndices = ntups;

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

2684 2685
	memset((char *) indinfo, 0, ntups * sizeof(IndInfo));

B
Bruce,  
Bruce Momjian 已提交
2686
	i_indoid = PQfnumber(res, "indoid");
2687 2688 2689 2690 2691 2692 2693 2694 2695 2696
	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");

	for (i = 0; i < ntups; i++)
	{
B
Bruce,  
Bruce Momjian 已提交
2697
		indinfo[i].indoid = strdup(PQgetvalue(res, i, i_indoid));
2698 2699 2700 2701
		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));
2702 2703 2704 2705 2706 2707
		parseNumericArray(PQgetvalue(res, i, i_indkey),
						  indinfo[i].indkey,
						  INDEX_MAX_KEYS);
		parseNumericArray(PQgetvalue(res, i, i_indclass),
						  indinfo[i].indclass,
						  INDEX_MAX_KEYS);
2708 2709 2710 2711
		indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
	}
	PQclear(res);
	return indinfo;
2712 2713
}

B
Bruce,  
Bruce Momjian 已提交
2714
/*------------------------------------------------------------------
2715
 * dumpComments --
B
Bruce,  
Bruce Momjian 已提交
2716
 *
2717
 * This routine is used to dump any comments associated with the
B
Bruce,  
Bruce Momjian 已提交
2718 2719 2720 2721
 * 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
2722
 * addition, the routine takes the stdio FILE handle to which the
B
Bruce,  
Bruce Momjian 已提交
2723 2724 2725 2726
 * output should be written.
 *------------------------------------------------------------------
*/

T
Tom Lane 已提交
2727
static void
B
Bruce Momjian 已提交
2728
dumpComment(Archive *fout, const char *target, const char *oid)
2729
{
B
Bruce,  
Bruce Momjian 已提交
2730

2731
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
2732
	PQExpBuffer query;
2733
	int			i_description;
B
Bruce,  
Bruce Momjian 已提交
2734 2735 2736 2737 2738 2739 2740 2741 2742 2743

	/*** 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);
2744 2745
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce,  
Bruce Momjian 已提交
2746 2747 2748 2749 2750 2751 2752
		fprintf(stderr, "DumpComment: SELECT failed: '%s'.\n",
				PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

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

2753 2754
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2755
		i_description = PQfnumber(res, "description");
B
Bruce Momjian 已提交
2756 2757 2758 2759 2760
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "COMMENT ON %s IS '%s';\n",
							target, checkForQuote(PQgetvalue(res, 0, i_description)));

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

B
Bruce,  
Bruce Momjian 已提交
2763 2764 2765 2766 2767
	}

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

	PQclear(res);
2768

B
Bruce,  
Bruce Momjian 已提交
2769 2770 2771
}

/*------------------------------------------------------------------
2772
 * dumpDBComment --
B
Bruce,  
Bruce Momjian 已提交
2773
 *
2774 2775
 * 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 已提交
2776 2777 2778 2779 2780
 * to dump the schema of the database, then this is the first
 * statement issued.
 *------------------------------------------------------------------
*/

2781
void
B
Bruce Momjian 已提交
2782
dumpDBComment(Archive *fout)
2783
{
B
Bruce,  
Bruce Momjian 已提交
2784

2785
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
2786
	PQExpBuffer query;
2787
	int			i_oid;
B
Bruce,  
Bruce Momjian 已提交
2788 2789 2790 2791 2792 2793 2794 2795 2796 2797

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

	query = createPQExpBuffer();
	appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = '%s'",
					  PQdb(g_conn));

	/*** Execute query ***/

	res = PQexec(g_conn, query->data);
2798 2799
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce,  
Bruce Momjian 已提交
2800 2801 2802 2803 2804 2805 2806
		fprintf(stderr, "dumpDBComment: SELECT failed: '%s'.\n",
				PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

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

2807 2808
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2809 2810 2811 2812 2813 2814 2815 2816 2817
		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);
2818

B
Bruce,  
Bruce Momjian 已提交
2819 2820
}

2821 2822
/*
 * dumpTypes
2823
 *	  writes out to fout the queries to recreate all the user-defined types
2824 2825 2826
 *
 */
void
B
Bruce Momjian 已提交
2827
dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
2828
		  TypeInfo *tinfo, int numTypes)
2829
{
2830
	int			i;
2831
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
2832
	PQExpBuffer	delq = createPQExpBuffer();
2833
	int			funcInd;
2834 2835 2836 2837 2838

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

		/* skip all the builtin types */
2839
		if (atooid(tinfo[i].oid) <= g_last_builtin_oid)
2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862
			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 已提交
2863
		appendPQExpBuffer(delq, "DROP TYPE %s;\n", fmtId(tinfo[i].typname, force_quotes));
2864

B
Hi, all  
Bruce Momjian 已提交
2865 2866
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877
						  "CREATE TYPE %s "
			   "( internallength = %s, externallength = %s, input = %s, "
				  "output = %s, send = %s, receive = %s, default = '%s'",
						  fmtId(tinfo[i].typname, force_quotes),
						  tinfo[i].typlen,
						  tinfo[i].typprtlen,
						  tinfo[i].typinput,
						  tinfo[i].typoutput,
						  tinfo[i].typsend,
						  tinfo[i].typreceive,
						  tinfo[i].typdefault);
2878 2879 2880

		if (tinfo[i].isArray)
		{
2881
			char	   *elemType;
2882

2883
			elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
2884

B
Hi, all  
Bruce Momjian 已提交
2885
			appendPQExpBuffer(q, ", element = %s, delimiter = '%s'",
2886
							  elemType, tinfo[i].typdelim);
2887 2888
		}
		if (tinfo[i].passedbyvalue)
B
Hi, all  
Bruce Momjian 已提交
2889
			appendPQExpBuffer(q, ",passedbyvalue);\n");
2890
		else
B
Hi, all  
Bruce Momjian 已提交
2891
			appendPQExpBuffer(q, ");\n");
2892

B
Bruce Momjian 已提交
2893
		ArchiveEntry(fout, tinfo[i].oid, fmtId(tinfo[i].typname, force_quotes), "TYPE", NULL,
2894
						q->data, delq->data, "", tinfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
2895 2896 2897 2898

		/*** Dump Type Comments ***/

		resetPQExpBuffer(q);
B
Bruce Momjian 已提交
2899 2900
		resetPQExpBuffer(delq);

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

B
Bruce Momjian 已提交
2904
		resetPQExpBuffer(q);
2905
	}
2906 2907
}

2908 2909
/*
 * dumpProcLangs
B
Bruce Momjian 已提交
2910
 *		  writes out to fout the queries to recreate user-defined procedural languages
2911 2912 2913
 *
 */
void
B
Bruce Momjian 已提交
2914
dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
B
Bruce Momjian 已提交
2915
			  TypeInfo *tinfo, int numTypes)
2916
{
2917 2918
	PGresult   *res;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2919 2920
	PQExpBuffer defqry = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
2921
	int			ntups;
B
Bruce Momjian 已提交
2922
	int			i_oid;
2923 2924 2925 2926
	int			i_lanname;
	int			i_lanpltrusted;
	int			i_lanplcallfoid;
	int			i_lancompiler;
2927
	Oid			lanoid;
2928 2929 2930
	char	   *lanname;
	char	   *lancompiler;
	const char *lanplcallfoid;
2931 2932 2933
	int			i,
				fidx;

B
Bruce Momjian 已提交
2934
	appendPQExpBuffer(query, "SELECT oid, * FROM pg_language "
2935 2936
					  "WHERE lanispl "
					  "ORDER BY oid");
B
Hi, all  
Bruce Momjian 已提交
2937
	res = PQexec(g_conn, query->data);
2938 2939 2940
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2941
		fprintf(stderr, "dumpProcLangs(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2942 2943 2944 2945
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);

B
Bruce Momjian 已提交
2946 2947 2948 2949
	i_lanname = PQfnumber(res, "lanname");
	i_lanpltrusted = PQfnumber(res, "lanpltrusted");
	i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
	i_lancompiler = PQfnumber(res, "lancompiler");
B
Bruce Momjian 已提交
2950
	i_oid = PQfnumber(res, "oid");
2951

B
Bruce Momjian 已提交
2952 2953
	for (i = 0; i < ntups; i++)
	{
2954
		lanoid = atooid(PQgetvalue(res, i, i_oid));
2955 2956 2957
		if (lanoid <= g_last_builtin_oid)
			continue;

2958
		lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
2959 2960


2961 2962 2963 2964 2965 2966 2967
		for (fidx = 0; fidx < numFuncs; fidx++)
		{
			if (!strcmp(finfo[fidx].oid, lanplcallfoid))
				break;
		}
		if (fidx >= numFuncs)
		{
B
Bruce Momjian 已提交
2968 2969
			fprintf(stderr, "dumpProcLangs(): handler procedure for "
						"language %s not found\n", PQgetvalue(res, i, i_lanname));
2970 2971 2972 2973 2974 2975 2976 2977
			exit_nicely(g_conn);
		}

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

		lanname = checkForQuote(PQgetvalue(res, i, i_lanname));
		lancompiler = checkForQuote(PQgetvalue(res, i, i_lancompiler));

B
Bruce Momjian 已提交
2978
		appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE '%s';\n", lanname);
2979

B
Bruce Momjian 已提交
2980
		appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE '%s' "
B
Bruce Momjian 已提交
2981
				"HANDLER %s LANCOMPILER '%s';\n",
B
Bruce Momjian 已提交
2982
				(PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ? "TRUSTED " : "",
B
Bruce Momjian 已提交
2983 2984 2985
				lanname,
				fmtId(finfo[fidx].proname, force_quotes),
				lancompiler);
2986

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

2990 2991
		free(lanname);
		free(lancompiler);
2992 2993 2994

		resetPQExpBuffer(defqry);
		resetPQExpBuffer(delqry);
2995 2996 2997 2998 2999 3000
	}

	PQclear(res);

}

3001 3002
/*
 * dumpFuncs
3003
 *	  writes out to fout the queries to recreate all the user-defined functions
3004 3005 3006
 *
 */
void
B
Bruce Momjian 已提交
3007
dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs,
3008
		  TypeInfo *tinfo, int numTypes)
3009
{
3010
	int			i;
3011 3012 3013

	for (i = 0; i < numFuncs; i++)
		dumpOneFunc(fout, finfo, i, tinfo, numTypes);
3014 3015 3016 3017
}

/*
 * dumpOneFunc:
3018 3019
 *	  dump out only one function,  the index of which is given in the third
 *	argument
3020 3021 3022
 *
 */

3023
static void
B
Bruce Momjian 已提交
3024
dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
3025
			TypeInfo *tinfo, int numTypes)
3026
{
3027
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3028 3029
	PQExpBuffer fn = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
B
Bruce,  
Bruce Momjian 已提交
3030
	PQExpBuffer fnlist = createPQExpBuffer();
B
Bruce Momjian 已提交
3031
	int			j;
3032
	PQExpBuffer asPart = createPQExpBuffer();
3033
	char		func_lang[NAMEDATALEN + 1];
3034 3035 3036 3037
	PGresult   *res;
	int			nlangs;
	int			i_lanname;
	char		query[256];
3038

3039 3040 3041 3042
	char		*listSep;
	char		*listSepComma = ",";
	char		*listSepNone = "";

3043 3044 3045 3046 3047
	if (finfo[i].dumped)
		return;
	else
		finfo[i].dumped = 1;

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

3050 3051 3052 3053 3054
	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 已提交
3055
  	{
3056 3057
		fprintf(stderr, "dumpOneFunc(): SELECT for procedural language failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
		exit_nicely(g_conn);
B
Bruce Momjian 已提交
3058
  	}
3059 3060 3061
	nlangs = PQntuples(res);

	if (nlangs != 1)
B
Bruce Momjian 已提交
3062
  	{
3063 3064
		fprintf(stderr, "dumpOneFunc(): procedural language for function %s not found\n", finfo[i].proname);
		exit_nicely(g_conn);
B
Bruce Momjian 已提交
3065 3066
  	}
  
3067
	i_lanname = PQfnumber(res, "lanname");
3068

3069
	/*
3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085
	 * See backend/commands/define.c for details of how the 'AS' clause
	 * is used.
	 */
	if (strcmp(finfo[i].probin, "-") != 0)
	{
		if (strcmp(finfo[i].prosrc, "-") != 0)
			appendPQExpBuffer(asPart, "AS '%s', '%s'", finfo[i].probin, finfo[i].prosrc);
		else
			appendPQExpBuffer(asPart, "AS '%s'", finfo[i].probin);
	}
	else
	{
		if (strcmp(finfo[i].prosrc, "-") != 0)
			appendPQExpBuffer(asPart, "AS '%s'", finfo[i].prosrc);
	}

3086
	strcpy(func_lang, PQgetvalue(res, 0, i_lanname));
B
Bruce Momjian 已提交
3087
  
3088
	PQclear(res);
B
Bruce Momjian 已提交
3089 3090 3091
 
	resetPQExpBuffer(fn);
	appendPQExpBuffer(fn, "%s (", fmtId(finfo[i].proname, force_quotes));
3092 3093
	for (j = 0; j < finfo[i].nargs; j++)
	{
B
Bruce Momjian 已提交
3094
		char			*typname;
3095

3096 3097 3098 3099
		typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j], zeroAsOpaque);
		appendPQExpBuffer(fn, "%s%s", 
							(j > 0) ? "," : "", 
							typname);
B
Bruce,  
Bruce Momjian 已提交
3100
		appendPQExpBuffer(fnlist, "%s%s",
3101 3102
							(j > 0) ? "," : "", 
							typname );
3103
	}
B
Bruce Momjian 已提交
3104 3105 3106 3107 3108 3109 3110
	appendPQExpBuffer(fn, ")");

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

	resetPQExpBuffer(q);
	appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data );
3111
	appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE '%s'",
3112
					  (finfo[i].retset) ? " SETOF " : "",
3113
					  findTypeByOid(tinfo, numTypes, finfo[i].prorettype, zeroAsOpaque),
3114
					  asPart->data, func_lang);
3115

3116
	if (finfo[i].iscachable || finfo[i].isstrict) /* OR in new attrs here */
3117
	{
3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130
		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, " )");
3131 3132 3133 3134
	}

	appendPQExpBuffer(q, ";\n");

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

B
Bruce,  
Bruce Momjian 已提交
3138 3139 3140 3141 3142 3143 3144 3145
	/*** 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);

3146 3147 3148 3149
}

/*
 * dumpOprs
3150
 *	  writes out to fout the queries to recreate all the user-defined operators
3151 3152
 *
 */
3153
void
B
Bruce Momjian 已提交
3154
dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
3155
		 TypeInfo *tinfo, int numTypes)
3156
{
B
Bruce Momjian 已提交
3157
	int			i;
3158
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3159
	PQExpBuffer delq = createPQExpBuffer();
3160 3161 3162 3163 3164 3165 3166 3167
	PQExpBuffer leftarg = createPQExpBuffer();
	PQExpBuffer rightarg = createPQExpBuffer();
	PQExpBuffer commutator = createPQExpBuffer();
	PQExpBuffer negator = createPQExpBuffer();
	PQExpBuffer restrictor = createPQExpBuffer();
	PQExpBuffer join = createPQExpBuffer();
	PQExpBuffer sort1 = createPQExpBuffer();
	PQExpBuffer sort2 = createPQExpBuffer();
3168 3169 3170 3171

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

B
Hi, all  
Bruce Momjian 已提交
3172 3173 3174 3175 3176 3177 3178 3179 3180
		resetPQExpBuffer(leftarg);
		resetPQExpBuffer(rightarg);
		resetPQExpBuffer(commutator);
		resetPQExpBuffer(negator);
		resetPQExpBuffer(restrictor);
		resetPQExpBuffer(join);
		resetPQExpBuffer(sort1);
		resetPQExpBuffer(sort2);

3181
		/* skip all the builtin oids */
3182
		if (atooid(oprinfo[i].oid) <= g_last_builtin_oid)
3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198
			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 已提交
3199
			appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ",
3200
								findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft, zeroAsOpaque) );
3201 3202 3203 3204
		}
		if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
			strcmp(oprinfo[i].oprkind, "b") == 0)
		{
B
Hi, all  
Bruce Momjian 已提交
3205
			appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ",
3206
							  findTypeByOid(tinfo, numTypes, oprinfo[i].oprright, zeroAsOpaque) );
3207
		}
B
Hi, all  
Bruce Momjian 已提交
3208 3209
		if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
			appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ",
3210 3211
				 findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom));

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

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

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

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

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

B
Bruce Momjian 已提交
3230 3231
		resetPQExpBuffer(delq);
		appendPQExpBuffer(delq, "DROP OPERATOR %s (%s", oprinfo[i].oprname,
3232
				findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft, zeroAsOpaque) );
B
Bruce Momjian 已提交
3233
		appendPQExpBuffer(delq, ", %s);\n",
3234
					findTypeByOid(tinfo, numTypes, oprinfo[i].oprright, zeroAsOpaque) );
3235

B
Hi, all  
Bruce Momjian 已提交
3236 3237
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
3238 3239 3240 3241 3242 3243 3244 3245 3246
						  "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 已提交
3247
						(strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
3248 3249 3250
						  join->data,
						  sort1->data,
						  sort2->data);
3251

B
Bruce Momjian 已提交
3252
		ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
3253
						q->data, delq->data, "", oprinfo[i].usename, NULL, NULL);
3254
	}
3255 3256 3257 3258
}

/*
 * dumpAggs
3259
 *	  writes out to fout the queries to create all the user-defined aggregates
3260 3261 3262
 *
 */
void
B
Bruce Momjian 已提交
3263
dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
3264
		 TypeInfo *tinfo, int numTypes)
3265
{
B
Bruce Momjian 已提交
3266
	int			i;
3267
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3268 3269
	PQExpBuffer delq = createPQExpBuffer();
	PQExpBuffer aggSig = createPQExpBuffer();
3270
	PQExpBuffer details = createPQExpBuffer();
3271 3272 3273

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

3276
		/* skip all the builtin oids */
3277
		if (atooid(agginfo[i].oid) <= g_last_builtin_oid)
3278
			continue;
3279

3280
		appendPQExpBuffer(details,
3281
						  "BASETYPE = %s, ",
3282
						  findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsAny + useBaseTypeName));
3283

3284 3285 3286
		appendPQExpBuffer(details,
						  "SFUNC = %s, STYPE = %s",
						  agginfo[i].aggtransfn,
3287
						  findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype, zeroAsOpaque + useBaseTypeName));
3288

3289 3290 3291
		if (agginfo[i].agginitval)
			appendPQExpBuffer(details, ", INITCOND = '%s'",
							  agginfo[i].agginitval);
3292

B
Hi, all  
Bruce Momjian 已提交
3293
		if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
3294 3295
			appendPQExpBuffer(details, ", FINALFUNC = %s",
							  agginfo[i].aggfinalfn);
3296

B
Bruce Momjian 已提交
3297 3298
		resetPQExpBuffer(aggSig);
		appendPQExpBuffer(aggSig, "%s %s", agginfo[i].aggname,
3299
							findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsOpaque + useBaseTypeName));
3300

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

B
Hi, all  
Bruce Momjian 已提交
3304
		resetPQExpBuffer(q);
3305
		appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
3306
						  agginfo[i].aggname,
3307
						  details->data);
3308

B
Bruce Momjian 已提交
3309
		ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
3310
						q->data, delq->data, "", agginfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
3311 3312 3313 3314

		/*** Dump Aggregate Comments ***/

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

3319
	}
3320 3321
}

3322 3323 3324 3325 3326
/*
 * These are some support functions to fix the acl problem of pg_dump
 *
 * Matthew C. Aycock 12/02/97
 */
3327 3328 3329

/* Append a keyword to a keyword list, inserting comma if needed.
 * Caller must make aclbuf big enough for all possible keywords.
3330
 */
3331
static void
B
Bruce Momjian 已提交
3332
AddAcl(char *aclbuf, const char *keyword)
3333
{
3334 3335 3336
	if (*aclbuf)
		strcat(aclbuf, ",");
	strcat(aclbuf, keyword);
3337
}
3338

3339
/*
3340
 * This will take a string of 'arwR' and return a malloced,
3341 3342
 * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
 */
V
Vadim B. Mikheev 已提交
3343
static char *
3344
GetPrivileges(const char *s)
3345
{
3346
	char		aclbuf[100];
3347

3348
	aclbuf[0] = '\0';
3349

B
Bruce Momjian 已提交
3350
	if (strchr(s, 'a'))
3351
		AddAcl(aclbuf, "INSERT");
3352

B
Bruce Momjian 已提交
3353
	if (strchr(s, 'w'))
3354
		AddAcl(aclbuf, "UPDATE,DELETE");
B
Bruce Momjian 已提交
3355 3356

	if (strchr(s, 'r'))
3357
		AddAcl(aclbuf, "SELECT");
3358

3359
	if (strchr(s, 'R'))
3360
		AddAcl(aclbuf, "RULE");
3361

3362 3363 3364
	/* Special-case when they're all there */
	if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
		return strdup("ALL");
3365

3366
	return strdup(aclbuf);
3367
}
3368

B
Bruce Momjian 已提交
3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384
/*
 * 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 已提交
3385 3386
/*
 * dumpACL:
3387 3388
 *	  Write out grant/revoke information
 *	  Called for sequences and tables
B
Bruce Momjian 已提交
3389 3390
 */

3391
static void
B
Bruce Momjian 已提交
3392
dumpACL(Archive *fout, TableInfo tbinfo)
B
Bruce Momjian 已提交
3393
{
B
Bruce Momjian 已提交
3394 3395
	const char 	*acls = tbinfo.relacl;
	char	   	*aclbuf,
B
Bruce Momjian 已提交
3396 3397 3398
			   *tok,
			   *eqpos,
			   *priv;
B
Bruce Momjian 已提交
3399 3400 3401
	char		*sql;
	char		tmp[1024];
	int		sSize = 4096;
3402 3403 3404 3405

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

B
Bruce Momjian 已提交
3406 3407 3408 3409 3410
	/*
	 * Allocate a larginsh buffer for the output SQL.
	 */
	sql = (char*)malloc(sSize);

B
Bruce Momjian 已提交
3411 3412 3413
	/*
	 * Revoke Default permissions for PUBLIC. Is this actually necessary,
	 * or is it just a waste of time?
3414
	 */
B
Bruce Momjian 已提交
3415
	sprintf(sql,	"REVOKE ALL on %s from PUBLIC;\n",
3416
			fmtId(tbinfo.relname, force_quotes));
3417 3418 3419

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

3421 3422
	/* Scan comma-separated ACL items */
	for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
3423
	{
3424

B
Bruce Momjian 已提交
3425 3426 3427
		/*
		 * Token may start with '{' and/or '"'.  Actually only the start
		 * of the string should have '{', but we don't verify that.
3428 3429 3430 3431 3432 3433 3434 3435
		 */
		if (*tok == '{')
			tok++;
		if (*tok == '"')
			tok++;

		/* User name is string up to = in tok */
		eqpos = strchr(tok, '=');
B
Bruce Momjian 已提交
3436
		if (!eqpos)
B
Bruce Momjian 已提交
3437
		{
3438 3439
			fprintf(stderr, "Could not parse ACL list ('%s') for '%s'...Exiting!\n",
					acls, tbinfo.relname);
B
Bruce Momjian 已提交
3440 3441 3442
			exit_nicely(g_conn);
		}

B
Bruce Momjian 已提交
3443 3444 3445 3446
		/*
		 * Parse the privileges (right-hand side).	Skip if there are
		 * none.
		 */
3447 3448
		priv = GetPrivileges(eqpos + 1);
		if (*priv)
3449
		{
B
Bruce Momjian 已提交
3450
			sprintf(tmp,	"GRANT %s on %s to ",
3451
					priv, fmtId(tbinfo.relname, force_quotes));
B
Bruce Momjian 已提交
3452
			strcatalloc(&sql, &sSize, tmp);
B
Bruce Momjian 已提交
3453 3454 3455

			/*
			 * Note: fmtId() can only be called once per printf, so don't
3456 3457 3458 3459 3460
			 * try to merge printing of username into the above printf.
			 */
			if (eqpos == tok)
			{
				/* Empty left-hand side means "PUBLIC" */
B
Bruce Momjian 已提交
3461
				strcatalloc(&sql, &sSize, "PUBLIC;\n");
3462
			}
3463
			else
3464 3465
			{
				*eqpos = '\0';	/* it's ok to clobber aclbuf */
3466
				if (strncmp(tok, "group ", strlen("group ")) == 0)
B
Bruce Momjian 已提交
3467
					sprintf(tmp, "GROUP %s;\n",
3468 3469
							fmtId(tok + strlen("group "), force_quotes));
				else
B
Bruce Momjian 已提交
3470 3471
					sprintf(tmp, "%s;\n", fmtId(tok, force_quotes));
				strcatalloc(&sql, &sSize, tmp);
3472
			}
3473
		}
3474
		free(priv);
B
Bruce Momjian 已提交
3475
	}
3476 3477

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

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

B
Bruce Momjian 已提交
3481 3482
}

3483

3484 3485
/*
 * dumpTables:
3486
 *	  write out to fout all the user-define tables
3487
 */
3488

3489
void
B
Bruce Momjian 已提交
3490
dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
3491 3492
		   InhInfo *inhinfo, int numInherits,
		   TypeInfo *tinfo, int numTypes, const char *tablename,
B
Bruce Momjian 已提交
3493 3494
		   const bool aclsSkip, const bool oids,
		   const bool schemaOnly, const bool dataOnly)
3495
{
3496 3497
	int			i,
				j,
B
Bruce Momjian 已提交
3498
				k;
3499
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3500
	PQExpBuffer delq = createPQExpBuffer();
3501
	char	   *serialSeq = NULL;		/* implicit sequence name created
B
Bruce Momjian 已提交
3502 3503 3504 3505
										 * by SERIAL datatype */
	const char *serialSeqSuffix = "_id_seq";	/* suffix for implicit
												 * SERIAL sequences */
	char	  **parentRels;		/* list of names of parent relations */
3506
	int			numParents;
B
Bruce Momjian 已提交
3507
	int			actual_atts;	/* number of attrs in this CREATE statment */
3508
	char	   *reltypename;
3509

V
Vadim B. Mikheev 已提交
3510
	/* First - dump SEQUENCEs */
B
Bruce Momjian 已提交
3511
	if (tablename)
B
Bruce Momjian 已提交
3512 3513 3514 3515 3516
	{
		serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
		strcpy(serialSeq, tablename);
		strcat(serialSeq, serialSeqSuffix);
	}
V
Vadim B. Mikheev 已提交
3517 3518 3519 3520
	for (i = 0; i < numTables; i++)
	{
		if (!(tblinfo[i].sequence))
			continue;
B
Bruce Momjian 已提交
3521
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
B
Bruce Momjian 已提交
3522
			|| (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
V
Vadim B. Mikheev 已提交
3523
		{
B
Bruce Momjian 已提交
3524
			/* becomeUser(fout, tblinfo[i].usename); */
V
Vadim B. Mikheev 已提交
3525
			dumpSequence(fout, tblinfo[i]);
3526
			if (!aclsSkip)
B
Bruce Momjian 已提交
3527
				dumpACL(fout, tblinfo[i]);
V
Vadim B. Mikheev 已提交
3528 3529
		}
	}
B
Bruce Momjian 已提交
3530
	if (tablename)
B
Bruce Momjian 已提交
3531
		free(serialSeq);
3532

3533 3534
	for (i = 0; i < numTables; i++)
	{
3535
		if (tblinfo[i].sequence)/* already dumped */
V
Vadim B. Mikheev 已提交
3536
			continue;
3537 3538 3539 3540

		if (!tablename || (!strcmp(tblinfo[i].relname, tablename)))
		{

3541 3542
			resetPQExpBuffer(delq);
			resetPQExpBuffer(q);
3543

3544 3545 3546 3547
			/* Use the view definition if there is one */
			if (tblinfo[i].viewdef != NULL)
			{
				reltypename = "VIEW";
3548

3549 3550
				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);
3551

3552 3553
			}
			else
3554
			{
3555
				reltypename = "TABLE";
3556

3557 3558
				parentRels = tblinfo[i].parentRels;
				numParents = tblinfo[i].numParents;
B
Bruce Momjian 已提交
3559

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

3562 3563 3564 3565 3566 3567
				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)
3568
					{
3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580
						/* 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",
3581
										  tblinfo[i].adef_expr[j]);
3582 3583 3584 3585 3586 3587 3588

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

						actual_atts++;
					}
3589
				}
B
Hi all  
Bruce Momjian 已提交
3590

3591 3592 3593 3594 3595 3596 3597
				/* 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",
3598
								  tblinfo[i].check_expr[k]);
3599
				}
3600

3601 3602 3603 3604 3605
				/* PRIMARY KEY */
				if (tblinfo[i].primary_key)
				{
					if (actual_atts + tblinfo[i].ncheck > 0)
						appendPQExpBuffer(q, ",\n\t");
3606 3607 3608 3609
					appendPQExpBuffer(q,
									  "CONSTRAINT %s PRIMARY KEY (%s)",
									  tblinfo[i].primary_key_name,
									  tblinfo[i].primary_key);
3610
				}
B
Bruce Momjian 已提交
3611

3612
				appendPQExpBuffer(q, "\n)");
3613

3614
				if (numParents > 0)
B
Hi all  
Bruce Momjian 已提交
3615
				{
3616 3617 3618 3619
					appendPQExpBuffer(q, "\ninherits (");
					for (k = 0; k < numParents; k++)
					{
						appendPQExpBuffer(q, "%s%s",
3620 3621
									  (k > 0) ? ", " : "",
									  fmtId(parentRels[k], force_quotes));
3622 3623
					}
					appendPQExpBuffer(q, ")");
B
Hi all  
Bruce Momjian 已提交
3624 3625
				}

3626 3627
				appendPQExpBuffer(q, ";\n");
			}
B
Bruce Momjian 已提交
3628 3629

			if (!dataOnly) {
3630 3631
					ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
								reltypename, NULL, q->data, delq->data, "", tblinfo[i].usename,
B
Bruce Momjian 已提交
3632 3633 3634 3635
								NULL, NULL);
			}

			if (!dataOnly && !aclsSkip)
B
Bruce Momjian 已提交
3636
				dumpACL(fout, tblinfo[i]);
3637

3638
			/* Dump Field Comments */
B
Bruce,  
Bruce Momjian 已提交
3639

3640 3641
			for (j = 0; j < tblinfo[i].numatts; j++)
			{
B
Bruce,  
Bruce Momjian 已提交
3642 3643 3644 3645 3646 3647
				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]);
			}
3648

B
Bruce,  
Bruce Momjian 已提交
3649
			/* Dump Table Comments */
3650

B
Bruce,  
Bruce Momjian 已提交
3651
			resetPQExpBuffer(q);
3652
			appendPQExpBuffer(q, "%s %s", reltypename, fmtId(tblinfo[i].relname, force_quotes));
B
Bruce,  
Bruce Momjian 已提交
3653
			dumpComment(fout, q->data, tblinfo[i].oid);
3654

3655 3656
		}
	}
3657 3658 3659 3660
}

/*
 * dumpIndices:
3661
 *	  write out to fout all the user-define indices
3662
 */
3663
void
B
Bruce Momjian 已提交
3664
dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
3665
			TableInfo *tblinfo, int numTables, const char *tablename)
3666
{
3667 3668 3669
	int			i,
				k;
	int			tableInd;
3670
	PQExpBuffer attlist = createPQExpBuffer();
B
Bruce Momjian 已提交
3671 3672 3673
	char	   *classname[INDEX_MAX_KEYS];
	char	   *funcname;		/* the name of the function to comput the
								 * index key from */
3674 3675 3676
	int			indkey,
				indclass;
	int			nclass;
3677

3678
	PQExpBuffer q = createPQExpBuffer(),
B
Bruce Momjian 已提交
3679
				delq = createPQExpBuffer(),
B
Hi, all  
Bruce Momjian 已提交
3680 3681
				id1 = createPQExpBuffer(),
				id2 = createPQExpBuffer();
3682
	PGresult   *res;
3683 3684 3685 3686

	for (i = 0; i < numIndices; i++)
	{
		tableInd = findTableByName(tblinfo, numTables,
3687 3688 3689 3690 3691
								   indinfo[i].indrelname);
		if (tableInd < 0)
		{
			fprintf(stderr, "failed sanity check, table %s was not found\n",
					indinfo[i].indrelname);
3692
			exit(1);
3693
		}
3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705

		if (strcmp(indinfo[i].indproc, "0") == 0)
			funcname = NULL;
		else
		{

			/*
			 * 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 已提交
3706 3707
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
3708 3709 3710
							  "SELECT proname from pg_proc "
							  "where pg_proc.oid = '%s'::oid",
							  indinfo[i].indproc);
B
Hi, all  
Bruce Momjian 已提交
3711
			res = PQexec(g_conn, q->data);
3712 3713
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
3714 3715
				fprintf(stderr, "dumpIndices(): SELECT (funcname) failed.  "
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3716 3717
				exit_nicely(g_conn);
			}
B
Bruce Momjian 已提交
3718
			funcname = strdup(PQgetvalue(res, 0, PQfnumber(res, "proname")));
3719 3720 3721 3722 3723 3724 3725 3726 3727
			PQclear(res);
		}

		/* convert opclass oid(s) into names */
		for (nclass = 0; nclass < INDEX_MAX_KEYS; nclass++)
		{
			indclass = atoi(indinfo[i].indclass[nclass]);
			if (indclass == 0)
				break;
B
Hi, all  
Bruce Momjian 已提交
3728 3729
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
3730 3731 3732
							  "SELECT opcname from pg_opclass "
							  "where pg_opclass.oid = '%u'::oid",
							  indclass);
B
Hi, all  
Bruce Momjian 已提交
3733
			res = PQexec(g_conn, q->data);
3734 3735
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
3736 3737
				fprintf(stderr, "dumpIndices(): SELECT (classname) failed.  "
									"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3738 3739
				exit_nicely(g_conn);
			}
B
Bruce Momjian 已提交
3740
			classname[nclass] = strdup(PQgetvalue(res, 0, PQfnumber(res, "opcname")));
3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751
			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 已提交
3752 3753
		resetPQExpBuffer(attlist);
		for (k = 0; k < INDEX_MAX_KEYS; k++)
3754
		{
3755
			char	   *attname;
3756 3757

			indkey = atoi(indinfo[i].indkey[k]);
B
Bruce Momjian 已提交
3758
			if (indkey == InvalidAttrNumber)
3759 3760 3761 3762 3763 3764 3765
				break;
			indkey--;
			if (indkey == ObjectIdAttributeNumber - 1)
				attname = "oid";
			else
				attname = tblinfo[tableInd].attnames[indkey];
			if (funcname)
B
Hi, all  
Bruce Momjian 已提交
3766
				appendPQExpBuffer(attlist, "%s%s",
B
Bruce Momjian 已提交
3767
					 (k == 0) ? "" : ", ", fmtId(attname, force_quotes));
3768 3769 3770 3771 3772
			else
			{
				if (k >= nclass)
				{
					fprintf(stderr, "dumpIndices(): OpClass not found for "
3773
							"attribute '%s' of index '%s'\n",
3774 3775 3776
							attname, indinfo[i].indexrelname);
					exit_nicely(g_conn);
				}
B
Hi, all  
Bruce Momjian 已提交
3777 3778 3779 3780 3781
				resetPQExpBuffer(id1);
				resetPQExpBuffer(id2);
				appendPQExpBuffer(id1, fmtId(attname, force_quotes));
				appendPQExpBuffer(id2, fmtId(classname[k], force_quotes));
				appendPQExpBuffer(attlist, "%s%s %s",
3782
							 (k == 0) ? "" : ", ", id1->data, id2->data);
3783 3784 3785 3786 3787 3788
				free(classname[k]);
			}
		}

		if (!tablename || (!strcmp(indinfo[i].indrelname, tablename)))
		{
B
Bruce Momjian 已提交
3789 3790 3791 3792 3793

			/*
			 * 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.
3794
			 */
3795

B
Hi, all  
Bruce Momjian 已提交
3796 3797 3798 3799
			resetPQExpBuffer(id1);
			resetPQExpBuffer(id2);
			appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
			appendPQExpBuffer(id2, fmtId(indinfo[i].indrelname, force_quotes));
3800

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

B
Bruce Momjian 已提交
3804 3805 3806
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "CREATE %s INDEX %s on %s using %s (",
					(strcmp(indinfo[i].indisunique, "t") == 0) ? "UNIQUE" : "",
B
Hi, all  
Bruce Momjian 已提交
3807 3808
					id1->data,
					id2->data,
3809 3810 3811
					indinfo[i].indamname);
			if (funcname)
			{
3812
				/* need 2 printf's here cuz fmtId has static return area */
B
Bruce Momjian 已提交
3813 3814 3815
				appendPQExpBuffer(q, " %s", fmtId(funcname, false));
				appendPQExpBuffer(q, " (%s) %s );\n", attlist->data, 
									fmtId(classname[0], force_quotes));
3816 3817 3818 3819
				free(funcname);
				free(classname[0]);
			}
			else
B
Bruce Momjian 已提交
3820
				appendPQExpBuffer(q, " %s );\n", attlist->data);
B
Bruce,  
Bruce Momjian 已提交
3821 3822 3823

			/* Dump Index Comments */

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

B
Bruce,  
Bruce Momjian 已提交
3827 3828 3829
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "INDEX %s", id1->data);
			dumpComment(fout, q->data, indinfo[i].indoid);
3830

3831 3832
		}
	}
3833 3834

}
3835

3836
/*
B
Bruce Momjian 已提交
3837
 * dumpTuples
3838 3839 3840 3841 3842
 *	  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
3843
 *	  in PostgreSQL.
3844 3845 3846 3847
 *
 * the attrmap passed in tells how to map the attributes copied in to the
 * attributes copied out
 */
3848
#ifdef NOT_USED
3849
void
3850
dumpTuples(PGresult *res, FILE *fout, int *attrmap)
3851
{
3852 3853 3854 3855
	int			j,
				k;
	int			m,
				n;
B
Bruce Momjian 已提交
3856
	char	  **outVals = NULL; /* values to copy out */
3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875

	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++)
			{
3876
				char	   *pval = outVals[k];
3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896

				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);
	}
3897
}
3898

3899
#endif
3900

3901 3902 3903 3904
/*
 * setMaxOid -
 * find the maximum oid and generate a COPY statement to set it
*/
3905

3906
static void
B
Bruce Momjian 已提交
3907
setMaxOid(Archive *fout)
3908
{
B
Bruce Momjian 已提交
3909 3910 3911 3912
	PGresult   	*res;
	Oid		max_oid;
	char		sql[1024];
	int		pos;
3913

3914
	res = PQexec(g_conn, "CREATE TEMPORARY TABLE pgdump_oid (dummy int4)");
3915 3916 3917
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
3918
		fprintf(stderr, "Can not create pgdump_oid table.  "
B
Bruce Momjian 已提交
3919
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3920 3921 3922
		exit_nicely(g_conn);
	}
	PQclear(res);
3923
	res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
3924 3925 3926
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
3927
		fprintf(stderr, "Can not insert into pgdump_oid table.  "
B
Bruce Momjian 已提交
3928
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3929 3930 3931 3932 3933 3934 3935 3936 3937
		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);
3938
	res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
3939 3940 3941
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
3942
		fprintf(stderr, "Can not drop pgdump_oid table.  "
B
Bruce Momjian 已提交
3943
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3944 3945 3946 3947
		exit_nicely(g_conn);
	}
	PQclear(res);
	if (g_verbose)
3948
		fprintf(stderr, "%s maximum system oid is %u %s\n",
3949
				g_comment_start, max_oid, g_comment_end);
3950 3951
	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 已提交
3952 3953
	pos = pos + snprintf(sql+pos, 1024-pos, "%-d\t0\n", max_oid);
	pos = pos + snprintf(sql+pos, 1024-pos, "\\.\n");
3954
	pos = pos + snprintf(sql+pos, 1024-pos, "DROP TABLE pgdump_oid;\n");
B
Bruce Momjian 已提交
3955

3956
	ArchiveEntry(fout, "0", "Max OID", "<Init>", NULL, sql, "", "", "", NULL, NULL);
3957
}
3958 3959 3960

/*
 * findLastBuiltInOid -
3961
 * find the last built in oid
3962 3963
 * we do this by retrieving datlastsysoid from the pg_database entry for this database,
 */
3964

3965
static Oid
3966
findLastBuiltinOid(const char* dbname)
3967
{
B
Bruce Momjian 已提交
3968
	PGresult   *res;
3969
	int			ntups;
3970
	Oid			last_oid;
3971 3972 3973 3974
	PQExpBuffer query = createPQExpBuffer();

	resetPQExpBuffer(query);
	appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = '%s'", dbname);
3975

3976
	res = PQexec(g_conn, query->data);
3977 3978 3979
	if (res == NULL ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
3980
		fprintf(stderr, "pg_dump: error in finding the last system OID");
3981
		fprintf(stderr, "Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3982 3983 3984
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);
3985
	if (ntups < 1)
3986
	{
3987 3988
		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");
3989 3990 3991 3992
		exit_nicely(g_conn);
	}
	if (ntups > 1)
	{
3993 3994
		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");
3995 3996
		exit_nicely(g_conn);
	}
3997
	last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
3998 3999
	PQclear(res);
	return last_oid;
4000 4001 4002 4003 4004
}


/*
 * checkForQuote:
4005
 *	  checks a string for quote characters and quotes them
4006
 */
4007
static char *
4008
checkForQuote(const char *s)
4009
{
B
Bruce Momjian 已提交
4010
	char	   *r;
4011
	char		c;
B
Bruce Momjian 已提交
4012
	char	   *result;
4013

4014
	int			j = 0;
4015

4016
	r = malloc(strlen(s) * 3 + 1);		/* definitely long enough */
4017

4018 4019
	while ((c = *s) != '\0')
	{
4020

4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031
		if (c == '\'')
		{
			r[j++] = '\'';		/* quote the single quotes */
		}
		r[j++] = c;
		s++;
	}
	r[j] = '\0';

	result = strdup(r);
	free(r);
4032

4033
	return result;
4034 4035

}
4036 4037


4038
static void
B
Bruce Momjian 已提交
4039
dumpSequence(Archive *fout, TableInfo tbinfo)
4040
{
4041
	PGresult   *res;
B
Bruce Momjian 已提交
4042
	int4		last,
4043 4044 4045 4046
				incby,
				maxv,
				minv,
				cache;
B
Bruce Momjian 已提交
4047
	char		cycled,
B
Bruce Momjian 已提交
4048
				called;
4049 4050
	const char *t;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
4051
	PQExpBuffer delqry = createPQExpBuffer();
4052

B
Hi, all  
Bruce Momjian 已提交
4053
	appendPQExpBuffer(query,
4054
			"SELECT sequence_name, last_value, increment_by, max_value, "
4055 4056
				  "min_value, cache_value, is_cycled, is_called from %s",
					  fmtId(tbinfo.relname, force_quotes));
4057

B
Hi, all  
Bruce Momjian 已提交
4058
	res = PQexec(g_conn, query->data);
4059 4060
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
4061 4062
		fprintf(stderr, "dumpSequence(%s): SELECT failed.  "
					"Explanation from backend: '%s'.\n", tbinfo.relname, PQerrorMessage(g_conn));
4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093
		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 已提交
4094 4095
	resetPQExpBuffer(delqry);
	appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n", fmtId(tbinfo.relname, force_quotes));
4096

4097 4098 4099 4100 4101 4102
	/*
	 * 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 已提交
4103 4104
	resetPQExpBuffer(query);
	appendPQExpBuffer(query,
4105 4106
				  "CREATE SEQUENCE %s start %d increment %d maxvalue %d "
					  "minvalue %d  cache %d %s;\n",
4107 4108 4109
					fmtId(tbinfo.relname, force_quotes), 
					  (called == 't') ? minv : last,
					  incby, maxv, minv, cache,
4110
					  (cycled == 't') ? "cycle" : "");
4111

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

4115 4116 4117 4118 4119 4120 4121 4122

	resetPQExpBuffer(query);
	appendPQExpBuffer(query, "SELECT setval ('%s', %d, '%c');\n", 
						fmtId(tbinfo.relname, force_quotes), last, called);

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

B
Bruce,  
Bruce Momjian 已提交
4123 4124 4125 4126 4127 4128
	/* Dump Sequence Comments */

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

4129
}
V
Vadim B. Mikheev 已提交
4130 4131


4132
static void
B
Bruce Momjian 已提交
4133
dumpTriggers(Archive *fout, const char *tablename,
4134
			 TableInfo *tblinfo, int numTables)
V
Vadim B. Mikheev 已提交
4135
{
4136 4137 4138
	int			i,
				j;

V
Vadim B. Mikheev 已提交
4139 4140 4141
	if (g_verbose)
		fprintf(stderr, "%s dumping out triggers %s\n",
				g_comment_start, g_comment_end);
4142

V
Vadim B. Mikheev 已提交
4143 4144 4145 4146 4147 4148
	for (i = 0; i < numTables; i++)
	{
		if (tablename && strcmp(tblinfo[i].relname, tablename))
			continue;
		for (j = 0; j < tblinfo[i].ntrig; j++)
		{
B
Bruce Momjian 已提交
4149
			ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
4150
						"TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "", "", 
B
Bruce Momjian 已提交
4151 4152
						tblinfo[i].usename, NULL, NULL);
			dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid);
V
Vadim B. Mikheev 已提交
4153 4154 4155
		}
	}
}
4156 4157


4158
static void
B
Bruce Momjian 已提交
4159
dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
4160
		  TableInfo *tblinfo, int numTables)
4161
{
B
Bruce Momjian 已提交
4162 4163 4164 4165
	PGresult   *res;
	int			nrules;
	int			i,
				t;
4166
	PQExpBuffer query = createPQExpBuffer();
4167

B
Bruce Momjian 已提交
4168
	int			i_definition;
4169
	int			i_oid;
4170
	int			i_owner;
4171
	int			i_rulename;
4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186

	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++)
	{
		if (tablename && strcmp(tblinfo[t].relname, tablename))
			continue;

		/*
		 * Get all rules defined for this table
4187 4188
		 * We include pg_rules in the cross since it filters out
		 * all view rules (pjw 15-Sep-2000).
4189
		 */
B
Hi, all  
Bruce Momjian 已提交
4190
		resetPQExpBuffer(query);
4191
		appendPQExpBuffer(query, "SELECT definition,"
4192
						  "   (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
4193 4194
						  "   pg_rewrite.oid, pg_rewrite.rulename "
						  "FROM pg_rewrite, pg_class, pg_rules "
4195
						  "WHERE pg_class.relname = '%s' "
4196 4197 4198
						  "    AND pg_rewrite.ev_class = pg_class.oid "
						  "    AND pg_rules.tablename = pg_class.relname "
						  "    AND pg_rules.rulename = pg_rewrite.rulename "
4199 4200
						  "ORDER BY pg_rewrite.oid",
						  tblinfo[t].relname);
B
Hi, all  
Bruce Momjian 已提交
4201
		res = PQexec(g_conn, query->data);
4202 4203 4204
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
4205
			fprintf(stderr, "dumpRules(): SELECT failed for rules associated with table \"%s\".\n\tExplanation from backend: '%s'.\n",
B
Bruce Momjian 已提交
4206
					tblinfo[t].relname, PQerrorMessage(g_conn));
4207 4208 4209 4210 4211
			exit_nicely(g_conn);
		}

		nrules = PQntuples(res);
		i_definition = PQfnumber(res, "definition");
4212
		i_owner = PQfnumber(res, "viewowner");
B
Bruce,  
Bruce Momjian 已提交
4213 4214
		i_oid = PQfnumber(res, "oid");
		i_rulename = PQfnumber(res, "rulename");
4215 4216 4217 4218

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

4220 4221
		for (i = 0; i < nrules; i++)
		{
B
Bruce Momjian 已提交
4222 4223
			ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
							"RULE", NULL, PQgetvalue(res, i, i_definition),
4224
							"", "", PQgetvalue(res, i, i_owner), NULL, NULL);
4225

B
Bruce,  
Bruce Momjian 已提交
4226 4227 4228 4229 4230
			/* 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));
4231

B
Bruce,  
Bruce Momjian 已提交
4232 4233
		}

4234 4235 4236 4237
		PQclear(res);
	}
}