pg_dump.c 111.2 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.178 2000/11/13 15:18:13 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

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

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

149
static int dumpBlobs(Archive *AH, char*, void*);
150
static int dumpDatabase(Archive *AH);
151

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

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

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

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

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


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

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

#ifdef HAVE_GETOPT_LONG
192
	puts(
B
Bruce Momjian 已提交
193
		"  -a, --data-only          dump out only the data, not the schema\n"
194
		"  -b, --blobs				dump out blob data\n"
B
Bruce Momjian 已提交
195
	   	"  -c, --clean              clean (drop) schema prior to create\n"
196
		"  -C, --create             output commands to create database\n"
B
Bruce Momjian 已提交
197 198 199 200 201 202
		"  -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"
203
		"  -k, --unixsocket <path>  server Unix-domain socket name\n"
B
Bruce Momjian 已提交
204 205 206
		"  -n, --no-quotes          suppress most quotes around identifiers\n"
		"  -N, --quotes             enable most quotes around identifiers\n"
		"  -o, --oids               dump object ids (oids)\n"
207
		"  -O, --no-owner           don't output \\connect commands in plain text format\n"
B
Bruce Momjian 已提交
208
		"  -p, --port <port>        server port number\n"
209
		"  -R, --no-reconnect       disable ALL reconnections to the database in plain text format\n"
B
Bruce Momjian 已提交
210
		"  -s, --schema-only        dump out only the schema, no data\n"
211
		"  -S, --superuser <name>   specify the superuser username to use in plain text format\n"
B
Bruce Momjian 已提交
212 213 214 215 216
		"  -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"
217
		);
B
Hi,  
Bruce Momjian 已提交
218
#else
219
	puts(
B
Bruce Momjian 已提交
220
		"  -a                       dump out only the data, no schema\n"
221
		"  -b                       dump out blob data\n"
B
Bruce Momjian 已提交
222
		"  -c                       clean (drop) schema prior to create\n"
223
		"  -C                       output commands to create database\n"
B
Bruce Momjian 已提交
224 225 226 227 228 229
		"  -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"
230
		"  -k <path>                server Unix-domain socket name\n"
B
Bruce Momjian 已提交
231 232 233
		"  -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 485
							PQgetvalue(res, tuple, field));
					break;
				default:
486

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

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

/*
 * DumpClasses -
527
 *	  dump the contents of all the classes.
528 529
 */
static void
B
Bruce Momjian 已提交
530
dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
531
			const char *onlytable, const bool oids, const bool force_quotes)
532 533
{

B
Bruce Momjian 已提交
534 535 536 537
	int				i;
	char	   		*all_only;
	DataDumperPtr	dumpFn;
	DumpContext		*dumpCtx;
538 539 540
	char			*oidsPart;
	char			copyBuf[512];
	char			*copyStmt;
541 542 543 544

	if (onlytable == NULL)
		all_only = "all";
	else
545
		all_only = "only";
546

547 548 549 550 551 552
	if (oids == true)
		oidsPart = "WITH OIDS ";
	else
		oidsPart = "";


553
	if (g_verbose)
554
		fprintf(stderr, "%s preparing to dump out the contents of %s %d table%s/sequence%s %s\n",
555 556
				g_comment_start, all_only,
				(onlytable == NULL) ? numTables : 1,
557
		  (onlytable == NULL) ? "s" : "", (onlytable == NULL) ? "s" : "",
558
				g_comment_end);
559

V
Vadim B. Mikheev 已提交
560 561 562 563 564 565 566 567 568 569
	/* 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)
570
					fprintf(stderr, "%s dumping out schema of sequence '%s' %s\n",
571
					 g_comment_start, tblinfo[i].relname, g_comment_end);
B
Bruce Momjian 已提交
572
				/* becomeUser(fout, tblinfo[i].usename); */
V
Vadim B. Mikheev 已提交
573 574 575 576
				dumpSequence(fout, tblinfo[i]);
			}
		}
	}
577 578 579

	for (i = 0; i < numTables; i++)
	{
580
		const char *classname = tblinfo[i].relname;
581 582

		/* Skip VIEW relations */
583
		if (tblinfo[i].viewdef != NULL)
584
			continue;
585 586

		if (tblinfo[i].sequence)/* already dumped */
V
Vadim B. Mikheev 已提交
587
			continue;
588 589 590 591

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

B
Bruce Momjian 已提交
595 596 597 598 599 600
			/* becomeUser(fout, tblinfo[i].usename); */

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

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

			ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
618
							"TABLE DATA", NULL, "", "", copyStmt, tblinfo[i].usename,
B
Bruce Momjian 已提交
619
							dumpFn, dumpCtx);
620
		}
621
	}
622 623
}

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

B
Bruce Momjian 已提交
650
	RestoreOptions	*ropt;
651

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

B
Hi,  
Bruce Momjian 已提交
683 684
#endif

685
	g_verbose = false;
686
	force_quotes = true;
687 688 689 690 691

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

692
	dataOnly = schemaOnly = dumpData = attrNames = false;
693

694 695 696 697
	if (!strrchr(argv[0], SEP_CHAR))
		progname = argv[0];
	else
		progname = strrchr(argv[0], SEP_CHAR) + 1;
698

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

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

712 713 714
	{
		switch (c)
		{
715
			case 'a':			/* Dump data only */
716
				dataOnly = true;
717
				break;
718

719 720 721 722
			case 'b':			/* Dump blobs */
				outputBlobs = true;
				break;

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

				outputCreate = 1;
				break;

733
			case 'd':			/* dump data as proper insert strings */
734
				dumpData = true;
735
				break;
736

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

743
			case 'f':
744 745
				filename = optarg;
				break;
746

B
Bruce Momjian 已提交
747 748 749
			case 'F':
				format = optarg;
				break;
750

B
Bruce Momjian 已提交
751
			case 'h':			/* server host */
752 753
				pghost = optarg;
				break;
754

755 756 757
			case 'i':			/* ignore database version mismatch */
				ignore_version = true;
				break;
758

759 760 761 762
			case 'k':			/* server Unix-domain socket */
				pgunixsocket = optarg;
				break;

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

				/*
				 * 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);
				}
861
				break;
862 863 864
#ifndef HAVE_GETOPT_LONG
			case '-':
				fprintf(stderr, "%s was compiled without support for long options.\n"
865
				   "Use -? for help on invocation options.\n", progname);
866 867 868
				exit(1);
				break;
#endif
869
			default:
870 871
				fprintf(stderr, "%s: unknown option -%c\nTry -? for help.\n", progname, c);
				exit(1);
872 873 874
		}
	}

P
Philip Warner 已提交
875 876 877 878 879 880 881 882
	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 已提交
883 884 885 886 887 888 889 890
	if (dataOnly && schemaOnly)
	{
		fprintf(stderr,
				"%s: 'Schema Only' and 'Data Only' are incompatible options.\n",
				progname);
		exit(1);
	}

891 892 893 894 895 896 897 898
	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);
	}

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

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

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

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

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

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

956
	dbname = argv[optind];
957

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

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

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

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

979 980 981
		PQclear(res);
	}

982
	g_last_builtin_oid = findLastBuiltinOid(dbname);
983

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

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

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

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

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

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

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

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

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

		RestoreArchive(g_fout, ropt);
	}

	CloseArchive(g_fout);
1047

1048 1049 1050
	clearTableInfo(tblinfo, numTables);
	PQfinish(g_conn);
	exit(0);
1051 1052
}

1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
/*
 * 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 */
1072
	appendPQExpBuffer(dbQry, "select (select usename from pg_user where datdba = usesysid) as dba from pg_database"
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 1105 1106
							" 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;
}


1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
/*
 * 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 */
1132
    appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject");
1133 1134 1135 1136

	res = PQexec(g_conn, oidQry->data);
	if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
	{
1137 1138
		fprintf(stderr, "dumpBlobs(): Declare Cursor failed.  Explanation from backend: '%s'.\n", 
										PQerrorMessage(g_conn));
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 1192 1193
		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;
}

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

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

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

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

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

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

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

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

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

	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;
1351 1352 1353 1354 1355 1356

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

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

B
Hi, all  
Bruce Momjian 已提交
1363
	res = PQexec(g_conn, query->data);
1364 1365 1366
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1367
		fprintf(stderr, "getOperators(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
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 1405 1406
		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));
1407 1408 1409 1410 1411

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

1412 1413 1414 1415 1416
	}

	PQclear(res);

	return oprinfo;
1417 1418
}

1419
void
1420
clearTypeInfo(TypeInfo *tp, int numTypes)
1421
{
1422
	int			i;
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 1454 1455

	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);
1456 1457 1458
}

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

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

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

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

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

1535 1536
		if (tblinfo[i].atttypmod)
			free((int *) tblinfo[i].atttypmod);
1537 1538 1539 1540
		if (tblinfo[i].inhAttrs)
			free((int *) tblinfo[i].inhAttrs);
		if (tblinfo[i].attnames)
			free(tblinfo[i].attnames);
1541 1542
		if (tblinfo[i].atttypedefns)
			free(tblinfo[i].atttypedefns);
1543 1544 1545 1546
		if (tblinfo[i].typnames)
			free(tblinfo[i].typnames);
		if (tblinfo[i].notnull)
			free(tblinfo[i].notnull);
1547 1548
		if (tblinfo[i].primary_key)
			free(tblinfo[i].primary_key);
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

V
Vadim B. Mikheev 已提交
2149 2150 2151 2152
		/* Get Triggers */
		if (tblinfo[i].ntrig > 0)
		{
			PGresult   *res2;
B
Bruce,  
Bruce Momjian 已提交
2153
			int			i_tgoid,
2154
						i_tgname,
2155 2156 2157
						i_tgfoid,
						i_tgtype,
						i_tgnargs,
2158 2159 2160 2161 2162
						i_tgargs,
						i_tgisconstraint,
						i_tgconstrname,
						i_tgdeferrable,
						i_tginitdeferred;
V
Vadim B. Mikheev 已提交
2163 2164
			int			ntups2;
			int			i2;
2165

V
Vadim B. Mikheev 已提交
2166
			if (g_verbose)
2167
				fprintf(stderr, "%s finding Triggers for relation: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2168 2169 2170
						g_comment_start,
						tblinfo[i].relname,
						g_comment_end);
2171

B
Hi, all  
Bruce Momjian 已提交
2172
			resetPQExpBuffer(query);
2173
			appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, tgisconstraint, tgconstrname, tgdeferrable, tginitdeferred, oid "
2174 2175 2176
							  "from pg_trigger "
							  "where tgrelid = '%s'::oid ",
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2177
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2178
			if (!res2 ||
2179
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2180
			{
B
Bruce Momjian 已提交
2181 2182
				fprintf(stderr, "getTables(): SELECT (for TRIGGER) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2183 2184 2185 2186 2187
				exit_nicely(g_conn);
			}
			ntups2 = PQntuples(res2);
			if (ntups2 != tblinfo[i].ntrig)
			{
2188
				fprintf(stderr, "getTables(): relation '%s': %d Triggers were expected, but got %d\n",
2189
						tblinfo[i].relname, tblinfo[i].ntrig, ntups2);
V
Vadim B. Mikheev 已提交
2190 2191 2192 2193 2194 2195 2196
				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 已提交
2197
			i_tgoid = PQfnumber(res2, "oid");
2198 2199 2200 2201 2202
			i_tgisconstraint = PQfnumber(res2, "tgisconstraint");
			i_tgconstrname = PQfnumber(res2, "tgconstrname");
			i_tgdeferrable = PQfnumber(res2, "tgdeferrable");
			i_tginitdeferred = PQfnumber(res2, "tginitdeferred");

B
Bruce Momjian 已提交
2203
			tblinfo[i].triggers = (TrigInfo*) malloc(ntups2 * sizeof(TrigInfo));
B
Hi, all  
Bruce Momjian 已提交
2204 2205
			resetPQExpBuffer(query);
			for (i2 = 0; i2 < ntups2; i2++)
V
Vadim B. Mikheev 已提交
2206
			{
2207
				const char *tgfuncoid = PQgetvalue(res2, i2, i_tgfoid);
2208
				char	   *tgfunc = NULL;
2209 2210
				int2		tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
				int			tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
B
Bruce Momjian 已提交
2211
				const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
2212 2213 2214
				int			tgisconstraint;
				int			tgdeferrable;
				int			tginitdeferred;
B
Bruce Momjian 已提交
2215
				const char *p;
2216 2217
				int			findx;

2218
				if (strcmp(PQgetvalue(res2, i2, i_tgisconstraint), "f") == 0)
2219
					tgisconstraint = 0;
2220
				else
2221
					tgisconstraint = 1;
2222 2223

				if (strcmp(PQgetvalue(res2, i2, i_tgdeferrable), "f") == 0)
2224
					tgdeferrable = 0;
2225
				else
2226
					tgdeferrable = 1;
2227 2228

				if (strcmp(PQgetvalue(res2, i2, i_tginitdeferred), "f") == 0)
2229
					tginitdeferred = 0;
2230
				else
2231
					tginitdeferred = 1;
2232

V
Vadim B. Mikheev 已提交
2233 2234
				for (findx = 0; findx < numFuncs; findx++)
				{
2235
					if (strcmp(finfo[findx].oid, tgfuncoid) == 0 &&
2236
						finfo[findx].nargs == 0 &&
V
Vadim B. Mikheev 已提交
2237 2238 2239
						strcmp(finfo[findx].prorettype, "0") == 0)
						break;
				}
2240

V
Vadim B. Mikheev 已提交
2241 2242
				if (findx == numFuncs)
				{
2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263
					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);
					}
2264
					tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
2265
					PQclear(r);
2266
				}
2267
				else
2268
					tgfunc = strdup(finfo[findx].proname);
B
Bruce Momjian 已提交
2269 2270

				appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
2271
									fmtId(PQgetvalue(res2, i2, i_tgname),
B
Bruce Momjian 已提交
2272 2273 2274
									force_quotes));
				appendPQExpBuffer(delqry, "ON %s;\n",
									fmtId(tblinfo[i].relname, force_quotes));
2275

B
Hi, all  
Bruce Momjian 已提交
2276
				resetPQExpBuffer(query);
2277 2278 2279 2280 2281
				if (tgisconstraint)
				{
					appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgconstrname), force_quotes));
				}
2282 2283
				else
				{
2284 2285 2286
					appendPQExpBuffer(query, "CREATE TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
				}
B
Bruce Momjian 已提交
2287
				appendPQExpBufferChar(query, ' ');
V
Vadim B. Mikheev 已提交
2288 2289 2290
				/* Trigger type */
				findx = 0;
				if (TRIGGER_FOR_BEFORE(tgtype))
B
Hi, all  
Bruce Momjian 已提交
2291
					appendPQExpBuffer(query, "BEFORE");
V
Vadim B. Mikheev 已提交
2292
				else
B
Hi, all  
Bruce Momjian 已提交
2293
					appendPQExpBuffer(query, "AFTER");
V
Vadim B. Mikheev 已提交
2294 2295
				if (TRIGGER_FOR_INSERT(tgtype))
				{
B
Hi, all  
Bruce Momjian 已提交
2296
					appendPQExpBuffer(query, " INSERT");
V
Vadim B. Mikheev 已提交
2297 2298 2299 2300 2301
					findx++;
				}
				if (TRIGGER_FOR_DELETE(tgtype))
				{
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2302
						appendPQExpBuffer(query, " OR DELETE");
V
Vadim B. Mikheev 已提交
2303
					else
B
Hi, all  
Bruce Momjian 已提交
2304
						appendPQExpBuffer(query, " DELETE");
V
Vadim B. Mikheev 已提交
2305 2306 2307
					findx++;
				}
				if (TRIGGER_FOR_UPDATE(tgtype))
2308
				{
V
Vadim B. Mikheev 已提交
2309
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2310
						appendPQExpBuffer(query, " OR UPDATE");
V
Vadim B. Mikheev 已提交
2311
					else
B
Hi, all  
Bruce Momjian 已提交
2312
						appendPQExpBuffer(query, " UPDATE");
2313
				}
2314 2315
				appendPQExpBuffer(query, " ON %s ", fmtId(tblinfo[i].relname, force_quotes));

2316
				if (tgisconstraint)
2317
				{
2318
					if (!tgdeferrable)
2319 2320 2321 2322
						appendPQExpBuffer(query, " NOT");
					appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
					if (tginitdeferred)
						appendPQExpBuffer(query, "DEFERRED");
2323
					else
2324
						appendPQExpBuffer(query, "IMMEDIATE");
2325

2326 2327 2328
				}

				appendPQExpBuffer(query, " FOR EACH ROW");
2329 2330
				appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
								  fmtId(tgfunc, force_quotes));
V
Vadim B. Mikheev 已提交
2331 2332
				for (findx = 0; findx < tgnargs; findx++)
				{
2333
					const char *s;
2334 2335

					for (p = tgargs;;)
V
Vadim B. Mikheev 已提交
2336
					{
2337
						p = strchr(p, '\\');
V
Vadim B. Mikheev 已提交
2338 2339
						if (p == NULL)
						{
B
Bruce Momjian 已提交
2340 2341
							fprintf(stderr, "getTables(): relation '%s': bad argument "
									"string (%s) for trigger '%s'\n",
2342 2343 2344
									tblinfo[i].relname,
									PQgetvalue(res2, i2, i_tgargs),
									PQgetvalue(res2, i2, i_tgname));
V
Vadim B. Mikheev 已提交
2345 2346 2347 2348 2349 2350 2351 2352
							exit_nicely(g_conn);
						}
						p++;
						if (*p == '\\')
						{
							p++;
							continue;
						}
2353
						if (p[0] == '0' && p[1] == '0' && p[2] == '0')
V
Vadim B. Mikheev 已提交
2354 2355 2356
							break;
					}
					p--;
2357
					appendPQExpBufferChar(query, '\'');
B
Bruce Momjian 已提交
2358
					for (s = tgargs; s < p;)
V
Vadim B. Mikheev 已提交
2359 2360
					{
						if (*s == '\'')
2361 2362
							appendPQExpBufferChar(query, '\\');
						appendPQExpBufferChar(query, *s++);
V
Vadim B. Mikheev 已提交
2363
					}
B
Bruce Momjian 已提交
2364 2365
					appendPQExpBufferChar(query, '\'');
					appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
V
Vadim B. Mikheev 已提交
2366 2367
					tgargs = p + 4;
				}
B
Hi, all  
Bruce Momjian 已提交
2368
				appendPQExpBuffer(query, ");\n");
2369

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

				/*** Initialize trcomments and troids ***/
2373

B
Bruce,  
Bruce Momjian 已提交
2374
				resetPQExpBuffer(query);
2375 2376
				appendPQExpBuffer(query, "TRIGGER %s ",
					fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
B
Bruce,  
Bruce Momjian 已提交
2377
				appendPQExpBuffer(query, "ON %s",
2378
								fmtId(tblinfo[i].relname, force_quotes));
B
Bruce Momjian 已提交
2379 2380 2381 2382
				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 已提交
2383

2384 2385
				if (tgfunc)
					free(tgfunc);
V
Vadim B. Mikheev 已提交
2386 2387 2388 2389
			}
			PQclear(res2);
		}
		else
B
Bruce,  
Bruce Momjian 已提交
2390
		{
V
Vadim B. Mikheev 已提交
2391
			tblinfo[i].triggers = NULL;
B
Bruce,  
Bruce Momjian 已提交
2392
		}
2393

2394 2395 2396 2397 2398
	}

	PQclear(res);

	return tblinfo;
2399 2400 2401 2402 2403

}

/*
 * getInherits
2404
 *	  read all the inheritance information
2405 2406
 * from the system catalogs return them in the InhInfo* structure
 *
2407 2408
 * numInherits is set to the number of tables read in
 *
2409 2410
 *
 */
2411
InhInfo    *
2412 2413
getInherits(int *numInherits)
{
2414
	PGresult   *res;
2415 2416
	int			ntups;
	int			i;
2417 2418
	PQExpBuffer query = createPQExpBuffer();
	InhInfo    *inhinfo;
2419

2420
	int			i_inhrelid;
2421
	int			i_inhparent;
2422 2423 2424

	/* find all the inheritance information */

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

B
Hi, all  
Bruce Momjian 已提交
2427
	res = PQexec(g_conn, query->data);
2428 2429 2430
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2431 2432
		fprintf(stderr, "getInherits(): SELECT failed.  Explanation from backend: '%s'.\n", 
				PQerrorMessage(g_conn));
2433 2434 2435 2436 2437 2438 2439 2440 2441
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numInherits = ntups;

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

2442
	i_inhrelid = PQfnumber(res, "inhrelid");
2443 2444 2445 2446
	i_inhparent = PQfnumber(res, "inhparent");

	for (i = 0; i < ntups; i++)
	{
2447
		inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
2448 2449 2450 2451 2452
		inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
	}

	PQclear(res);
	return inhinfo;
2453 2454 2455 2456
}

/*
 * getTableAttrs -
2457 2458
 *	  for each table in tblinfo, read its attributes types and names
 *
2459
 * this is implemented in a very inefficient way right now, looping
2460
 * through the tblinfo and doing a join per table to find the attrs and their
2461 2462
 * types
 *
2463
 *	modifies tblinfo
2464 2465
 */
void
2466
getTableAttrs(TableInfo *tblinfo, int numTables)
2467
{
2468 2469
	int			i,
				j;
2470
	PQExpBuffer q = createPQExpBuffer();
2471 2472
	int			i_attname;
	int			i_typname;
2473
	int			i_atttypmod;
2474
	int			i_attnotnull;
V
Vadim B. Mikheev 已提交
2475
	int			i_atthasdef;
2476
	int			i_attoid;
2477
	int			i_atttypedefn;
2478
	PGresult   *res;
2479
	int			ntups;
2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494

	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)
2495
			fprintf(stderr, "%s finding the attrs and types for table: '%s' %s\n",
2496 2497 2498 2499
					g_comment_start,
					tblinfo[i].relname,
					g_comment_end);

B
Hi, all  
Bruce Momjian 已提交
2500
		resetPQExpBuffer(q);
B
Bruce,  
Bruce Momjian 已提交
2501
		appendPQExpBuffer(q, "SELECT a.oid as attoid, a.attnum, a.attname, t.typname, a.atttypmod, "
2502
						  "a.attnotnull, a.atthasdef, format_type(a.atttypid, a.atttypmod) as atttypedefn "
2503 2504 2505 2506
						  "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 已提交
2507
		res = PQexec(g_conn, q->data);
2508 2509 2510
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
B
Bruce Momjian 已提交
2511 2512
			fprintf(stderr, "getTableAttrs(): SELECT failed.  "
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2513 2514 2515 2516 2517
			exit_nicely(g_conn);
		}

		ntups = PQntuples(res);

B
Bruce,  
Bruce Momjian 已提交
2518
		i_attoid = PQfnumber(res, "attoid");
2519 2520
		i_attname = PQfnumber(res, "attname");
		i_typname = PQfnumber(res, "typname");
2521
		i_atttypmod = PQfnumber(res, "atttypmod");
2522
		i_attnotnull = PQfnumber(res, "attnotnull");
V
Vadim B. Mikheev 已提交
2523
		i_atthasdef = PQfnumber(res, "atthasdef");
2524
		i_atttypedefn = PQfnumber(res, "atttypedefn");
2525 2526

		tblinfo[i].numatts = ntups;
B
Bruce,  
Bruce Momjian 已提交
2527
		tblinfo[i].attoids = (char **) malloc(ntups * sizeof(char *));
2528
		tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
2529
		tblinfo[i].atttypedefns = (char **) malloc(ntups * sizeof(char *));
2530
		tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
2531
		tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
2532 2533
		tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
		tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
V
Vadim B. Mikheev 已提交
2534
		tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
2535 2536 2537 2538
		tblinfo[i].parentRels = NULL;
		tblinfo[i].numParents = 0;
		for (j = 0; j < ntups; j++)
		{
B
Bruce,  
Bruce Momjian 已提交
2539
			tblinfo[i].attoids[j] = strdup(PQgetvalue(res, j, i_attoid));
2540
			tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
2541
			tblinfo[i].atttypedefns[j] = strdup(PQgetvalue(res, j, i_atttypedefn));
2542
			tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
2543
			tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
2544 2545 2546
			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 已提交
2547 2548 2549
			if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
			{
				PGresult   *res2;
2550

V
Vadim B. Mikheev 已提交
2551
				if (g_verbose)
2552
					fprintf(stderr, "%s finding DEFAULT expression for attr: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2553 2554 2555
							g_comment_start,
							tblinfo[i].attnames[j],
							g_comment_end);
2556

B
Hi, all  
Bruce Momjian 已提交
2557 2558
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
2559 2560
							 "where adrelid = '%s'::oid and adnum = %d ",
								  tblinfo[i].oid, j + 1);
B
Hi, all  
Bruce Momjian 已提交
2561
				res2 = PQexec(g_conn, q->data);
V
Vadim B. Mikheev 已提交
2562
				if (!res2 ||
2563
					PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2564
				{
B
Bruce Momjian 已提交
2565 2566
					fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2567 2568 2569 2570 2571 2572 2573
					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;
2574 2575 2576
		}
		PQclear(res);
	}
2577 2578 2579 2580 2581
}


/*
 * getIndices
2582
 *	  read all the user-defined indices information
2583 2584
 * from the system catalogs return them in the InhInfo* structure
 *
2585 2586
 * numIndices is set to the number of indices read in
 *
2587 2588
 *
 */
2589
IndInfo    *
2590 2591
getIndices(int *numIndices)
{
2592
	int			i;
2593
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2594
	PGresult   *res;
2595
	int			ntups;
B
Bruce Momjian 已提交
2596
	IndInfo    *indinfo;
2597 2598 2599 2600 2601 2602 2603 2604

	int			i_indexrelname;
	int			i_indrelname;
	int			i_indamname;
	int			i_indproc;
	int			i_indkey;
	int			i_indclass;
	int			i_indisunique;
2605
	int			i_indoid;
2606 2607 2608 2609 2610

	/*
	 * find all the user-defined indices. We do not handle partial
	 * indices.
	 *
2611
	 * Notice we skip indices on system classes
2612 2613 2614 2615
	 *
	 * this is a 4-way join !!
	 */

B
Hi, all  
Bruce Momjian 已提交
2616
	appendPQExpBuffer(query,
2617 2618 2619 2620 2621 2622
					  "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 "
2623 2624
					  "and t2.relname !~ '^pg_' and not i.indisprimary",
					  g_last_builtin_oid);
2625

B
Hi, all  
Bruce Momjian 已提交
2626
	res = PQexec(g_conn, query->data);
2627 2628 2629
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2630 2631
		fprintf(stderr, "getIndices(): SELECT failed.  "
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2632 2633 2634 2635 2636 2637 2638 2639 2640
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numIndices = ntups;

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

2641 2642
	memset((char *) indinfo, 0, ntups * sizeof(IndInfo));

B
Bruce,  
Bruce Momjian 已提交
2643
	i_indoid = PQfnumber(res, "indoid");
2644 2645 2646 2647 2648 2649 2650 2651 2652 2653
	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 已提交
2654
		indinfo[i].indoid = strdup(PQgetvalue(res, i, i_indoid));
2655 2656 2657 2658
		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));
2659 2660 2661 2662 2663 2664
		parseNumericArray(PQgetvalue(res, i, i_indkey),
						  indinfo[i].indkey,
						  INDEX_MAX_KEYS);
		parseNumericArray(PQgetvalue(res, i, i_indclass),
						  indinfo[i].indclass,
						  INDEX_MAX_KEYS);
2665 2666 2667 2668
		indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
	}
	PQclear(res);
	return indinfo;
2669 2670
}

B
Bruce,  
Bruce Momjian 已提交
2671
/*------------------------------------------------------------------
2672
 * dumpComments --
B
Bruce,  
Bruce Momjian 已提交
2673
 *
2674
 * This routine is used to dump any comments associated with the
B
Bruce,  
Bruce Momjian 已提交
2675 2676 2677 2678
 * 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
2679
 * addition, the routine takes the stdio FILE handle to which the
B
Bruce,  
Bruce Momjian 已提交
2680 2681 2682 2683
 * output should be written.
 *------------------------------------------------------------------
*/

T
Tom Lane 已提交
2684
static void
B
Bruce Momjian 已提交
2685
dumpComment(Archive *fout, const char *target, const char *oid)
2686
{
B
Bruce,  
Bruce Momjian 已提交
2687

2688
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
2689
	PQExpBuffer query;
2690
	int			i_description;
B
Bruce,  
Bruce Momjian 已提交
2691 2692 2693 2694 2695 2696 2697 2698 2699 2700

	/*** 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);
2701 2702
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce,  
Bruce Momjian 已提交
2703 2704 2705 2706 2707 2708 2709
		fprintf(stderr, "DumpComment: SELECT failed: '%s'.\n",
				PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

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

2710 2711
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2712
		i_description = PQfnumber(res, "description");
B
Bruce Momjian 已提交
2713 2714 2715 2716 2717
		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*/,
2718
					   "" /* Copy */, "" /*Owner*/, NULL, NULL);	
B
Bruce Momjian 已提交
2719

B
Bruce,  
Bruce Momjian 已提交
2720 2721 2722 2723 2724
	}

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

	PQclear(res);
2725

B
Bruce,  
Bruce Momjian 已提交
2726 2727 2728
}

/*------------------------------------------------------------------
2729
 * dumpDBComment --
B
Bruce,  
Bruce Momjian 已提交
2730
 *
2731 2732
 * 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 已提交
2733 2734 2735 2736 2737
 * to dump the schema of the database, then this is the first
 * statement issued.
 *------------------------------------------------------------------
*/

2738
void
B
Bruce Momjian 已提交
2739
dumpDBComment(Archive *fout)
2740
{
B
Bruce,  
Bruce Momjian 已提交
2741

2742
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
2743
	PQExpBuffer query;
2744
	int			i_oid;
B
Bruce,  
Bruce Momjian 已提交
2745 2746 2747 2748 2749 2750 2751 2752 2753 2754

	/*** 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);
2755 2756
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce,  
Bruce Momjian 已提交
2757 2758 2759 2760 2761 2762 2763
		fprintf(stderr, "dumpDBComment: SELECT failed: '%s'.\n",
				PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

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

2764 2765
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2766 2767 2768 2769 2770 2771 2772 2773 2774
		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);
2775

B
Bruce,  
Bruce Momjian 已提交
2776 2777
}

2778 2779
/*
 * dumpTypes
2780
 *	  writes out to fout the queries to recreate all the user-defined types
2781 2782 2783
 *
 */
void
B
Bruce Momjian 已提交
2784
dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
2785
		  TypeInfo *tinfo, int numTypes)
2786
{
2787
	int			i;
2788
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
2789
	PQExpBuffer	delq = createPQExpBuffer();
2790
	int			funcInd;
2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819

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

		/* skip all the builtin types */
		if (atoi(tinfo[i].oid) < g_last_builtin_oid)
			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 已提交
2820
		appendPQExpBuffer(delq, "DROP TYPE %s;\n", fmtId(tinfo[i].typname, force_quotes));
2821

B
Hi, all  
Bruce Momjian 已提交
2822 2823
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834
						  "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);
2835 2836 2837

		if (tinfo[i].isArray)
		{
2838
			char	   *elemType;
2839

2840
			elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
2841

B
Hi, all  
Bruce Momjian 已提交
2842
			appendPQExpBuffer(q, ", element = %s, delimiter = '%s'",
2843
							  elemType, tinfo[i].typdelim);
2844 2845
		}
		if (tinfo[i].passedbyvalue)
B
Hi, all  
Bruce Momjian 已提交
2846
			appendPQExpBuffer(q, ",passedbyvalue);\n");
2847
		else
B
Hi, all  
Bruce Momjian 已提交
2848
			appendPQExpBuffer(q, ");\n");
2849

B
Bruce Momjian 已提交
2850
		ArchiveEntry(fout, tinfo[i].oid, fmtId(tinfo[i].typname, force_quotes), "TYPE", NULL,
2851
						q->data, delq->data, "", tinfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
2852 2853 2854 2855

		/*** Dump Type Comments ***/

		resetPQExpBuffer(q);
B
Bruce Momjian 已提交
2856 2857
		resetPQExpBuffer(delq);

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

B
Bruce Momjian 已提交
2861
		resetPQExpBuffer(q);
2862
	}
2863 2864
}

2865 2866
/*
 * dumpProcLangs
B
Bruce Momjian 已提交
2867
 *		  writes out to fout the queries to recreate user-defined procedural languages
2868 2869 2870
 *
 */
void
B
Bruce Momjian 已提交
2871
dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
B
Bruce Momjian 已提交
2872
			  TypeInfo *tinfo, int numTypes)
2873
{
2874 2875
	PGresult   *res;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2876 2877
	PQExpBuffer defqry = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
2878
	int			ntups;
B
Bruce Momjian 已提交
2879
	int			i_oid;
2880 2881 2882 2883
	int			i_lanname;
	int			i_lanpltrusted;
	int			i_lanplcallfoid;
	int			i_lancompiler;
2884
	Oid			lanoid;
2885 2886 2887
	char	   *lanname;
	char	   *lancompiler;
	const char *lanplcallfoid;
2888 2889 2890
	int			i,
				fidx;

B
Bruce Momjian 已提交
2891
	appendPQExpBuffer(query, "SELECT oid, * FROM pg_language "
2892 2893
					  "WHERE lanispl "
					  "ORDER BY oid");
B
Hi, all  
Bruce Momjian 已提交
2894
	res = PQexec(g_conn, query->data);
2895 2896 2897
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2898
		fprintf(stderr, "dumpProcLangs(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2899 2900 2901 2902
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);

B
Bruce Momjian 已提交
2903 2904 2905 2906
	i_lanname = PQfnumber(res, "lanname");
	i_lanpltrusted = PQfnumber(res, "lanpltrusted");
	i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
	i_lancompiler = PQfnumber(res, "lancompiler");
B
Bruce Momjian 已提交
2907
	i_oid = PQfnumber(res, "oid");
2908

B
Bruce Momjian 已提交
2909 2910
	for (i = 0; i < ntups; i++)
	{
2911 2912 2913 2914
		lanoid = atoi(PQgetvalue(res, i, i_oid));
		if (lanoid <= g_last_builtin_oid)
			continue;

2915
		lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
2916 2917


2918 2919 2920 2921 2922 2923 2924
		for (fidx = 0; fidx < numFuncs; fidx++)
		{
			if (!strcmp(finfo[fidx].oid, lanplcallfoid))
				break;
		}
		if (fidx >= numFuncs)
		{
B
Bruce Momjian 已提交
2925 2926
			fprintf(stderr, "dumpProcLangs(): handler procedure for "
						"language %s not found\n", PQgetvalue(res, i, i_lanname));
2927 2928 2929 2930 2931 2932 2933 2934
			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 已提交
2935
		appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE '%s';\n", lanname);
2936

B
Bruce Momjian 已提交
2937
		appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE '%s' "
B
Bruce Momjian 已提交
2938
				"HANDLER %s LANCOMPILER '%s';\n",
B
Bruce Momjian 已提交
2939
				(PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ? "TRUSTED " : "",
B
Bruce Momjian 已提交
2940 2941 2942
				lanname,
				fmtId(finfo[fidx].proname, force_quotes),
				lancompiler);
2943

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

2947 2948
		free(lanname);
		free(lancompiler);
2949 2950 2951

		resetPQExpBuffer(defqry);
		resetPQExpBuffer(delqry);
2952 2953 2954 2955 2956 2957
	}

	PQclear(res);

}

2958 2959
/*
 * dumpFuncs
2960
 *	  writes out to fout the queries to recreate all the user-defined functions
2961 2962 2963
 *
 */
void
B
Bruce Momjian 已提交
2964
dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs,
2965
		  TypeInfo *tinfo, int numTypes)
2966
{
2967
	int			i;
2968 2969 2970

	for (i = 0; i < numFuncs; i++)
		dumpOneFunc(fout, finfo, i, tinfo, numTypes);
2971 2972 2973 2974
}

/*
 * dumpOneFunc:
2975 2976
 *	  dump out only one function,  the index of which is given in the third
 *	argument
2977 2978 2979
 *
 */

2980
static void
B
Bruce Momjian 已提交
2981
dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
2982
			TypeInfo *tinfo, int numTypes)
2983
{
2984
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
2985 2986
	PQExpBuffer fn = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
B
Bruce,  
Bruce Momjian 已提交
2987
	PQExpBuffer fnlist = createPQExpBuffer();
B
Bruce Momjian 已提交
2988
	int			j;
2989
	PQExpBuffer asPart = createPQExpBuffer();
2990
	char		func_lang[NAMEDATALEN + 1];
2991 2992 2993 2994
	PGresult   *res;
	int			nlangs;
	int			i_lanname;
	char		query[256];
2995

2996 2997 2998 2999
	char		*listSep;
	char		*listSepComma = ",";
	char		*listSepNone = "";

3000 3001 3002 3003 3004
	if (finfo[i].dumped)
		return;
	else
		finfo[i].dumped = 1;

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

3007 3008 3009 3010 3011
	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 已提交
3012
  	{
3013 3014
		fprintf(stderr, "dumpOneFunc(): SELECT for procedural language failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
		exit_nicely(g_conn);
B
Bruce Momjian 已提交
3015
  	}
3016 3017 3018
	nlangs = PQntuples(res);

	if (nlangs != 1)
B
Bruce Momjian 已提交
3019
  	{
3020 3021
		fprintf(stderr, "dumpOneFunc(): procedural language for function %s not found\n", finfo[i].proname);
		exit_nicely(g_conn);
B
Bruce Momjian 已提交
3022 3023
  	}
  
3024
	i_lanname = PQfnumber(res, "lanname");
3025

3026
	/*
3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042
	 * 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);
	}

3043
	strcpy(func_lang, PQgetvalue(res, 0, i_lanname));
B
Bruce Momjian 已提交
3044
  
3045
	PQclear(res);
B
Bruce Momjian 已提交
3046 3047 3048
 
	resetPQExpBuffer(fn);
	appendPQExpBuffer(fn, "%s (", fmtId(finfo[i].proname, force_quotes));
3049 3050
	for (j = 0; j < finfo[i].nargs; j++)
	{
B
Bruce Momjian 已提交
3051
		char			*typname;
3052

3053 3054 3055 3056
		typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j], zeroAsOpaque);
		appendPQExpBuffer(fn, "%s%s", 
							(j > 0) ? "," : "", 
							typname);
B
Bruce,  
Bruce Momjian 已提交
3057
		appendPQExpBuffer(fnlist, "%s%s",
3058 3059
							(j > 0) ? "," : "", 
							typname );
3060
	}
B
Bruce Momjian 已提交
3061 3062 3063 3064 3065 3066 3067
	appendPQExpBuffer(fn, ")");

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

	resetPQExpBuffer(q);
	appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data );
3068
	appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE '%s'",
3069
					  (finfo[i].retset) ? " SETOF " : "",
3070
					  findTypeByOid(tinfo, numTypes, finfo[i].prorettype, zeroAsOpaque),
3071
					  asPart->data, func_lang);
3072

3073
	if (finfo[i].iscachable || finfo[i].isstrict) /* OR in new attrs here */
3074
	{
3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087
		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, " )");
3088 3089 3090 3091
	}

	appendPQExpBuffer(q, ";\n");

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

B
Bruce,  
Bruce Momjian 已提交
3095 3096 3097 3098 3099 3100 3101 3102
	/*** 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);

3103 3104 3105 3106
}

/*
 * dumpOprs
3107
 *	  writes out to fout the queries to recreate all the user-defined operators
3108 3109
 *
 */
3110
void
B
Bruce Momjian 已提交
3111
dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
3112
		 TypeInfo *tinfo, int numTypes)
3113
{
B
Bruce Momjian 已提交
3114
	int			i;
3115
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3116
	PQExpBuffer delq = createPQExpBuffer();
3117 3118 3119 3120 3121 3122 3123 3124
	PQExpBuffer leftarg = createPQExpBuffer();
	PQExpBuffer rightarg = createPQExpBuffer();
	PQExpBuffer commutator = createPQExpBuffer();
	PQExpBuffer negator = createPQExpBuffer();
	PQExpBuffer restrictor = createPQExpBuffer();
	PQExpBuffer join = createPQExpBuffer();
	PQExpBuffer sort1 = createPQExpBuffer();
	PQExpBuffer sort2 = createPQExpBuffer();
3125 3126 3127 3128

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

B
Hi, all  
Bruce Momjian 已提交
3129 3130 3131 3132 3133 3134 3135 3136 3137
		resetPQExpBuffer(leftarg);
		resetPQExpBuffer(rightarg);
		resetPQExpBuffer(commutator);
		resetPQExpBuffer(negator);
		resetPQExpBuffer(restrictor);
		resetPQExpBuffer(join);
		resetPQExpBuffer(sort1);
		resetPQExpBuffer(sort2);

3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155
		/* skip all the builtin oids */
		if (atoi(oprinfo[i].oid) < g_last_builtin_oid)
			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 已提交
3156
			appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ",
3157
								findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft, zeroAsOpaque) );
3158 3159 3160 3161
		}
		if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
			strcmp(oprinfo[i].oprkind, "b") == 0)
		{
B
Hi, all  
Bruce Momjian 已提交
3162
			appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ",
3163
							  findTypeByOid(tinfo, numTypes, oprinfo[i].oprright, zeroAsOpaque) );
3164
		}
B
Hi, all  
Bruce Momjian 已提交
3165 3166
		if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
			appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ",
3167 3168
				 findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom));

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

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

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

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

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

B
Bruce Momjian 已提交
3187 3188
		resetPQExpBuffer(delq);
		appendPQExpBuffer(delq, "DROP OPERATOR %s (%s", oprinfo[i].oprname,
3189
				findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft, zeroAsOpaque) );
B
Bruce Momjian 已提交
3190
		appendPQExpBuffer(delq, ", %s);\n",
3191
					findTypeByOid(tinfo, numTypes, oprinfo[i].oprright, zeroAsOpaque) );
3192

B
Hi, all  
Bruce Momjian 已提交
3193 3194
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
3195 3196 3197 3198 3199 3200 3201 3202 3203
						  "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 已提交
3204
						(strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
3205 3206 3207
						  join->data,
						  sort1->data,
						  sort2->data);
3208

B
Bruce Momjian 已提交
3209
		ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
3210
						q->data, delq->data, "", oprinfo[i].usename, NULL, NULL);
3211
	}
3212 3213 3214 3215
}

/*
 * dumpAggs
3216
 *	  writes out to fout the queries to create all the user-defined aggregates
3217 3218 3219
 *
 */
void
B
Bruce Momjian 已提交
3220
dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
3221
		 TypeInfo *tinfo, int numTypes)
3222
{
B
Bruce Momjian 已提交
3223
	int			i;
3224
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3225 3226
	PQExpBuffer delq = createPQExpBuffer();
	PQExpBuffer aggSig = createPQExpBuffer();
3227
	PQExpBuffer details = createPQExpBuffer();
3228 3229 3230

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

3233 3234 3235
		/* skip all the builtin oids */
		if (atoi(agginfo[i].oid) < g_last_builtin_oid)
			continue;
3236

3237
		appendPQExpBuffer(details,
3238
						  "BASETYPE = %s, ",
3239
						  findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsAny + useBaseTypeName));
3240

3241 3242 3243
		appendPQExpBuffer(details,
						  "SFUNC = %s, STYPE = %s",
						  agginfo[i].aggtransfn,
3244
						  findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype, zeroAsOpaque + useBaseTypeName));
3245

3246 3247 3248
		if (agginfo[i].agginitval)
			appendPQExpBuffer(details, ", INITCOND = '%s'",
							  agginfo[i].agginitval);
3249

B
Hi, all  
Bruce Momjian 已提交
3250
		if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
3251 3252
			appendPQExpBuffer(details, ", FINALFUNC = %s",
							  agginfo[i].aggfinalfn);
3253

B
Bruce Momjian 已提交
3254 3255
		resetPQExpBuffer(aggSig);
		appendPQExpBuffer(aggSig, "%s %s", agginfo[i].aggname,
3256
							findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsOpaque + useBaseTypeName));
3257

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

B
Hi, all  
Bruce Momjian 已提交
3261
		resetPQExpBuffer(q);
3262
		appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
3263
						  agginfo[i].aggname,
3264
						  details->data);
3265

B
Bruce Momjian 已提交
3266
		ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
3267
						q->data, delq->data, "", agginfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
3268 3269 3270 3271

		/*** Dump Aggregate Comments ***/

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

3276
	}
3277 3278
}

3279 3280 3281 3282 3283
/*
 * These are some support functions to fix the acl problem of pg_dump
 *
 * Matthew C. Aycock 12/02/97
 */
3284 3285 3286

/* Append a keyword to a keyword list, inserting comma if needed.
 * Caller must make aclbuf big enough for all possible keywords.
3287
 */
3288
static void
B
Bruce Momjian 已提交
3289
AddAcl(char *aclbuf, const char *keyword)
3290
{
3291 3292 3293
	if (*aclbuf)
		strcat(aclbuf, ",");
	strcat(aclbuf, keyword);
3294
}
3295

3296
/*
3297
 * This will take a string of 'arwR' and return a malloced,
3298 3299
 * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
 */
V
Vadim B. Mikheev 已提交
3300
static char *
3301
GetPrivileges(const char *s)
3302
{
3303
	char		aclbuf[100];
3304

3305
	aclbuf[0] = '\0';
3306

B
Bruce Momjian 已提交
3307
	if (strchr(s, 'a'))
3308
		AddAcl(aclbuf, "INSERT");
3309

B
Bruce Momjian 已提交
3310
	if (strchr(s, 'w'))
3311
		AddAcl(aclbuf, "UPDATE,DELETE");
B
Bruce Momjian 已提交
3312 3313

	if (strchr(s, 'r'))
3314
		AddAcl(aclbuf, "SELECT");
3315

3316
	if (strchr(s, 'R'))
3317
		AddAcl(aclbuf, "RULE");
3318

3319 3320 3321
	/* Special-case when they're all there */
	if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
		return strdup("ALL");
3322

3323
	return strdup(aclbuf);
3324
}
3325

B
Bruce Momjian 已提交
3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341
/*
 * 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 已提交
3342 3343
/*
 * dumpACL:
3344 3345
 *	  Write out grant/revoke information
 *	  Called for sequences and tables
B
Bruce Momjian 已提交
3346 3347
 */

3348
static void
B
Bruce Momjian 已提交
3349
dumpACL(Archive *fout, TableInfo tbinfo)
B
Bruce Momjian 已提交
3350
{
B
Bruce Momjian 已提交
3351 3352
	const char 	*acls = tbinfo.relacl;
	char	   	*aclbuf,
B
Bruce Momjian 已提交
3353 3354 3355
			   *tok,
			   *eqpos,
			   *priv;
B
Bruce Momjian 已提交
3356 3357 3358
	char		*sql;
	char		tmp[1024];
	int		sSize = 4096;
3359 3360 3361 3362

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

B
Bruce Momjian 已提交
3363 3364 3365 3366 3367
	/*
	 * Allocate a larginsh buffer for the output SQL.
	 */
	sql = (char*)malloc(sSize);

B
Bruce Momjian 已提交
3368 3369 3370
	/*
	 * Revoke Default permissions for PUBLIC. Is this actually necessary,
	 * or is it just a waste of time?
3371
	 */
B
Bruce Momjian 已提交
3372
	sprintf(sql,	"REVOKE ALL on %s from PUBLIC;\n",
3373
			fmtId(tbinfo.relname, force_quotes));
3374 3375 3376

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

3378 3379
	/* Scan comma-separated ACL items */
	for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
3380
	{
3381

B
Bruce Momjian 已提交
3382 3383 3384
		/*
		 * Token may start with '{' and/or '"'.  Actually only the start
		 * of the string should have '{', but we don't verify that.
3385 3386 3387 3388 3389 3390 3391 3392
		 */
		if (*tok == '{')
			tok++;
		if (*tok == '"')
			tok++;

		/* User name is string up to = in tok */
		eqpos = strchr(tok, '=');
B
Bruce Momjian 已提交
3393
		if (!eqpos)
B
Bruce Momjian 已提交
3394
		{
3395 3396
			fprintf(stderr, "Could not parse ACL list ('%s') for '%s'...Exiting!\n",
					acls, tbinfo.relname);
B
Bruce Momjian 已提交
3397 3398 3399
			exit_nicely(g_conn);
		}

B
Bruce Momjian 已提交
3400 3401 3402 3403
		/*
		 * Parse the privileges (right-hand side).	Skip if there are
		 * none.
		 */
3404 3405
		priv = GetPrivileges(eqpos + 1);
		if (*priv)
3406
		{
B
Bruce Momjian 已提交
3407
			sprintf(tmp,	"GRANT %s on %s to ",
3408
					priv, fmtId(tbinfo.relname, force_quotes));
B
Bruce Momjian 已提交
3409
			strcatalloc(&sql, &sSize, tmp);
B
Bruce Momjian 已提交
3410 3411 3412

			/*
			 * Note: fmtId() can only be called once per printf, so don't
3413 3414 3415 3416 3417
			 * try to merge printing of username into the above printf.
			 */
			if (eqpos == tok)
			{
				/* Empty left-hand side means "PUBLIC" */
B
Bruce Momjian 已提交
3418
				strcatalloc(&sql, &sSize, "PUBLIC;\n");
3419
			}
3420
			else
3421 3422
			{
				*eqpos = '\0';	/* it's ok to clobber aclbuf */
3423
				if (strncmp(tok, "group ", strlen("group ")) == 0)
B
Bruce Momjian 已提交
3424
					sprintf(tmp, "GROUP %s;\n",
3425 3426
							fmtId(tok + strlen("group "), force_quotes));
				else
B
Bruce Momjian 已提交
3427 3428
					sprintf(tmp, "%s;\n", fmtId(tok, force_quotes));
				strcatalloc(&sql, &sSize, tmp);
3429
			}
3430
		}
3431
		free(priv);
B
Bruce Momjian 已提交
3432
	}
3433 3434

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

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

B
Bruce Momjian 已提交
3438 3439
}

3440

3441 3442
/*
 * dumpTables:
3443
 *	  write out to fout all the user-define tables
3444
 */
3445

3446
void
B
Bruce Momjian 已提交
3447
dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
3448 3449
		   InhInfo *inhinfo, int numInherits,
		   TypeInfo *tinfo, int numTypes, const char *tablename,
B
Bruce Momjian 已提交
3450 3451
		   const bool aclsSkip, const bool oids,
		   const bool schemaOnly, const bool dataOnly)
3452
{
3453 3454
	int			i,
				j,
B
Bruce Momjian 已提交
3455
				k;
3456
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3457
	PQExpBuffer delq = createPQExpBuffer();
3458
	char	   *serialSeq = NULL;		/* implicit sequence name created
B
Bruce Momjian 已提交
3459 3460 3461 3462
										 * by SERIAL datatype */
	const char *serialSeqSuffix = "_id_seq";	/* suffix for implicit
												 * SERIAL sequences */
	char	  **parentRels;		/* list of names of parent relations */
3463
	int			numParents;
B
Bruce Momjian 已提交
3464
	int			actual_atts;	/* number of attrs in this CREATE statment */
3465
	char	   *reltypename;
3466

V
Vadim B. Mikheev 已提交
3467
	/* First - dump SEQUENCEs */
B
Bruce Momjian 已提交
3468
	if (tablename)
B
Bruce Momjian 已提交
3469 3470 3471 3472 3473
	{
		serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
		strcpy(serialSeq, tablename);
		strcat(serialSeq, serialSeqSuffix);
	}
V
Vadim B. Mikheev 已提交
3474 3475 3476 3477
	for (i = 0; i < numTables; i++)
	{
		if (!(tblinfo[i].sequence))
			continue;
B
Bruce Momjian 已提交
3478
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
B
Bruce Momjian 已提交
3479
			|| (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
V
Vadim B. Mikheev 已提交
3480
		{
B
Bruce Momjian 已提交
3481
			/* becomeUser(fout, tblinfo[i].usename); */
V
Vadim B. Mikheev 已提交
3482
			dumpSequence(fout, tblinfo[i]);
3483
			if (!aclsSkip)
B
Bruce Momjian 已提交
3484
				dumpACL(fout, tblinfo[i]);
V
Vadim B. Mikheev 已提交
3485 3486
		}
	}
B
Bruce Momjian 已提交
3487
	if (tablename)
B
Bruce Momjian 已提交
3488
		free(serialSeq);
3489

3490 3491
	for (i = 0; i < numTables; i++)
	{
3492
		if (tblinfo[i].sequence)/* already dumped */
V
Vadim B. Mikheev 已提交
3493
			continue;
3494 3495 3496 3497

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

3498 3499
			resetPQExpBuffer(delq);
			resetPQExpBuffer(q);
3500

3501 3502 3503 3504
			/* Use the view definition if there is one */
			if (tblinfo[i].viewdef != NULL)
			{
				reltypename = "VIEW";
3505

3506 3507
				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);
3508

3509 3510
			}
			else
3511
			{
3512
				reltypename = "TABLE";
3513

3514 3515
				parentRels = tblinfo[i].parentRels;
				numParents = tblinfo[i].numParents;
B
Bruce Momjian 已提交
3516

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

3519 3520 3521 3522 3523 3524
				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)
3525
					{
3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537
						/* 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",
3538
										  tblinfo[i].adef_expr[j]);
3539 3540 3541 3542 3543 3544 3545

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

						actual_atts++;
					}
3546
				}
B
Hi all  
Bruce Momjian 已提交
3547

3548 3549 3550 3551 3552 3553 3554
				/* 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",
3555
								  tblinfo[i].check_expr[k]);
3556
				}
3557

3558 3559 3560 3561 3562 3563 3564
				/* PRIMARY KEY */
				if (tblinfo[i].primary_key)
				{
					if (actual_atts + tblinfo[i].ncheck > 0)
						appendPQExpBuffer(q, ",\n\t");
					appendPQExpBuffer(q, "PRIMARY KEY (%s)", tblinfo[i].primary_key);
				}
B
Bruce Momjian 已提交
3565

3566
				appendPQExpBuffer(q, "\n)");
3567

3568
				if (numParents > 0)
B
Hi all  
Bruce Momjian 已提交
3569
				{
3570 3571 3572 3573
					appendPQExpBuffer(q, "\ninherits (");
					for (k = 0; k < numParents; k++)
					{
						appendPQExpBuffer(q, "%s%s",
3574 3575
									  (k > 0) ? ", " : "",
									  fmtId(parentRels[k], force_quotes));
3576 3577
					}
					appendPQExpBuffer(q, ")");
B
Hi all  
Bruce Momjian 已提交
3578 3579
				}

3580 3581
				appendPQExpBuffer(q, ";\n");
			}
B
Bruce Momjian 已提交
3582 3583

			if (!dataOnly) {
3584 3585
					ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
								reltypename, NULL, q->data, delq->data, "", tblinfo[i].usename,
B
Bruce Momjian 已提交
3586 3587 3588 3589
								NULL, NULL);
			}

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

3592
			/* Dump Field Comments */
B
Bruce,  
Bruce Momjian 已提交
3593

3594 3595
			for (j = 0; j < tblinfo[i].numatts; j++)
			{
B
Bruce,  
Bruce Momjian 已提交
3596 3597 3598 3599 3600 3601
				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]);
			}
3602

B
Bruce,  
Bruce Momjian 已提交
3603
			/* Dump Table Comments */
3604

B
Bruce,  
Bruce Momjian 已提交
3605
			resetPQExpBuffer(q);
3606
			appendPQExpBuffer(q, "%s %s", reltypename, fmtId(tblinfo[i].relname, force_quotes));
B
Bruce,  
Bruce Momjian 已提交
3607
			dumpComment(fout, q->data, tblinfo[i].oid);
3608

3609 3610
		}
	}
3611 3612 3613 3614
}

/*
 * dumpIndices:
3615
 *	  write out to fout all the user-define indices
3616
 */
3617
void
B
Bruce Momjian 已提交
3618
dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
3619
			TableInfo *tblinfo, int numTables, const char *tablename)
3620
{
3621 3622 3623
	int			i,
				k;
	int			tableInd;
3624
	PQExpBuffer attlist = createPQExpBuffer();
B
Bruce Momjian 已提交
3625 3626 3627
	char	   *classname[INDEX_MAX_KEYS];
	char	   *funcname;		/* the name of the function to comput the
								 * index key from */
3628 3629 3630
	int			indkey,
				indclass;
	int			nclass;
3631

3632
	PQExpBuffer q = createPQExpBuffer(),
B
Bruce Momjian 已提交
3633
				delq = createPQExpBuffer(),
B
Hi, all  
Bruce Momjian 已提交
3634 3635
				id1 = createPQExpBuffer(),
				id2 = createPQExpBuffer();
3636
	PGresult   *res;
3637 3638 3639 3640

	for (i = 0; i < numIndices; i++)
	{
		tableInd = findTableByName(tblinfo, numTables,
3641 3642 3643 3644 3645
								   indinfo[i].indrelname);
		if (tableInd < 0)
		{
			fprintf(stderr, "failed sanity check, table %s was not found\n",
					indinfo[i].indrelname);
3646
			exit(1);
3647
		}
3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659

		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 已提交
3660 3661
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
3662 3663 3664
							  "SELECT proname from pg_proc "
							  "where pg_proc.oid = '%s'::oid",
							  indinfo[i].indproc);
B
Hi, all  
Bruce Momjian 已提交
3665
			res = PQexec(g_conn, q->data);
3666 3667
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
3668 3669
				fprintf(stderr, "dumpIndices(): SELECT (funcname) failed.  "
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3670 3671
				exit_nicely(g_conn);
			}
B
Bruce Momjian 已提交
3672
			funcname = strdup(PQgetvalue(res, 0, PQfnumber(res, "proname")));
3673 3674 3675 3676 3677 3678 3679 3680 3681
			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 已提交
3682 3683
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
3684 3685 3686
							  "SELECT opcname from pg_opclass "
							  "where pg_opclass.oid = '%u'::oid",
							  indclass);
B
Hi, all  
Bruce Momjian 已提交
3687
			res = PQexec(g_conn, q->data);
3688 3689
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
3690 3691
				fprintf(stderr, "dumpIndices(): SELECT (classname) failed.  "
									"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3692 3693
				exit_nicely(g_conn);
			}
B
Bruce Momjian 已提交
3694
			classname[nclass] = strdup(PQgetvalue(res, 0, PQfnumber(res, "opcname")));
3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705
			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 已提交
3706 3707
		resetPQExpBuffer(attlist);
		for (k = 0; k < INDEX_MAX_KEYS; k++)
3708
		{
3709
			char	   *attname;
3710 3711

			indkey = atoi(indinfo[i].indkey[k]);
B
Bruce Momjian 已提交
3712
			if (indkey == InvalidAttrNumber)
3713 3714 3715 3716 3717 3718 3719
				break;
			indkey--;
			if (indkey == ObjectIdAttributeNumber - 1)
				attname = "oid";
			else
				attname = tblinfo[tableInd].attnames[indkey];
			if (funcname)
B
Hi, all  
Bruce Momjian 已提交
3720
				appendPQExpBuffer(attlist, "%s%s",
B
Bruce Momjian 已提交
3721
					 (k == 0) ? "" : ", ", fmtId(attname, force_quotes));
3722 3723 3724 3725 3726
			else
			{
				if (k >= nclass)
				{
					fprintf(stderr, "dumpIndices(): OpClass not found for "
3727
							"attribute '%s' of index '%s'\n",
3728 3729 3730
							attname, indinfo[i].indexrelname);
					exit_nicely(g_conn);
				}
B
Hi, all  
Bruce Momjian 已提交
3731 3732 3733 3734 3735
				resetPQExpBuffer(id1);
				resetPQExpBuffer(id2);
				appendPQExpBuffer(id1, fmtId(attname, force_quotes));
				appendPQExpBuffer(id2, fmtId(classname[k], force_quotes));
				appendPQExpBuffer(attlist, "%s%s %s",
3736
							 (k == 0) ? "" : ", ", id1->data, id2->data);
3737 3738 3739 3740 3741 3742
				free(classname[k]);
			}
		}

		if (!tablename || (!strcmp(indinfo[i].indrelname, tablename)))
		{
B
Bruce Momjian 已提交
3743 3744 3745 3746 3747

			/*
			 * 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.
3748
			 */
3749

B
Hi, all  
Bruce Momjian 已提交
3750 3751 3752 3753
			resetPQExpBuffer(id1);
			resetPQExpBuffer(id2);
			appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
			appendPQExpBuffer(id2, fmtId(indinfo[i].indrelname, force_quotes));
3754

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

B
Bruce Momjian 已提交
3758 3759 3760
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "CREATE %s INDEX %s on %s using %s (",
					(strcmp(indinfo[i].indisunique, "t") == 0) ? "UNIQUE" : "",
B
Hi, all  
Bruce Momjian 已提交
3761 3762
					id1->data,
					id2->data,
3763 3764 3765
					indinfo[i].indamname);
			if (funcname)
			{
3766
				/* need 2 printf's here cuz fmtId has static return area */
B
Bruce Momjian 已提交
3767 3768 3769
				appendPQExpBuffer(q, " %s", fmtId(funcname, false));
				appendPQExpBuffer(q, " (%s) %s );\n", attlist->data, 
									fmtId(classname[0], force_quotes));
3770 3771 3772 3773
				free(funcname);
				free(classname[0]);
			}
			else
B
Bruce Momjian 已提交
3774
				appendPQExpBuffer(q, " %s );\n", attlist->data);
B
Bruce,  
Bruce Momjian 已提交
3775 3776 3777

			/* Dump Index Comments */

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

B
Bruce,  
Bruce Momjian 已提交
3781 3782 3783
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "INDEX %s", id1->data);
			dumpComment(fout, q->data, indinfo[i].indoid);
3784

3785 3786
		}
	}
3787 3788

}
3789

3790
/*
B
Bruce Momjian 已提交
3791
 * dumpTuples
3792 3793 3794 3795 3796
 *	  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
3797
 *	  in PostgreSQL.
3798 3799 3800 3801
 *
 * the attrmap passed in tells how to map the attributes copied in to the
 * attributes copied out
 */
3802
#ifdef NOT_USED
3803
void
3804
dumpTuples(PGresult *res, FILE *fout, int *attrmap)
3805
{
3806 3807 3808 3809
	int			j,
				k;
	int			m,
				n;
B
Bruce Momjian 已提交
3810
	char	  **outVals = NULL; /* values to copy out */
3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829

	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++)
			{
3830
				char	   *pval = outVals[k];
3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850

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

3853
#endif
3854

3855 3856 3857 3858
/*
 * setMaxOid -
 * find the maximum oid and generate a COPY statement to set it
*/
3859

3860
static void
B
Bruce Momjian 已提交
3861
setMaxOid(Archive *fout)
3862
{
B
Bruce Momjian 已提交
3863 3864 3865 3866
	PGresult   	*res;
	Oid		max_oid;
	char		sql[1024];
	int		pos;
3867

3868
	res = PQexec(g_conn, "CREATE TEMPORARY TABLE pgdump_oid (dummy int4)");
3869 3870 3871
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
3872
		fprintf(stderr, "Can not create pgdump_oid table.  "
B
Bruce Momjian 已提交
3873
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3874 3875 3876
		exit_nicely(g_conn);
	}
	PQclear(res);
3877
	res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
3878 3879 3880
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
3881
		fprintf(stderr, "Can not insert into pgdump_oid table.  "
B
Bruce Momjian 已提交
3882
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3883 3884 3885 3886 3887 3888 3889 3890 3891
		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);
3892
	res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
3893 3894 3895
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
3896
		fprintf(stderr, "Can not drop pgdump_oid table.  "
B
Bruce Momjian 已提交
3897
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3898 3899 3900 3901
		exit_nicely(g_conn);
	}
	PQclear(res);
	if (g_verbose)
3902
		fprintf(stderr, "%s maximum system oid is %u %s\n",
3903
				g_comment_start, max_oid, g_comment_end);
3904 3905
	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 已提交
3906 3907
	pos = pos + snprintf(sql+pos, 1024-pos, "%-d\t0\n", max_oid);
	pos = pos + snprintf(sql+pos, 1024-pos, "\\.\n");
3908
	pos = pos + snprintf(sql+pos, 1024-pos, "DROP TABLE pgdump_oid;\n");
B
Bruce Momjian 已提交
3909

3910
	ArchiveEntry(fout, "0", "Max OID", "<Init>", NULL, sql, "", "", "", NULL, NULL);
3911
}
3912 3913 3914

/*
 * findLastBuiltInOid -
3915
 * find the last built in oid
3916 3917
 * we do this by retrieving datlastsysoid from the pg_database entry for this database,
 */
3918

3919
static int
3920
findLastBuiltinOid(const char* dbname)
3921
{
B
Bruce Momjian 已提交
3922
	PGresult   *res;
3923 3924
	int			ntups;
	int			last_oid;
3925 3926 3927 3928
	PQExpBuffer query = createPQExpBuffer();

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

3930
	res = PQexec(g_conn, query->data);
3931 3932 3933
	if (res == NULL ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
3934
		fprintf(stderr, "pg_dump: error in finding the last system OID");
3935
		fprintf(stderr, "Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3936 3937 3938
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);
3939
	if (ntups < 1)
3940
	{
3941 3942
		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");
3943 3944 3945 3946
		exit_nicely(g_conn);
	}
	if (ntups > 1)
	{
3947 3948
		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");
3949 3950
		exit_nicely(g_conn);
	}
3951
	last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
3952 3953
	PQclear(res);
	return last_oid;
3954 3955 3956 3957 3958
}


/*
 * checkForQuote:
3959
 *	  checks a string for quote characters and quotes them
3960
 */
3961
static char *
3962
checkForQuote(const char *s)
3963
{
B
Bruce Momjian 已提交
3964
	char	   *r;
3965
	char		c;
B
Bruce Momjian 已提交
3966
	char	   *result;
3967

3968
	int			j = 0;
3969

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

3972 3973
	while ((c = *s) != '\0')
	{
3974

3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985
		if (c == '\'')
		{
			r[j++] = '\'';		/* quote the single quotes */
		}
		r[j++] = c;
		s++;
	}
	r[j] = '\0';

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

3987
	return result;
3988 3989

}
3990 3991


3992
static void
B
Bruce Momjian 已提交
3993
dumpSequence(Archive *fout, TableInfo tbinfo)
3994
{
3995
	PGresult   *res;
B
Bruce Momjian 已提交
3996
	int4		last,
3997 3998 3999 4000
				incby,
				maxv,
				minv,
				cache;
B
Bruce Momjian 已提交
4001
	char		cycled,
B
Bruce Momjian 已提交
4002
				called;
4003 4004
	const char *t;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
4005
	PQExpBuffer delqry = createPQExpBuffer();
4006

B
Hi, all  
Bruce Momjian 已提交
4007
	appendPQExpBuffer(query,
4008
			"SELECT sequence_name, last_value, increment_by, max_value, "
4009 4010
				  "min_value, cache_value, is_cycled, is_called from %s",
					  fmtId(tbinfo.relname, force_quotes));
4011

B
Hi, all  
Bruce Momjian 已提交
4012
	res = PQexec(g_conn, query->data);
4013 4014
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
4015 4016
		fprintf(stderr, "dumpSequence(%s): SELECT failed.  "
					"Explanation from backend: '%s'.\n", tbinfo.relname, PQerrorMessage(g_conn));
4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047
		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 已提交
4048 4049
	resetPQExpBuffer(delqry);
	appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n", fmtId(tbinfo.relname, force_quotes));
4050

4051 4052 4053 4054 4055 4056
	/*
	 * 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 已提交
4057 4058
	resetPQExpBuffer(query);
	appendPQExpBuffer(query,
4059 4060
				  "CREATE SEQUENCE %s start %d increment %d maxvalue %d "
					  "minvalue %d  cache %d %s;\n",
4061 4062 4063
					fmtId(tbinfo.relname, force_quotes), 
					  (called == 't') ? minv : last,
					  incby, maxv, minv, cache,
4064
					  (cycled == 't') ? "cycle" : "");
4065

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

4069 4070 4071 4072 4073 4074 4075 4076

	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 已提交
4077 4078 4079 4080 4081 4082
	/* Dump Sequence Comments */

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

4083
}
V
Vadim B. Mikheev 已提交
4084 4085


4086
static void
B
Bruce Momjian 已提交
4087
dumpTriggers(Archive *fout, const char *tablename,
4088
			 TableInfo *tblinfo, int numTables)
V
Vadim B. Mikheev 已提交
4089
{
4090 4091 4092
	int			i,
				j;

V
Vadim B. Mikheev 已提交
4093 4094 4095
	if (g_verbose)
		fprintf(stderr, "%s dumping out triggers %s\n",
				g_comment_start, g_comment_end);
4096

V
Vadim B. Mikheev 已提交
4097 4098 4099 4100 4101 4102
	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 已提交
4103
			ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
4104
						"TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "", "", 
B
Bruce Momjian 已提交
4105 4106
						tblinfo[i].usename, NULL, NULL);
			dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid);
V
Vadim B. Mikheev 已提交
4107 4108 4109
		}
	}
}
4110 4111


4112
static void
B
Bruce Momjian 已提交
4113
dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
4114
		  TableInfo *tblinfo, int numTables)
4115
{
B
Bruce Momjian 已提交
4116 4117 4118 4119
	PGresult   *res;
	int			nrules;
	int			i,
				t;
4120
	PQExpBuffer query = createPQExpBuffer();
4121

B
Bruce Momjian 已提交
4122
	int			i_definition;
4123
	int			i_oid;
4124
	int			i_owner;
4125
	int			i_rulename;
4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140

	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
4141 4142
		 * We include pg_rules in the cross since it filters out
		 * all view rules (pjw 15-Sep-2000).
4143
		 */
B
Hi, all  
Bruce Momjian 已提交
4144
		resetPQExpBuffer(query);
4145
		appendPQExpBuffer(query, "SELECT definition,"
4146
						  "   (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
4147 4148
						  "   pg_rewrite.oid, pg_rewrite.rulename "
						  "FROM pg_rewrite, pg_class, pg_rules "
4149
						  "WHERE pg_class.relname = '%s' "
4150 4151 4152
						  "    AND pg_rewrite.ev_class = pg_class.oid "
						  "    AND pg_rules.tablename = pg_class.relname "
						  "    AND pg_rules.rulename = pg_rewrite.rulename "
4153 4154
						  "ORDER BY pg_rewrite.oid",
						  tblinfo[t].relname);
B
Hi, all  
Bruce Momjian 已提交
4155
		res = PQexec(g_conn, query->data);
4156 4157 4158
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
4159
			fprintf(stderr, "dumpRules(): SELECT failed for rules associated with table \"%s\".\n\tExplanation from backend: '%s'.\n",
B
Bruce Momjian 已提交
4160
					tblinfo[t].relname, PQerrorMessage(g_conn));
4161 4162 4163 4164 4165
			exit_nicely(g_conn);
		}

		nrules = PQntuples(res);
		i_definition = PQfnumber(res, "definition");
4166
		i_owner = PQfnumber(res, "viewowner");
B
Bruce,  
Bruce Momjian 已提交
4167 4168
		i_oid = PQfnumber(res, "oid");
		i_rulename = PQfnumber(res, "rulename");
4169 4170 4171 4172

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

4174 4175
		for (i = 0; i < nrules; i++)
		{
B
Bruce Momjian 已提交
4176 4177
			ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
							"RULE", NULL, PQgetvalue(res, i, i_definition),
4178
							"", "", PQgetvalue(res, i, i_owner), NULL, NULL);
4179

B
Bruce,  
Bruce Momjian 已提交
4180 4181 4182 4183 4184
			/* 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));
4185

B
Bruce,  
Bruce Momjian 已提交
4186 4187
		}

4188 4189 4190 4191
		PQclear(res);
	}
}