pg_dump.c 100.7 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.160 2000/07/21 11:40:08 pjw Exp $
26
 *
27
 * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
28
 *
29 30 31 32
 *	 Applied 'insert string' patch from "Marc G. Fournier" <scrappy@ki.net>
 *	 Added '-t table' option
 *	 Added '-a' option
 *	 Added '-da' option
33
 *
34 35
 * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
 *
36 37 38
 *	 - Fixed dumpTable output to output lengths for char and varchar types!
 *	 - Added single. quote to twin single quote expansion for 'insert' string
 *	   mode.
39
 *
40 41
 * Modifications - 7/26/96 - asussman@vidya.com
 *
42
 *	 - Fixed ouput lengths for char and varchar type where the length is variable (-1)
43
 *
44 45
 * Modifications - 6/1/97 - igor@sba.miami.edu
 * - Added functions to free allocated memory used for retrieving
46 47
 *	 indices,tables,inheritance,types,functions and aggregates.
 *	 No more leaks reported by Purify.
48 49 50
 *
 *
 * Modifications - 1/26/98 - pjlobo@euitt.upm.es
51
 *		 - Added support for password authentication
B
Bruce Momjian 已提交
52 53 54 55 56 57 58 59 60 61 62 63
 *
 * Modifications - 28-Jun-2000 - Philip Warner pjw@rhyme.com.au
 *		 - Used custom IO routines to allow for more
 *		   output formats and simple rearrangement of order.
 *		 - Discouraged operations more appropriate to the 'restore'
 *		   operation. (eg. -c "clear schema" - now always dumps
 *		   commands, but pg_restore can be told not to output them). 
 *		 - Added RI warnings to the 'as insert strings' output mode
 *		 - Added a small number of comments
 *		 - Added a -Z option for compression level on compressed formats
 *		 - Restored '-f' in usage output
 *
64 65 66 67 68 69
 *
 * 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)
 *
 *-------------------------------------------------------------------------
70 71
 */

72
#include <unistd.h>				/* for getopt() */
73
#include <ctype.h>
74

75 76
#include "pg_backup.h"

77
#include "postgres.h"
78 79 80 81 82 83 84 85 86

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

#include "access/attnum.h"
87
#include "access/htup.h"
88
#include "catalog/pg_index.h"
89
#include "catalog/pg_language.h"
V
Vadim B. Mikheev 已提交
90
#include "catalog/pg_trigger.h"
91
#include "catalog/pg_type.h"
92

93
#include "libpq-fe.h"
94
#include <libpq/libpq-fs.h>
95
#ifndef HAVE_STRDUP
96 97
#include "strdup.h"
#endif
98 99

#include "pg_dump.h"
B
Bruce Momjian 已提交
100
#include "pg_backup.h"
101

B
Bruce Momjian 已提交
102 103 104 105
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,
106
			 TableInfo *tblinfo, int numTables);
B
Bruce Momjian 已提交
107
static void dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
108
		  TableInfo *tblinfo, int numTables);
109 110
static char *checkForQuote(const char *s);
static void clearTableInfo(TableInfo *, int);
B
Bruce Momjian 已提交
111
static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
112
			TypeInfo *tinfo, int numTypes);
113 114
static int	findLastBuiltinOid(void);
static bool isViewRule(char *relname);
B
Bruce Momjian 已提交
115
static void setMaxOid(Archive *fout);
116

117 118
static void AddAcl(char *aclbuf, const char *keyword);
static char *GetPrivileges(const char *s);
V
Vadim B. Mikheev 已提交
119

120 121 122
static int dumpBlobs(Archive *AH, char*, void*);


B
Bruce Momjian 已提交
123
extern char *optarg;
124
extern int	optind,
B
Bruce Momjian 已提交
125
			opterr;
126 127

/* global decls */
128
bool		g_verbose;			/* User wants verbose narration of our
B
Bruce Momjian 已提交
129 130
								 * activities. */
int			g_last_builtin_oid; /* value of the last builtin oid */
B
Bruce Momjian 已提交
131
Archive	   *g_fout;				/* the script file */
B
Bruce Momjian 已提交
132 133 134
PGconn	   *g_conn;				/* the database connection */

bool		force_quotes;		/* User wants to suppress double-quotes */
135 136 137 138
bool		dumpData;			/* dump data using proper insert strings */
bool		attrNames;			/* put attr names into insert strings */
bool		schemaOnly;
bool		dataOnly;
139
bool		aclsSkip;
140

B
Bruce Momjian 已提交
141
char		g_opaque_type[10];	/* name for the opaque type */
142 143

/* placeholders for the delimiters for comments */
144 145
char		g_comment_start[10];
char		g_comment_end[10];
146 147


B
Bruce Momjian 已提交
148 149 150 151 152 153
typedef struct _dumpContext {
	TableInfo	*tblinfo;
	int		tblidx;
	bool		oids;
} DumpContext;

154
static void
155
help(const char *progname)
156
{
P
Peter Eisentraut 已提交
157
	printf("%s dumps a database as a text file.\n\n", progname);
158 159 160
	puts("Usage:");
	printf("  %s [options] dbname\n\n", progname);
	puts("Options:");
B
Hi,  
Bruce Momjian 已提交
161 162

#ifdef HAVE_GETOPT_LONG
163
	puts(
B
Bruce Momjian 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
		"  -a, --data-only          dump out only the data, not the schema\n"
	   	"  -c, --clean              clean (drop) schema prior to create\n"
		"  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"
		"  -D, --attribute-inserts  dump data as INSERT commands with attribute names\n"
		"  -f, --file               specify output file name\n"
		"  -F, --format {c|f|p}     output file format (custom, files, plain text)\n"
		"  -h, --host <hostname>    server host name\n"
		"  -i, --ignore-version     proceed when database version != pg_dump version\n"
		"  -n, --no-quotes          suppress most quotes around identifiers\n"
		"  -N, --quotes             enable most quotes around identifiers\n"
		"  -o, --oids               dump object ids (oids)\n"
		"  -p, --port <port>        server port number\n"
		"  -s, --schema-only        dump out only the schema, no data\n"
		"  -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"
182
		);
B
Hi,  
Bruce Momjian 已提交
183
#else
184
	puts(
B
Bruce Momjian 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
		"  -a                       dump out only the data, no schema\n"
		"  -c                       clean (drop) schema prior to create\n"
		"  -d                       dump data as INSERT, rather than COPY, commands\n"
		"  -D                       dump data as INSERT commands with attribute names\n"
		"  -f                       specify output file name\n"
		"  -F {c|f|p}               output file format (custom, files, plain text)\n"
		"  -h <hostname>            server host name\n"
		"  -i                       proceed when database version != pg_dump version\n"
		"  -n                       suppress most quotes around identifiers\n"
		"  -N                       enable most quotes around identifiers\n"
		"  -o                       dump object ids (oids)\n"
		"  -p <port>                server port number\n"
		"  -s                       dump out only the schema, no data\n"
		"  -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"
203
		);
B
Hi,  
Bruce Momjian 已提交
204
#endif
205 206
	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>.");
207
}
208

209

210 211 212
static void
version(void)
{
213
	puts("pg_dump (PostgreSQL) " PG_VERSION);
214 215 216
	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.");
217 218
}

219

220
static void
221
exit_nicely(PGconn *conn)
222
{
223 224
	PQfinish(conn);
	exit(1);
225 226 227
}


M
Marc G. Fournier 已提交
228 229
/*
 * isViewRule
230
 *				Determine if the relation is a VIEW
M
Marc G. Fournier 已提交
231 232
 *
 */
233
static bool
M
Marc G. Fournier 已提交
234 235
isViewRule(char *relname)
{
B
Bruce Momjian 已提交
236 237
	PGresult   *res;
	int			ntups;
238
	PQExpBuffer query = createPQExpBuffer();
239

B
Hi, all  
Bruce Momjian 已提交
240 241 242 243
	appendPQExpBuffer(query, "select relname from pg_class, pg_rewrite ");
	appendPQExpBuffer(query, "where pg_class.oid = ev_class ");
	appendPQExpBuffer(query, "and pg_rewrite.ev_type = '1' ");
	appendPQExpBuffer(query, "and rulename = '_RET%s'", relname);
244

B
Hi, all  
Bruce Momjian 已提交
245
	res = PQexec(g_conn, query->data);
246 247 248
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
249 250
		fprintf(stderr, "isViewRule(): SELECT failed.  Explanation from backend: '%s'.\n", 
					PQerrorMessage(g_conn));
251 252 253 254 255 256 257
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	PQclear(res);
	return ntups > 0 ? TRUE : FALSE;
M
Marc G. Fournier 已提交
258
}
259

260 261
#define COPYBUFSIZ		8192

B
Bruce Momjian 已提交
262 263 264 265 266 267 268
/*
 *	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.
 */
static int 
dumpClasses_nodumpData(Archive *fout, char* oid, void *dctxv)
269
{
B
Bruce Momjian 已提交
270 271 272
	const DumpContext	*dctx = (DumpContext*)dctxv; 	
	const char 	*classname = dctx->tblinfo[dctx->tblidx].relname;
	const bool	oids = dctx->oids;
273

274 275 276 277 278
	PGresult   *res;
	char		query[255];
	int			ret;
	bool		copydone;
	char		copybuf[COPYBUFSIZ];
279

280
	if (oids == true)
281
	{
282 283 284 285 286 287 288 289
		/* 
		 * 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)
		 *
		 */

290
		sprintf(query, "COPY %s WITH OIDS TO stdout;\n",
291
				fmtId(classname, force_quotes));
292 293 294
	}
	else
	{
295 296 297 298 299 300 301
		/* 
		 *archprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname, force_quotes));
		 *
		 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
		 *
		 */

302
		sprintf(query, "COPY %s TO stdout;\n", fmtId(classname, force_quotes));
303 304
	}
	res = PQexec(g_conn, query);
305 306
	if (!res ||
		PQresultStatus(res) == PGRES_FATAL_ERROR)
307
	{
308
		fprintf(stderr, "SQL query to dump the contents of Table '%s' "
309 310 311 312 313 314 315 316 317
				"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)
		{
318
			fprintf(stderr, "SQL query to dump the contents of Table '%s' "
319 320 321 322 323 324 325 326 327 328 329
					"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;
			while (!copydone)
			{
330
				ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
331 332 333 334 335 336 337 338 339

				if (copybuf[0] == '\\' &&
					copybuf[1] == '.' &&
					copybuf[2] == '\0')
				{
					copydone = true;	/* don't print this... */
				}
				else
				{
B
Bruce Momjian 已提交
340
					archputs(copybuf, fout);
341 342
					switch (ret)
					{
343 344 345 346
						case EOF:
							copydone = true;
							/* FALLTHROUGH */
						case 0:
B
Bruce Momjian 已提交
347
							archputc('\n', fout);
348 349 350
							break;
						case 1:
							break;
351 352 353
					}
				}
			}
B
Bruce Momjian 已提交
354
			archprintf(fout, "\\.\n");
355
		}
356
		ret = PQendcopy(g_conn);
357 358
		if (ret != 0)
		{
359
			fprintf(stderr, "SQL query to dump the contents of Table '%s' "
360 361 362 363 364
					"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 已提交
365
			PQclear(res);
366 367 368
			exit_nicely(g_conn);
		}
	}
B
Bruce Momjian 已提交
369
	return 1;
370 371 372 373
}



B
Bruce Momjian 已提交
374 375
static int
dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
376
{
B
Bruce Momjian 已提交
377 378 379
	const DumpContext	*dctx = (DumpContext*)dctxv;
	const char			*classname = dctx->tblinfo[dctx->tblidx].relname;

380 381
	PGresult   *res;
	PQExpBuffer q = createPQExpBuffer();
382 383
	int			tuple;
	int			field;
384
	const char *expsrc;
385

B
Hi, all  
Bruce Momjian 已提交
386 387
	appendPQExpBuffer(q, "SELECT * FROM %s", fmtId(classname, force_quotes));
	res = PQexec(g_conn, q->data);
388 389 390
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
391 392
		fprintf(stderr, "dumpClasses(): command failed.  Explanation from backend: '%s'.\n", 
					PQerrorMessage(g_conn));
393 394
		exit_nicely(g_conn);
	}
395
	for (tuple = 0; tuple < PQntuples(res); tuple++)
396
	{
B
Bruce Momjian 已提交
397
		archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
398
		if (attrNames == true)
399
		{
B
Hi, all  
Bruce Momjian 已提交
400 401
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "(");
402
			for (field = 0; field < PQnfields(res); field++)
403
			{
404
				if (field > 0)
B
Hi, all  
Bruce Momjian 已提交
405 406
					appendPQExpBuffer(q, ",");
				appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
407
			}
B
Hi, all  
Bruce Momjian 已提交
408
			appendPQExpBuffer(q, ") ");
B
Bruce Momjian 已提交
409
			archprintf(fout, "%s", q->data);
410
		}
B
Bruce Momjian 已提交
411
		archprintf(fout, "VALUES (");
412
		for (field = 0; field < PQnfields(res); field++)
413
		{
414
			if (field > 0)
B
Bruce Momjian 已提交
415
				archprintf(fout, ",");
416
			if (PQgetisnull(res, tuple, field))
417
			{
B
Bruce Momjian 已提交
418
				archprintf(fout, "NULL");
419 420 421
				continue;
			}
			switch (PQftype(res, field))
422
			{
423 424
				case INT2OID:
				case INT4OID:
425
				case OIDOID:	/* int types */
426
				case FLOAT4OID:
427
				case FLOAT8OID:/* float types */
428
					/* These types are printed without quotes */
B
Bruce Momjian 已提交
429
					archprintf(fout, "%s",
430 431 432
							PQgetvalue(res, tuple, field));
					break;
				default:
433

434 435
					/*
					 * All other types are printed as string literals,
436 437 438
					 * with appropriate escaping of special characters.
					 * Quote mark ' goes to '' per SQL standard, other
					 * stuff goes to \ sequences.
439
					 */
B
Bruce Momjian 已提交
440
					archputc('\'', fout);
441 442 443 444 445 446
					expsrc = PQgetvalue(res, tuple, field);
					while (*expsrc)
					{
						char		ch = *expsrc++;

						if (ch == '\\' || ch == '\'')
447
						{
B
Bruce Momjian 已提交
448 449
							archputc(ch, fout);			/* double these */
							archputc(ch, fout);
450
						}
451 452 453
						else if (ch < '\040')
						{
							/* generate octal escape for control chars */
B
Bruce Momjian 已提交
454 455 456 457
							archputc('\\', fout);
							archputc(((ch >> 6) & 3) + '0', fout);
							archputc(((ch >> 3) & 7) + '0', fout);
							archputc((ch & 7) + '0', fout);
458 459
						}
						else
B
Bruce Momjian 已提交
460
							archputc(ch, fout);
461
					}
B
Bruce Momjian 已提交
462
					archputc('\'', fout);
463
					break;
464
			}
465
		}
B
Bruce Momjian 已提交
466
		archprintf(fout, ");\n");
467 468
	}
	PQclear(res);
B
Bruce Momjian 已提交
469
	return 1;
470 471 472 473
}

/*
 * DumpClasses -
474
 *	  dump the contents of all the classes.
475 476
 */
static void
B
Bruce Momjian 已提交
477
dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
478
			const char *onlytable, const bool oids, const bool force_quotes)
479 480
{

B
Bruce Momjian 已提交
481 482 483 484
	int				i;
	char	   		*all_only;
	DataDumperPtr	dumpFn;
	DumpContext		*dumpCtx;
485 486 487
	char			*oidsPart;
	char			copyBuf[512];
	char			*copyStmt;
488 489 490 491

	if (onlytable == NULL)
		all_only = "all";
	else
492
		all_only = "only";
493

494 495 496 497 498 499
	if (oids == true)
		oidsPart = "WITH OIDS ";
	else
		oidsPart = "";


500
	if (g_verbose)
501 502 503
		fprintf(stderr, "%s dumping out the contents of %s %d table%s/sequence%s %s\n",
				g_comment_start, all_only,
				(onlytable == NULL) ? numTables : 1,
504
		  (onlytable == NULL) ? "s" : "", (onlytable == NULL) ? "s" : "",
505
				g_comment_end);
506

V
Vadim B. Mikheev 已提交
507 508 509 510 511 512 513 514 515 516
	/* 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)
517
					fprintf(stderr, "%s dumping out schema of sequence '%s' %s\n",
518
					 g_comment_start, tblinfo[i].relname, g_comment_end);
B
Bruce Momjian 已提交
519
				/* becomeUser(fout, tblinfo[i].usename); */
V
Vadim B. Mikheev 已提交
520 521 522 523
				dumpSequence(fout, tblinfo[i]);
			}
		}
	}
524 525 526

	for (i = 0; i < numTables; i++)
	{
527
		const char *classname = tblinfo[i].relname;
528 529 530 531

		/* Skip VIEW relations */
		if (isViewRule(tblinfo[i].relname))
			continue;
532 533

		if (tblinfo[i].sequence)/* already dumped */
V
Vadim B. Mikheev 已提交
534
			continue;
535 536 537 538

		if (!onlytable || (!strcmp(classname, onlytable)))
		{
			if (g_verbose)
539
				fprintf(stderr, "%s dumping out the contents of Table '%s' %s\n",
540 541
						g_comment_start, classname, g_comment_end);

B
Bruce Momjian 已提交
542 543 544 545 546 547
			/* becomeUser(fout, tblinfo[i].usename); */

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

549 550
			if (!dumpData) /* Dump/restore using COPY */
			{
B
Bruce Momjian 已提交
551 552
				dumpFn = dumpClasses_nodumpData;
				/* dumpClasses_nodumpData(fout, classname, oids); */
553 554 555 556 557 558
				sprintf(copyBuf, "COPY %s %s FROM stdin;\n", fmtId(tblinfo[i].relname, force_quotes),
						oidsPart);
				copyStmt = copyBuf;
			}
			else /* Restore using INSERT */
			{
B
Bruce Momjian 已提交
559 560
				dumpFn = dumpClasses_dumpData;
				/* dumpClasses_dumpData(fout, classname); */
561 562
				copyStmt = NULL;
			}
B
Bruce Momjian 已提交
563 564

			ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
565
							"TABLE DATA", NULL, "", "", copyStmt, tblinfo[i].usename,
B
Bruce Momjian 已提交
566
							dumpFn, dumpCtx);
567
		}
568
	}
569 570
}

571
int
572
main(int argc, char **argv)
573
{
B
Bruce Momjian 已提交
574 575 576
	int			c;
	const char *progname;
	const char *filename = NULL;
B
Bruce Momjian 已提交
577
	const char *format = "p";
B
Bruce Momjian 已提交
578 579 580 581
	const char *dbname = NULL;
	const char *pghost = NULL;
	const char *pgport = NULL;
	char	   *tablename = NULL;
582
	bool		oids = false;
B
Bruce Momjian 已提交
583 584
	TableInfo  *tblinfo;
	int			numTables;
585
	bool		use_password = false;
B
Bruce Momjian 已提交
586
	int			compressLevel = -1;
587
	bool		ignore_version = false;
588 589 590 591
	int			plainText = 0;
	int			outputClean = 0;
	int			outputBlobs = 0;

B
Bruce Momjian 已提交
592
	RestoreOptions	*ropt;
593

B
Hi,  
Bruce Momjian 已提交
594 595 596
#ifdef HAVE_GETOPT_LONG
	static struct option long_options[] = {
		{"data-only", no_argument, NULL, 'a'},
597
		{"blobs", no_argument, NULL, 'b' },
B
Hi,  
Bruce Momjian 已提交
598
		{"clean", no_argument, NULL, 'c'},
B
Bruce Momjian 已提交
599 600
		{"file", required_argument, NULL, 'f'},
		{"format", required_argument, NULL, 'F'},
601
		{"inserts", no_argument, NULL, 'd'},
602
		{"attribute-inserts", no_argument, NULL, 'D'},
B
Hi,  
Bruce Momjian 已提交
603
		{"host", required_argument, NULL, 'h'},
604
		{"ignore-version", no_argument, NULL, 'i'},
B
Hi,  
Bruce Momjian 已提交
605 606
		{"no-quotes", no_argument, NULL, 'n'},
		{"quotes", no_argument, NULL, 'N'},
607
		{"oids", no_argument, NULL, 'o'},
B
Hi,  
Bruce Momjian 已提交
608 609 610 611 612 613
		{"port", required_argument, NULL, 'p'},
		{"schema-only", no_argument, NULL, 's'},
		{"table", required_argument, NULL, 't'},
		{"password", no_argument, NULL, 'u'},
		{"verbose", no_argument, NULL, 'v'},
		{"no-acl", no_argument, NULL, 'x'},
B
Bruce Momjian 已提交
614
		{"compress", required_argument, NULL, 'Z'},
B
Hi,  
Bruce Momjian 已提交
615
		{"help", no_argument, NULL, '?'},
616
		{"version", no_argument, NULL, 'V'}
617
	};
618 619
	int			optindex;

B
Hi,  
Bruce Momjian 已提交
620 621
#endif

622
	g_verbose = false;
623
	force_quotes = true;
624 625 626 627 628

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

629
	dataOnly = schemaOnly = dumpData = attrNames = false;
630

631 632 633 634
	if (!strrchr(argv[0], SEP_CHAR))
		progname = argv[0];
	else
		progname = strrchr(argv[0], SEP_CHAR) + 1;
635

636 637 638 639 640 641
	/* Set defaulty options based on progname */
	if (strcmp(progname, "pg_backup") == 0)
	{
		format = "c";
		outputBlobs = 1;
	}
642

B
Hi,  
Bruce Momjian 已提交
643
#ifdef HAVE_GETOPT_LONG
B
Bruce Momjian 已提交
644
	while ((c = getopt_long(argc, argv, "acdDf:F:h:inNop:st:uvxzZ:V?", long_options, &optindex)) != -1)
B
Hi,  
Bruce Momjian 已提交
645
#else
B
Bruce Momjian 已提交
646
	while ((c = getopt(argc, argv, "acdDf:F:h:inNop:st:uvxzZ:V?-")) != -1)
B
Hi,  
Bruce Momjian 已提交
647
#endif
648 649 650
	{
		switch (c)
		{
651
			case 'a':			/* Dump data only */
652
				dataOnly = true;
653
				break;
654 655 656 657
			case 'b':			/* Dump blobs */
				outputBlobs = true;
				break;

B
Bruce Momjian 已提交
658
			case 'c':			/* clean (i.e., drop) schema prior to
B
Bruce Momjian 已提交
659 660 661 662
 								 * create */
				outputClean = 1;
 				break;
 
663
			case 'd':			/* dump data as proper insert strings */
664
				dumpData = true;
665 666 667
				break;
			case 'D':			/* dump data as proper insert strings with
								 * attr names */
668 669
				dumpData = true;
				attrNames = true;
670
				break;
671
			case 'f':
672 673
				filename = optarg;
				break;
B
Bruce Momjian 已提交
674 675 676
			case 'F':
				format = optarg;
				break;
B
Bruce Momjian 已提交
677
			case 'h':			/* server host */
678 679
				pghost = optarg;
				break;
680 681 682
			case 'i':			/* ignore database version mismatch */
				ignore_version = true;
				break;
B
Bruce Momjian 已提交
683 684
			case 'n':			/* Do not force double-quotes on
								 * identifiers */
685
				force_quotes = false;
686
				break;
687
			case 'N':			/* Force double-quotes on identifiers */
688
				force_quotes = true;
689
				break;
690
			case 'o':			/* Dump oids */
691
				oids = true;
692
				break;
693 694 695
			case 'p':			/* server port */
				pgport = optarg;
				break;
696
			case 's':			/* dump schema only */
697
				schemaOnly = true;
698 699
				break;
			case 't':			/* Dump data for this table only */
700
				{
701
					int			i;
702 703

					tablename = strdup(optarg);
B
Bruce Momjian 已提交
704 705 706 707 708

					/*
					 * quoted string? Then strip quotes and preserve
					 * case...
					 */
709 710 711
					if (tablename[0] == '"')
					{
						strcpy(tablename, &tablename[1]);
B
Bruce Momjian 已提交
712 713
						if (*(tablename + strlen(tablename) - 1) == '"')
							*(tablename + strlen(tablename) - 1) = '\0';
714 715 716 717 718
					}
					/* otherwise, convert table name to lowercase... */
					else
					{
						for (i = 0; tablename[i]; i++)
719 720
							if (isascii((int) tablename[i]) &&
								isupper((int) tablename[i]))
721 722
								tablename[i] = tolower(tablename[i]);
					}
723
				}
724
				break;
725 726 727
			case 'u':
				use_password = true;
				break;
728 729
			case 'v':			/* verbose */
				g_verbose = true;
730
				break;
731 732
			case 'x':			/* skip ACL dump */
				aclsSkip = true;
733
				break;
B
Bruce Momjian 已提交
734 735 736
			case 'Z':			/* Compression Level */
				compressLevel = atoi(optarg);
				break;
737 738 739 740
			case 'V':
				version();
				exit(0);
				break;
741
			case '?':
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756

				/*
				 * 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);
				}
757
				break;
758 759 760
#ifndef HAVE_GETOPT_LONG
			case '-':
				fprintf(stderr, "%s was compiled without support for long options.\n"
761
				   "Use -? for help on invocation options.\n", progname);
762 763 764
				exit(1);
				break;
#endif
765
			default:
766 767
				fprintf(stderr, "%s: unknown option -%c\nTry -? for help.\n", progname, c);
				exit(1);
768 769 770
		}
	}

B
Bruce Momjian 已提交
771 772 773 774 775 776 777 778
	if (dataOnly && schemaOnly)
	{
		fprintf(stderr,
				"%s: 'Schema Only' and 'Data Only' are incompatible options.\n",
				progname);
		exit(1);
	}

779 780 781
	if (dumpData == true && oids == true)
	{
		fprintf(stderr,
782
				"%s: INSERT's can not set oids, so INSERT and OID options can not be used together.\n",
783
				progname);
784
		exit(1);
785
	}
786

787
	/* open the output file */
B
Bruce Momjian 已提交
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
	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;
803 804 805 806 807 808
			g_fout = CreateArchive(filename, archNull, 0);
			break;

		case 't':
		case 'T':
			g_fout = CreateArchive(filename, archTar, compressLevel);
B
Bruce Momjian 已提交
809 810 811
			break;

		default:
812
			fprintf(stderr,
B
Bruce Momjian 已提交
813 814 815 816 817 818 819 820 821 822
				"%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);
823 824
	}

825 826
	/* Let the archiver know how noisy to be */
	g_fout->verbose = g_verbose;
827

828
	dbname = argv[optind];
829

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

833 834 835 836 837 838 839 840
	/*
	 * Start serializable transaction to dump consistent data
	 */
	{
		PGresult   *res;

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

844 845 846
		PQclear(res);
		res = PQexec(g_conn, "set transaction isolation level serializable");
		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
847 848 849
		    exit_horribly(g_fout, "SET TRANSACTION command failed. Explanation from backend: '%s'.\n",
				PQerrorMessage(g_conn));

850 851 852
		PQclear(res);
	}

853 854
	g_last_builtin_oid = findLastBuiltinOid();

855
	if (oids == true)
856
		setMaxOid(g_fout);
B
Bruce Momjian 已提交
857 858

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

863
	if (!schemaOnly)
864 865 866 867 868 869
	{
	    dumpClasses(tblinfo, numTables, g_fout, tablename, oids, force_quotes);
	}

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

871 872
	if (!dataOnly)				/* dump indexes and triggers at the end
								 * for performance */
V
Vadim B. Mikheev 已提交
873 874 875
	{
		dumpSchemaIdx(g_fout, tablename, tblinfo, numTables);
		dumpTriggers(g_fout, tablename, tblinfo, numTables);
876
		dumpRules(g_fout, tablename, tblinfo, numTables);
V
Vadim B. Mikheev 已提交
877
	}
878

879 880 881 882 883 884 885 886 887
	/* Now sort the output nicely */
	SortTocByOID(g_fout);
	MoveToEnd(g_fout, "TABLE DATA");
	MoveToEnd(g_fout, "BLOBS");
	MoveToEnd(g_fout, "INDEX");
	MoveToEnd(g_fout, "TRIGGER");
	MoveToEnd(g_fout, "RULE");
	MoveToEnd(g_fout, "ACL");

B
Bruce Momjian 已提交
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
	if (plainText) 
	{
		ropt = NewRestoreOptions();
		ropt->filename = (char*)filename;
		ropt->dropSchema = outputClean;
		ropt->aclsSkip = aclsSkip;

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

		RestoreArchive(g_fout, ropt);
	}

	CloseArchive(g_fout);
904

905 906 907
	clearTableInfo(tblinfo, numTables);
	PQfinish(g_conn);
	exit(0);
908 909
}

910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
/*
 * 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 */
    appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT oid from pg_class where relkind = 'l'");

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

996
/*
997 998
 * getTypes:
 *	  read all base types in the system catalogs and return them in the
999 1000
 * TypeInfo* structure
 *
1001
 *	numTypes is set to the number of types read in
1002 1003
 *
 */
1004
TypeInfo   *
1005 1006
getTypes(int *numTypes)
{
B
Bruce Momjian 已提交
1007
	PGresult   *res;
1008 1009
	int			ntups;
	int			i;
1010
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1011
	TypeInfo   *tinfo;
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027

	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;
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039

	/* 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 已提交
1040
	appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
1041
		  "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
1042 1043
		 "typdefault, typrelid, typbyval, usename from pg_type, pg_user "
					  "where typowner = usesysid");
1044

B
Hi, all  
Bruce Momjian 已提交
1045
	res = PQexec(g_conn, query->data);
1046 1047 1048
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1049
		fprintf(stderr, "getTypes(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
		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");

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

		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;
1110 1111 1112 1113
}

/*
 * getOperators:
1114
 *	  read all operators in the system catalogs and return them in the
1115 1116
 * OprInfo* structure
 *
1117 1118
 *	numOprs is set to the number of operators read in
 *
1119 1120
 *
 */
1121
OprInfo    *
1122 1123
getOperators(int *numOprs)
{
1124
	PGresult   *res;
1125 1126
	int			ntups;
	int			i;
1127
	PQExpBuffer query = createPQExpBuffer();
1128

B
Bruce Momjian 已提交
1129
	OprInfo    *oprinfo;
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144

	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;
1145 1146 1147 1148 1149 1150

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

B
Hi, all  
Bruce Momjian 已提交
1151
	appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
1152 1153 1154 1155
			   "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
					  "oprcanhash, oprlsortop, oprrsortop, usename "
					  "from pg_operator, pg_user "
					  "where oprowner = usesysid");
1156

B
Hi, all  
Bruce Momjian 已提交
1157
	res = PQexec(g_conn, query->data);
1158 1159 1160
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1161
		fprintf(stderr, "getOperators(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
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 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
		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));
	}

	PQclear(res);

	return oprinfo;
1206 1207
}

1208
void
1209
clearTypeInfo(TypeInfo *tp, int numTypes)
1210
{
1211
	int			i;
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244

	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);
1245 1246 1247
}

void
1248
clearFuncInfo(FuncInfo *fun, int numFuncs)
1249
{
1250 1251
	int			i,
				a;
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262

	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);
1263
		for (a = 0; a < FUNC_MAX_ARGS; ++a)
1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
			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);
1274 1275
}

1276
static void
1277
clearTableInfo(TableInfo *tblinfo, int numTables)
1278
{
1279 1280
	int			i,
				j;
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300

	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 已提交
1301 1302
			if (tblinfo[i].attoids[j])
				free(tblinfo[i].attoids[j]);
1303 1304 1305 1306 1307
			if (tblinfo[i].attnames[j])
				free(tblinfo[i].attnames[j]);
			if (tblinfo[i].typnames[j])
				free(tblinfo[i].typnames[j]);
		}
B
Bruce Momjian 已提交
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323

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

1324 1325
		if (tblinfo[i].atttypmod)
			free((int *) tblinfo[i].atttypmod);
1326 1327 1328 1329 1330 1331 1332 1333
		if (tblinfo[i].inhAttrs)
			free((int *) tblinfo[i].inhAttrs);
		if (tblinfo[i].attnames)
			free(tblinfo[i].attnames);
		if (tblinfo[i].typnames)
			free(tblinfo[i].typnames);
		if (tblinfo[i].notnull)
			free(tblinfo[i].notnull);
1334 1335
		if (tblinfo[i].primary_key)
			free(tblinfo[i].primary_key);
1336 1337
	}
	free(tblinfo);
1338 1339
}

1340
void
1341
clearInhInfo(InhInfo *inh, int numInherits)
1342
{
1343
	int			i;
1344 1345 1346 1347 1348

	if (!inh)
		return;
	for (i = 0; i < numInherits; ++i)
	{
1349 1350
		if (inh[i].inhrelid)
			free(inh[i].inhrelid);
1351 1352 1353 1354
		if (inh[i].inhparent)
			free(inh[i].inhparent);
	}
	free(inh);
1355 1356 1357
}

void
1358
clearOprInfo(OprInfo *opr, int numOprs)
1359
{
1360
	int			i;
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395

	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);
1396 1397 1398
}

void
1399
clearIndInfo(IndInfo *ind, int numIndices)
1400
{
1401 1402
	int			i,
				a;
1403 1404 1405 1406 1407

	if (!ind)
		return;
	for (i = 0; i < numIndices; ++i)
	{
B
Bruce,  
Bruce Momjian 已提交
1408 1409
		if (ind[i].indoid)
			free(ind[i].indoid);
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
		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);
1429 1430 1431
}

void
B
Bruce Momjian 已提交
1432
clearAggInfo(AggInfo *agginfo, int numArgs)
1433
{
1434
	int			i;
1435 1436 1437 1438 1439 1440 1441 1442 1443

	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);
1444 1445
		if (agginfo[i].aggtransfn)
			free(agginfo[i].aggtransfn);
1446 1447
		if (agginfo[i].aggfinalfn)
			free(agginfo[i].aggfinalfn);
1448 1449
		if (agginfo[i].aggtranstype)
			free(agginfo[i].aggtranstype);
1450 1451
		if (agginfo[i].aggbasetype)
			free(agginfo[i].aggbasetype);
1452 1453
		if (agginfo[i].agginitval)
			free(agginfo[i].agginitval);
1454 1455 1456 1457
		if (agginfo[i].usename)
			free(agginfo[i].usename);
	}
	free(agginfo);
1458
}
1459 1460 1461

/*
 * getAggregates:
1462
 *	  read all the user-defined aggregates in the system catalogs and
1463 1464
 * return them in the AggInfo* structure
 *
1465 1466
 * numAggs is set to the number of aggregates read in
 *
1467 1468
 *
 */
1469
AggInfo    *
1470 1471
getAggregates(int *numAggs)
{
B
Bruce Momjian 已提交
1472
	PGresult   *res;
1473 1474
	int			ntups;
	int			i;
1475
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1476
	AggInfo    *agginfo;
1477 1478 1479

	int			i_oid;
	int			i_aggname;
1480
	int			i_aggtransfn;
1481
	int			i_aggfinalfn;
1482
	int			i_aggtranstype;
1483
	int			i_aggbasetype;
1484
	int			i_agginitval;
1485
	int			i_usename;
1486 1487 1488

	/* find all user-defined aggregates */

B
Hi, all  
Bruce Momjian 已提交
1489
	appendPQExpBuffer(query,
1490 1491 1492
					  "SELECT pg_aggregate.oid, aggname, aggtransfn, "
					  "aggfinalfn, aggtranstype, aggbasetype, "
					  "agginitval, usename from pg_aggregate, pg_user "
1493
					  "where aggowner = usesysid");
1494

B
Hi, all  
Bruce Momjian 已提交
1495
	res = PQexec(g_conn, query->data);
1496 1497 1498
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1499 1500
		fprintf(stderr, "getAggregates(): SELECT failed.  Explanation from backend: '%s'.\n",
					PQerrorMessage(g_conn));
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510
		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");
1511
	i_aggtransfn = PQfnumber(res, "aggtransfn");
1512
	i_aggfinalfn = PQfnumber(res, "aggfinalfn");
1513
	i_aggtranstype = PQfnumber(res, "aggtranstype");
1514
	i_aggbasetype = PQfnumber(res, "aggbasetype");
1515
	i_agginitval = PQfnumber(res, "agginitval");
1516 1517 1518 1519 1520 1521
	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));
1522
		agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
1523
		agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
1524
		agginfo[i].aggtranstype = strdup(PQgetvalue(res, i, i_aggtranstype));
1525
		agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
1526
		agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
1527 1528 1529 1530 1531 1532
		agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
	}

	PQclear(res);

	return agginfo;
1533 1534 1535 1536
}

/*
 * getFuncs:
1537
 *	  read all the user-defined functions in the system catalogs and
1538 1539
 * return them in the FuncInfo* structure
 *
1540 1541
 * numFuncs is set to the number of functions read in
 *
1542 1543
 *
 */
1544
FuncInfo   *
1545 1546
getFuncs(int *numFuncs)
{
1547
	PGresult   *res;
1548 1549
	int			ntups;
	int			i;
1550 1551
	PQExpBuffer query = createPQExpBuffer();
	FuncInfo   *finfo;
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562

	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;
	int			i_usename;
1563 1564 1565

	/* find all user-defined funcs */

B
Hi, all  
Bruce Momjian 已提交
1566
	appendPQExpBuffer(query,
1567 1568 1569 1570 1571
		   "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
					  "proretset, proargtypes, prosrc, probin, usename "
					  "from pg_proc, pg_user "
				 "where pg_proc.oid > '%u'::oid and proowner = usesysid",
					  g_last_builtin_oid);
1572

B
Hi, all  
Bruce Momjian 已提交
1573
	res = PQexec(g_conn, query->data);
1574 1575 1576
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1577 1578
		fprintf(stderr, "getFuncs(): SELECT failed.  Explanation from backend: '%s'.\n", 
					PQerrorMessage(g_conn));
1579 1580 1581 1582 1583 1584 1585 1586 1587
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numFuncs = ntups;

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

1588 1589
	memset((char *) finfo, 0, ntups * sizeof(FuncInfo));

1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611
	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");
	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));
1612
		finfo[i].lang = atoi(PQgetvalue(res, i, i_prolang));
1613
		finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1614 1615 1616 1617
		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);
1618
			exit(1);
1619 1620 1621 1622
		}
		parseNumericArray(PQgetvalue(res, i, i_proargtypes),
						  finfo[i].argtypes,
						  finfo[i].nargs);
1623 1624 1625 1626 1627 1628
		finfo[i].dumped = 0;
	}

	PQclear(res);

	return finfo;
1629 1630 1631 1632 1633

}

/*
 * getTables
1634
 *	  read all the user-defined tables (no indices, no catalogs)
1635 1636
 * in the system catalogs return them in the TableInfo* structure
 *
1637 1638
 * numTables is set to the number of tables read in
 *
1639 1640
 *
 */
1641
TableInfo  *
V
Vadim B. Mikheev 已提交
1642
getTables(int *numTables, FuncInfo *finfo, int numFuncs)
1643
{
1644
	PGresult   *res;
1645 1646
	int			ntups;
	int			i;
1647
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1648
	PQExpBuffer delqry = createPQExpBuffer();
1649
	TableInfo  *tblinfo;
1650

B
Bruce Momjian 已提交
1651
	int			i_reloid;
1652 1653 1654 1655
	int			i_relname;
	int			i_relkind;
	int			i_relacl;
	int			i_usename;
V
Vadim B. Mikheev 已提交
1656 1657
	int			i_relchecks;
	int			i_reltriggers;
1658
	int			i_relhasindex;
1659 1660 1661 1662 1663 1664

	/*
	 * 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*
	 *
1665 1666 1667
	 * we ignore tables that are not type 'r' (ordinary relation) or 'S'
	 * (sequence) --- in particular, Large Object relations (type 'l') are
	 * ignored.
1668 1669
	 */

B
Hi, all  
Bruce Momjian 已提交
1670
	appendPQExpBuffer(query,
1671 1672 1673 1674 1675 1676
			   "SELECT pg_class.oid, relname, relkind, relacl, usename, "
					  "relchecks, reltriggers, relhasindex "
					  "from pg_class, pg_user "
					  "where relowner = usesysid and "
				"(relkind = 'r' or relkind = 'S') and relname !~ '^pg_' "
					  "order by oid");
1677

B
Hi, all  
Bruce Momjian 已提交
1678
	res = PQexec(g_conn, query->data);
1679 1680 1681
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1682 1683
		fprintf(stderr, "getTables(): SELECT failed.  Explanation from backend: '%s'.\n", 
					PQerrorMessage(g_conn));
1684 1685 1686 1687 1688 1689 1690 1691 1692
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numTables = ntups;

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

B
Bruce Momjian 已提交
1693
	i_reloid = PQfnumber(res, "oid");
1694 1695 1696 1697
	i_relname = PQfnumber(res, "relname");
	i_relkind = PQfnumber(res, "relkind");
	i_relacl = PQfnumber(res, "relacl");
	i_usename = PQfnumber(res, "usename");
V
Vadim B. Mikheev 已提交
1698 1699
	i_relchecks = PQfnumber(res, "relchecks");
	i_reltriggers = PQfnumber(res, "reltriggers");
B
Hi, all  
Bruce Momjian 已提交
1700
	i_relhasindex = PQfnumber(res, "relhasindex");
1701 1702 1703

	for (i = 0; i < ntups; i++)
	{
B
Bruce Momjian 已提交
1704
		tblinfo[i].oid = strdup(PQgetvalue(res, i, i_reloid));
1705 1706 1707 1708
		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 已提交
1709 1710
		tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
		tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
1711

B
Bruce Momjian 已提交
1712 1713 1714
		/*
		 * Exclude inherited CHECKs from CHECK constraints total. If a
		 * constraint matches by name and condition with a constraint
1715 1716 1717 1718
		 * belonging to a parent class, we assume it was inherited.
		 */
		if (tblinfo[i].ncheck > 0)
		{
B
Bruce Momjian 已提交
1719
			PGresult   *res2;
1720 1721
			int			ntups2;

B
Bruce Momjian 已提交
1722
			if (g_verbose)
1723 1724 1725 1726 1727 1728
				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 已提交
1729 1730
			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "SELECT rcname from pg_relcheck, pg_inherits as i "
1731 1732 1733 1734 1735 1736 1737 1738
							  "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 已提交
1739
			res2 = PQexec(g_conn, query->data);
1740 1741 1742
			if (!res2 ||
				PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
1743 1744
				fprintf(stderr, "getTables(): SELECT (for inherited CHECK) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759
				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 已提交
1760 1761 1762
		if (tblinfo[i].ncheck > 0)
		{
			PGresult   *res2;
1763 1764
			int			i_rcname,
						i_rcsrc;
V
Vadim B. Mikheev 已提交
1765 1766
			int			ntups2;
			int			i2;
1767

V
Vadim B. Mikheev 已提交
1768
			if (g_verbose)
1769
				fprintf(stderr, "%s finding CHECK constraints for relation: '%s' %s\n",
V
Vadim B. Mikheev 已提交
1770 1771 1772
						g_comment_start,
						tblinfo[i].relname,
						g_comment_end);
1773

B
Hi, all  
Bruce Momjian 已提交
1774 1775
			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
1776 1777 1778 1779 1780 1781 1782 1783
							  "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 已提交
1784
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
1785
			if (!res2 ||
1786
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
1787
			{
B
Bruce Momjian 已提交
1788 1789
				fprintf(stderr, "getTables(): SELECT (for CHECK) failed.  "
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
1790 1791 1792 1793 1794
				exit_nicely(g_conn);
			}
			ntups2 = PQntuples(res2);
			if (ntups2 != tblinfo[i].ncheck)
			{
1795
				fprintf(stderr, "getTables(): relation '%s': %d CHECKs were expected, but got %d\n",
1796
						tblinfo[i].relname, tblinfo[i].ncheck, ntups2);
V
Vadim B. Mikheev 已提交
1797 1798 1799 1800
				exit_nicely(g_conn);
			}
			i_rcname = PQfnumber(res2, "rcname");
			i_rcsrc = PQfnumber(res2, "rcsrc");
1801
			tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
V
Vadim B. Mikheev 已提交
1802 1803
			for (i2 = 0; i2 < ntups2; i2++)
			{
B
Bruce Momjian 已提交
1804 1805
				const char *name = PQgetvalue(res2, i2, i_rcname);
				const char *expr = PQgetvalue(res2, i2, i_rcsrc);
1806

B
Hi, all  
Bruce Momjian 已提交
1807
				resetPQExpBuffer(query);
1808 1809
				if (name[0] != '$')
				{
1810 1811
					appendPQExpBuffer(query, "CONSTRAINT %s ",
									  fmtId(name, force_quotes));
B
Bruce Momjian 已提交
1812
				}
1813
				appendPQExpBuffer(query, "CHECK (%s)", expr);
B
Hi, all  
Bruce Momjian 已提交
1814
				tblinfo[i].check_expr[i2] = strdup(query->data);
V
Vadim B. Mikheev 已提交
1815 1816 1817 1818 1819
			}
			PQclear(res2);
		}
		else
			tblinfo[i].check_expr = NULL;
1820

1821 1822
		/* Get primary key */
		if (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0)
1823
		{
1824 1825 1826
			PGresult   *res2;
			char		str[INDEX_MAX_KEYS * (NAMEDATALEN * 2 + 4) + 1];
			int			j;
B
Bruce Momjian 已提交
1827

B
Hi, all  
Bruce Momjian 已提交
1828
			resetPQExpBuffer(query);
B
Bruce Momjian 已提交
1829
			appendPQExpBuffer(query,
1830 1831 1832 1833 1834 1835
							  "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);
1836
			res2 = PQexec(g_conn, query->data);
B
Bruce Momjian 已提交
1837 1838 1839
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
				fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY) failed.  Explanation from backend: %s",
1840
						PQerrorMessage(g_conn));
B
Bruce Momjian 已提交
1841 1842
				exit_nicely(g_conn);
			}
1843

1844 1845 1846
			str[0] = '\0';
			for (j = 0; j < PQntuples(res2); j++)
			{
1847
				if (strlen(str) > 0)
1848 1849 1850 1851
					strcat(str, ", ");
				strcat(str, fmtId(PQgetvalue(res2, j, 0), force_quotes));
			}

1852 1853
			if (strlen(str) > 0)
			{
1854
				tblinfo[i].primary_key = strdup(str);
1855 1856
				if (tblinfo[i].primary_key == NULL)
				{
1857 1858 1859 1860 1861 1862
					perror("strdup");
					exit(1);
				}
			}
			else
				tblinfo[i].primary_key = NULL;
1863
		}
1864 1865
		else
			tblinfo[i].primary_key = NULL;
B
Bruce Momjian 已提交
1866

V
Vadim B. Mikheev 已提交
1867 1868 1869 1870
		/* Get Triggers */
		if (tblinfo[i].ntrig > 0)
		{
			PGresult   *res2;
B
Bruce,  
Bruce Momjian 已提交
1871
			int			i_tgoid,
1872
						i_tgname,
1873 1874 1875
						i_tgfoid,
						i_tgtype,
						i_tgnargs,
1876 1877 1878 1879 1880
						i_tgargs,
						i_tgisconstraint,
						i_tgconstrname,
						i_tgdeferrable,
						i_tginitdeferred;
V
Vadim B. Mikheev 已提交
1881 1882
			int			ntups2;
			int			i2;
1883

V
Vadim B. Mikheev 已提交
1884
			if (g_verbose)
1885
				fprintf(stderr, "%s finding Triggers for relation: '%s' %s\n",
V
Vadim B. Mikheev 已提交
1886 1887 1888
						g_comment_start,
						tblinfo[i].relname,
						g_comment_end);
1889

B
Hi, all  
Bruce Momjian 已提交
1890
			resetPQExpBuffer(query);
1891
			appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, tgisconstraint, tgconstrname, tgdeferrable, tginitdeferred, oid "
1892 1893 1894
							  "from pg_trigger "
							  "where tgrelid = '%s'::oid ",
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
1895
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
1896
			if (!res2 ||
1897
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
1898
			{
B
Bruce Momjian 已提交
1899 1900
				fprintf(stderr, "getTables(): SELECT (for TRIGGER) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
1901 1902 1903 1904 1905
				exit_nicely(g_conn);
			}
			ntups2 = PQntuples(res2);
			if (ntups2 != tblinfo[i].ntrig)
			{
1906
				fprintf(stderr, "getTables(): relation '%s': %d Triggers were expected, but got %d\n",
1907
						tblinfo[i].relname, tblinfo[i].ntrig, ntups2);
V
Vadim B. Mikheev 已提交
1908 1909 1910 1911 1912 1913 1914
				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 已提交
1915
			i_tgoid = PQfnumber(res2, "oid");
1916 1917 1918 1919 1920
			i_tgisconstraint = PQfnumber(res2, "tgisconstraint");
			i_tgconstrname = PQfnumber(res2, "tgconstrname");
			i_tgdeferrable = PQfnumber(res2, "tgdeferrable");
			i_tginitdeferred = PQfnumber(res2, "tginitdeferred");

B
Bruce Momjian 已提交
1921
			tblinfo[i].triggers = (TrigInfo*) malloc(ntups2 * sizeof(TrigInfo));
B
Hi, all  
Bruce Momjian 已提交
1922 1923
			resetPQExpBuffer(query);
			for (i2 = 0; i2 < ntups2; i2++)
V
Vadim B. Mikheev 已提交
1924
			{
1925
				const char *tgfuncoid = PQgetvalue(res2, i2, i_tgfoid);
1926
				char	   *tgfunc = NULL;
1927 1928
				int2		tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
				int			tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
B
Bruce Momjian 已提交
1929
				const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
1930 1931 1932
				int			tgisconstraint;
				int			tgdeferrable;
				int			tginitdeferred;
B
Bruce Momjian 已提交
1933
				const char *p;
1934 1935
				int			findx;

1936
				if (strcmp(PQgetvalue(res2, i2, i_tgisconstraint), "f") == 0)
1937
					tgisconstraint = 0;
1938
				else
1939
					tgisconstraint = 1;
1940 1941

				if (strcmp(PQgetvalue(res2, i2, i_tgdeferrable), "f") == 0)
1942
					tgdeferrable = 0;
1943
				else
1944
					tgdeferrable = 1;
1945 1946

				if (strcmp(PQgetvalue(res2, i2, i_tginitdeferred), "f") == 0)
1947
					tginitdeferred = 0;
1948
				else
1949
					tginitdeferred = 1;
1950

V
Vadim B. Mikheev 已提交
1951 1952
				for (findx = 0; findx < numFuncs; findx++)
				{
1953
					if (strcmp(finfo[findx].oid, tgfuncoid) == 0 &&
1954
						finfo[findx].nargs == 0 &&
V
Vadim B. Mikheev 已提交
1955 1956 1957
						strcmp(finfo[findx].prorettype, "0") == 0)
						break;
				}
1958

V
Vadim B. Mikheev 已提交
1959 1960
				if (findx == numFuncs)
				{
1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981
					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);
					}
1982
					tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
1983
					PQclear(r);
1984
				}
1985
				else
1986
					tgfunc = strdup(finfo[findx].proname);
B
Bruce Momjian 已提交
1987 1988

				appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
1989
									fmtId(PQgetvalue(res2, i2, i_tgname),
B
Bruce Momjian 已提交
1990 1991 1992
									force_quotes));
				appendPQExpBuffer(delqry, "ON %s;\n",
									fmtId(tblinfo[i].relname, force_quotes));
1993

B
Hi, all  
Bruce Momjian 已提交
1994
				resetPQExpBuffer(query);
1995 1996 1997 1998 1999
				if (tgisconstraint)
				{
					appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgconstrname), force_quotes));
				}
2000 2001
				else
				{
2002 2003 2004
					appendPQExpBuffer(query, "CREATE TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
				}
B
Bruce Momjian 已提交
2005
				appendPQExpBufferChar(query, ' ');
V
Vadim B. Mikheev 已提交
2006 2007 2008
				/* Trigger type */
				findx = 0;
				if (TRIGGER_FOR_BEFORE(tgtype))
B
Hi, all  
Bruce Momjian 已提交
2009
					appendPQExpBuffer(query, "BEFORE");
V
Vadim B. Mikheev 已提交
2010
				else
B
Hi, all  
Bruce Momjian 已提交
2011
					appendPQExpBuffer(query, "AFTER");
V
Vadim B. Mikheev 已提交
2012 2013
				if (TRIGGER_FOR_INSERT(tgtype))
				{
B
Hi, all  
Bruce Momjian 已提交
2014
					appendPQExpBuffer(query, " INSERT");
V
Vadim B. Mikheev 已提交
2015 2016 2017 2018 2019
					findx++;
				}
				if (TRIGGER_FOR_DELETE(tgtype))
				{
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2020
						appendPQExpBuffer(query, " OR DELETE");
V
Vadim B. Mikheev 已提交
2021
					else
B
Hi, all  
Bruce Momjian 已提交
2022
						appendPQExpBuffer(query, " DELETE");
V
Vadim B. Mikheev 已提交
2023 2024 2025
					findx++;
				}
				if (TRIGGER_FOR_UPDATE(tgtype))
2026
				{
V
Vadim B. Mikheev 已提交
2027
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2028
						appendPQExpBuffer(query, " OR UPDATE");
V
Vadim B. Mikheev 已提交
2029
					else
B
Hi, all  
Bruce Momjian 已提交
2030
						appendPQExpBuffer(query, " UPDATE");
2031
				}
2032 2033
				appendPQExpBuffer(query, " ON %s ", fmtId(tblinfo[i].relname, force_quotes));

2034
				if (tgisconstraint)
2035
				{
2036
					if (!tgdeferrable)
2037 2038 2039 2040
						appendPQExpBuffer(query, " NOT");
					appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
					if (tginitdeferred)
						appendPQExpBuffer(query, "DEFERRED");
2041
					else
2042
						appendPQExpBuffer(query, "IMMEDIATE");
2043

2044 2045 2046
				}

				appendPQExpBuffer(query, " FOR EACH ROW");
2047 2048
				appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
								  fmtId(tgfunc, force_quotes));
V
Vadim B. Mikheev 已提交
2049 2050
				for (findx = 0; findx < tgnargs; findx++)
				{
2051
					const char *s;
2052 2053

					for (p = tgargs;;)
V
Vadim B. Mikheev 已提交
2054
					{
2055
						p = strchr(p, '\\');
V
Vadim B. Mikheev 已提交
2056 2057
						if (p == NULL)
						{
B
Bruce Momjian 已提交
2058 2059
							fprintf(stderr, "getTables(): relation '%s': bad argument "
									"string (%s) for trigger '%s'\n",
2060 2061 2062
									tblinfo[i].relname,
									PQgetvalue(res2, i2, i_tgargs),
									PQgetvalue(res2, i2, i_tgname));
V
Vadim B. Mikheev 已提交
2063 2064 2065 2066 2067 2068 2069 2070
							exit_nicely(g_conn);
						}
						p++;
						if (*p == '\\')
						{
							p++;
							continue;
						}
2071
						if (p[0] == '0' && p[1] == '0' && p[2] == '0')
V
Vadim B. Mikheev 已提交
2072 2073 2074
							break;
					}
					p--;
2075
					appendPQExpBufferChar(query, '\'');
B
Bruce Momjian 已提交
2076
					for (s = tgargs; s < p;)
V
Vadim B. Mikheev 已提交
2077 2078
					{
						if (*s == '\'')
2079 2080
							appendPQExpBufferChar(query, '\\');
						appendPQExpBufferChar(query, *s++);
V
Vadim B. Mikheev 已提交
2081
					}
B
Bruce Momjian 已提交
2082 2083
					appendPQExpBufferChar(query, '\'');
					appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
V
Vadim B. Mikheev 已提交
2084 2085
					tgargs = p + 4;
				}
B
Hi, all  
Bruce Momjian 已提交
2086
				appendPQExpBuffer(query, ");\n");
2087

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

				/*** Initialize trcomments and troids ***/
2091

B
Bruce,  
Bruce Momjian 已提交
2092
				resetPQExpBuffer(query);
2093 2094
				appendPQExpBuffer(query, "TRIGGER %s ",
					fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
B
Bruce,  
Bruce Momjian 已提交
2095
				appendPQExpBuffer(query, "ON %s",
2096
								fmtId(tblinfo[i].relname, force_quotes));
B
Bruce Momjian 已提交
2097 2098 2099 2100
				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 已提交
2101

2102 2103
				if (tgfunc)
					free(tgfunc);
V
Vadim B. Mikheev 已提交
2104 2105 2106 2107
			}
			PQclear(res2);
		}
		else
B
Bruce,  
Bruce Momjian 已提交
2108
		{
V
Vadim B. Mikheev 已提交
2109
			tblinfo[i].triggers = NULL;
B
Bruce,  
Bruce Momjian 已提交
2110
		}
2111

2112 2113 2114 2115 2116
	}

	PQclear(res);

	return tblinfo;
2117 2118 2119 2120 2121

}

/*
 * getInherits
2122
 *	  read all the inheritance information
2123 2124
 * from the system catalogs return them in the InhInfo* structure
 *
2125 2126
 * numInherits is set to the number of tables read in
 *
2127 2128
 *
 */
2129
InhInfo    *
2130 2131
getInherits(int *numInherits)
{
2132
	PGresult   *res;
2133 2134
	int			ntups;
	int			i;
2135 2136
	PQExpBuffer query = createPQExpBuffer();
	InhInfo    *inhinfo;
2137

2138
	int			i_inhrelid;
2139
	int			i_inhparent;
2140 2141 2142

	/* find all the inheritance information */

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

B
Hi, all  
Bruce Momjian 已提交
2145
	res = PQexec(g_conn, query->data);
2146 2147 2148
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2149 2150
		fprintf(stderr, "getInherits(): SELECT failed.  Explanation from backend: '%s'.\n", 
				PQerrorMessage(g_conn));
2151 2152 2153 2154 2155 2156 2157 2158 2159
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numInherits = ntups;

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

2160
	i_inhrelid = PQfnumber(res, "inhrelid");
2161 2162 2163 2164
	i_inhparent = PQfnumber(res, "inhparent");

	for (i = 0; i < ntups; i++)
	{
2165
		inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
2166 2167 2168 2169 2170
		inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
	}

	PQclear(res);
	return inhinfo;
2171 2172 2173 2174
}

/*
 * getTableAttrs -
2175 2176
 *	  for each table in tblinfo, read its attributes types and names
 *
2177
 * this is implemented in a very inefficient way right now, looping
2178
 * through the tblinfo and doing a join per table to find the attrs and their
2179 2180
 * types
 *
2181
 *	modifies tblinfo
2182 2183
 */
void
2184
getTableAttrs(TableInfo *tblinfo, int numTables)
2185
{
2186 2187
	int			i,
				j;
2188
	PQExpBuffer q = createPQExpBuffer();
2189 2190
	int			i_attname;
	int			i_typname;
2191
	int			i_atttypmod;
2192
	int			i_attnotnull;
V
Vadim B. Mikheev 已提交
2193
	int			i_atthasdef;
2194 2195
	int			i_attoid;
	PGresult   *res;
2196
	int			ntups;
2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211

	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)
2212
			fprintf(stderr, "%s finding the attrs and types for table: '%s' %s\n",
2213 2214 2215 2216
					g_comment_start,
					tblinfo[i].relname,
					g_comment_end);

B
Hi, all  
Bruce Momjian 已提交
2217
		resetPQExpBuffer(q);
B
Bruce,  
Bruce Momjian 已提交
2218
		appendPQExpBuffer(q, "SELECT a.oid as attoid, a.attnum, a.attname, t.typname, a.atttypmod, "
2219 2220 2221 2222 2223
						  "a.attnotnull, a.atthasdef "
						  "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 已提交
2224
		res = PQexec(g_conn, q->data);
2225 2226 2227
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
B
Bruce Momjian 已提交
2228 2229
			fprintf(stderr, "getTableAttrs(): SELECT failed.  "
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2230 2231 2232 2233 2234
			exit_nicely(g_conn);
		}

		ntups = PQntuples(res);

B
Bruce,  
Bruce Momjian 已提交
2235
		i_attoid = PQfnumber(res, "attoid");
2236 2237
		i_attname = PQfnumber(res, "attname");
		i_typname = PQfnumber(res, "typname");
2238
		i_atttypmod = PQfnumber(res, "atttypmod");
2239
		i_attnotnull = PQfnumber(res, "attnotnull");
V
Vadim B. Mikheev 已提交
2240
		i_atthasdef = PQfnumber(res, "atthasdef");
2241 2242

		tblinfo[i].numatts = ntups;
B
Bruce,  
Bruce Momjian 已提交
2243
		tblinfo[i].attoids = (char **) malloc(ntups * sizeof(char *));
2244 2245
		tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
		tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
2246
		tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
2247 2248
		tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
		tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
V
Vadim B. Mikheev 已提交
2249
		tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
2250 2251 2252 2253
		tblinfo[i].parentRels = NULL;
		tblinfo[i].numParents = 0;
		for (j = 0; j < ntups; j++)
		{
B
Bruce,  
Bruce Momjian 已提交
2254
			tblinfo[i].attoids[j] = strdup(PQgetvalue(res, j, i_attoid));
2255 2256
			tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
			tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
2257
			tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
2258 2259 2260
			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 已提交
2261 2262 2263
			if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
			{
				PGresult   *res2;
2264

V
Vadim B. Mikheev 已提交
2265
				if (g_verbose)
2266
					fprintf(stderr, "%s finding DEFAULT expression for attr: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2267 2268 2269
							g_comment_start,
							tblinfo[i].attnames[j],
							g_comment_end);
2270

B
Hi, all  
Bruce Momjian 已提交
2271 2272
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
2273 2274
							 "where adrelid = '%s'::oid and adnum = %d ",
								  tblinfo[i].oid, j + 1);
B
Hi, all  
Bruce Momjian 已提交
2275
				res2 = PQexec(g_conn, q->data);
V
Vadim B. Mikheev 已提交
2276
				if (!res2 ||
2277
					PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2278
				{
B
Bruce Momjian 已提交
2279 2280
					fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2281 2282 2283 2284 2285 2286 2287
					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;
2288 2289 2290
		}
		PQclear(res);
	}
2291 2292 2293 2294 2295
}


/*
 * getIndices
2296
 *	  read all the user-defined indices information
2297 2298
 * from the system catalogs return them in the InhInfo* structure
 *
2299 2300
 * numIndices is set to the number of indices read in
 *
2301 2302
 *
 */
2303
IndInfo    *
2304 2305
getIndices(int *numIndices)
{
2306
	int			i;
2307
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2308
	PGresult   *res;
2309
	int			ntups;
B
Bruce Momjian 已提交
2310
	IndInfo    *indinfo;
2311 2312 2313 2314 2315 2316 2317 2318

	int			i_indexrelname;
	int			i_indrelname;
	int			i_indamname;
	int			i_indproc;
	int			i_indkey;
	int			i_indclass;
	int			i_indisunique;
2319
	int			i_indoid;
2320 2321 2322 2323 2324

	/*
	 * find all the user-defined indices. We do not handle partial
	 * indices.
	 *
2325
	 * Notice we skip indices on inversion objects (relkind 'l')
2326 2327 2328 2329
	 *
	 * this is a 4-way join !!
	 */

B
Hi, all  
Bruce Momjian 已提交
2330
	appendPQExpBuffer(query,
2331 2332 2333 2334 2335 2336 2337 2338
					  "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 "
					  "and t2.relname !~ '^pg_' and t2.relkind != 'l' and not i.indisprimary",
					  g_last_builtin_oid);
2339

B
Hi, all  
Bruce Momjian 已提交
2340
	res = PQexec(g_conn, query->data);
2341 2342 2343
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2344 2345
		fprintf(stderr, "getIndices(): SELECT failed.  "
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2346 2347 2348 2349 2350 2351 2352 2353 2354
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numIndices = ntups;

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

2355 2356
	memset((char *) indinfo, 0, ntups * sizeof(IndInfo));

B
Bruce,  
Bruce Momjian 已提交
2357
	i_indoid = PQfnumber(res, "indoid");
2358 2359 2360 2361 2362 2363 2364 2365 2366 2367
	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 已提交
2368
		indinfo[i].indoid = strdup(PQgetvalue(res, i, i_indoid));
2369 2370 2371 2372
		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));
2373 2374 2375 2376 2377 2378
		parseNumericArray(PQgetvalue(res, i, i_indkey),
						  indinfo[i].indkey,
						  INDEX_MAX_KEYS);
		parseNumericArray(PQgetvalue(res, i, i_indclass),
						  indinfo[i].indclass,
						  INDEX_MAX_KEYS);
2379 2380 2381 2382
		indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
	}
	PQclear(res);
	return indinfo;
2383 2384
}

B
Bruce,  
Bruce Momjian 已提交
2385
/*------------------------------------------------------------------
2386
 * dumpComments --
B
Bruce,  
Bruce Momjian 已提交
2387
 *
2388
 * This routine is used to dump any comments associated with the
B
Bruce,  
Bruce Momjian 已提交
2389 2390 2391 2392
 * 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
2393
 * addition, the routine takes the stdio FILE handle to which the
B
Bruce,  
Bruce Momjian 已提交
2394 2395 2396 2397
 * output should be written.
 *------------------------------------------------------------------
*/

T
Tom Lane 已提交
2398
static void
B
Bruce Momjian 已提交
2399
dumpComment(Archive *fout, const char *target, const char *oid)
2400
{
B
Bruce,  
Bruce Momjian 已提交
2401

2402
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
2403
	PQExpBuffer query;
2404
	int			i_description;
B
Bruce,  
Bruce Momjian 已提交
2405 2406 2407 2408 2409 2410 2411 2412 2413 2414

	/*** 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);
2415 2416
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce,  
Bruce Momjian 已提交
2417 2418 2419 2420 2421 2422 2423
		fprintf(stderr, "DumpComment: SELECT failed: '%s'.\n",
				PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

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

2424 2425
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2426
		i_description = PQfnumber(res, "description");
B
Bruce Momjian 已提交
2427 2428 2429 2430 2431
		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*/,
2432
					   "" /* Copy */, "" /*Owner*/, NULL, NULL);	
B
Bruce Momjian 已提交
2433

B
Bruce,  
Bruce Momjian 已提交
2434 2435 2436 2437 2438
	}

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

	PQclear(res);
2439

B
Bruce,  
Bruce Momjian 已提交
2440 2441 2442
}

/*------------------------------------------------------------------
2443
 * dumpDBComment --
B
Bruce,  
Bruce Momjian 已提交
2444
 *
2445 2446
 * 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 已提交
2447 2448 2449 2450 2451
 * to dump the schema of the database, then this is the first
 * statement issued.
 *------------------------------------------------------------------
*/

2452
void
B
Bruce Momjian 已提交
2453
dumpDBComment(Archive *fout)
2454
{
B
Bruce,  
Bruce Momjian 已提交
2455

2456
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
2457
	PQExpBuffer query;
2458
	int			i_oid;
B
Bruce,  
Bruce Momjian 已提交
2459 2460 2461 2462 2463 2464 2465 2466 2467 2468

	/*** 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);
2469 2470
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce,  
Bruce Momjian 已提交
2471 2472 2473 2474 2475 2476 2477
		fprintf(stderr, "dumpDBComment: SELECT failed: '%s'.\n",
				PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

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

2478 2479
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2480 2481 2482 2483 2484 2485 2486 2487 2488
		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);
2489

B
Bruce,  
Bruce Momjian 已提交
2490 2491
}

2492 2493
/*
 * dumpTypes
2494
 *	  writes out to fout the queries to recreate all the user-defined types
2495 2496 2497
 *
 */
void
B
Bruce Momjian 已提交
2498
dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
2499
		  TypeInfo *tinfo, int numTypes)
2500
{
2501
	int			i;
2502
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
2503
	PQExpBuffer	delq = createPQExpBuffer();
2504
	int			funcInd;
2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533

	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 已提交
2534
		appendPQExpBuffer(delq, "DROP TYPE %s;\n", fmtId(tinfo[i].typname, force_quotes));
2535

B
Hi, all  
Bruce Momjian 已提交
2536 2537
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548
						  "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);
2549 2550 2551

		if (tinfo[i].isArray)
		{
2552
			char	   *elemType;
2553 2554 2555

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

B
Hi, all  
Bruce Momjian 已提交
2556
			appendPQExpBuffer(q, ", element = %s, delimiter = '%s'",
2557
							  elemType, tinfo[i].typdelim);
2558 2559
		}
		if (tinfo[i].passedbyvalue)
B
Hi, all  
Bruce Momjian 已提交
2560
			appendPQExpBuffer(q, ",passedbyvalue);\n");
2561
		else
B
Hi, all  
Bruce Momjian 已提交
2562
			appendPQExpBuffer(q, ");\n");
2563

B
Bruce Momjian 已提交
2564
		ArchiveEntry(fout, tinfo[i].oid, fmtId(tinfo[i].typname, force_quotes), "TYPE", NULL,
2565
						q->data, delq->data, "", tinfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
2566 2567 2568 2569

		/*** Dump Type Comments ***/

		resetPQExpBuffer(q);
B
Bruce Momjian 已提交
2570 2571
		resetPQExpBuffer(delq);

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

B
Bruce Momjian 已提交
2575
		resetPQExpBuffer(q);
2576
	}
2577 2578
}

2579 2580
/*
 * dumpProcLangs
B
Bruce Momjian 已提交
2581
 *		  writes out to fout the queries to recreate user-defined procedural languages
2582 2583 2584
 *
 */
void
B
Bruce Momjian 已提交
2585
dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
B
Bruce Momjian 已提交
2586
			  TypeInfo *tinfo, int numTypes)
2587
{
2588 2589
	PGresult   *res;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2590 2591
	PQExpBuffer defqry = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
2592
	int			ntups;
B
Bruce Momjian 已提交
2593
	int			i_oid;
2594 2595 2596 2597
	int			i_lanname;
	int			i_lanpltrusted;
	int			i_lanplcallfoid;
	int			i_lancompiler;
2598 2599 2600
	char	   *lanname;
	char	   *lancompiler;
	const char *lanplcallfoid;
2601 2602 2603
	int			i,
				fidx;

B
Bruce Momjian 已提交
2604
	appendPQExpBuffer(query, "SELECT oid, * FROM pg_language "
2605 2606
					  "WHERE lanispl "
					  "ORDER BY oid");
B
Hi, all  
Bruce Momjian 已提交
2607
	res = PQexec(g_conn, query->data);
2608 2609 2610
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2611
		fprintf(stderr, "dumpProcLangs(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2612 2613 2614 2615
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);

B
Bruce Momjian 已提交
2616 2617 2618 2619
	i_lanname = PQfnumber(res, "lanname");
	i_lanpltrusted = PQfnumber(res, "lanpltrusted");
	i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
	i_lancompiler = PQfnumber(res, "lancompiler");
B
Bruce Momjian 已提交
2620
	i_oid = PQfnumber(res, "oid");
2621

B
Bruce Momjian 已提交
2622 2623
	for (i = 0; i < ntups; i++)
	{
2624 2625 2626 2627 2628 2629 2630 2631
		lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
		for (fidx = 0; fidx < numFuncs; fidx++)
		{
			if (!strcmp(finfo[fidx].oid, lanplcallfoid))
				break;
		}
		if (fidx >= numFuncs)
		{
B
Bruce Momjian 已提交
2632 2633
			fprintf(stderr, "dumpProcLangs(): handler procedure for "
						"language %s not found\n", PQgetvalue(res, i, i_lanname));
2634 2635 2636 2637 2638 2639 2640 2641
			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 已提交
2642
		appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE '%s';\n", lanname);
2643

B
Bruce Momjian 已提交
2644
		appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE '%s' "
B
Bruce Momjian 已提交
2645
				"HANDLER %s LANCOMPILER '%s';\n",
B
Bruce Momjian 已提交
2646
				(PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ? "TRUSTED " : "",
B
Bruce Momjian 已提交
2647 2648 2649
				lanname,
				fmtId(finfo[fidx].proname, force_quotes),
				lancompiler);
2650

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

2654 2655 2656 2657 2658 2659 2660 2661
		free(lanname);
		free(lancompiler);
	}

	PQclear(res);

}

2662 2663
/*
 * dumpFuncs
2664
 *	  writes out to fout the queries to recreate all the user-defined functions
2665 2666 2667
 *
 */
void
B
Bruce Momjian 已提交
2668
dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs,
2669
		  TypeInfo *tinfo, int numTypes)
2670
{
2671
	int			i;
2672 2673 2674

	for (i = 0; i < numFuncs; i++)
		dumpOneFunc(fout, finfo, i, tinfo, numTypes);
2675 2676 2677 2678
}

/*
 * dumpOneFunc:
2679 2680
 *	  dump out only one function,  the index of which is given in the third
 *	argument
2681 2682 2683
 *
 */

2684
static void
B
Bruce Momjian 已提交
2685
dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
2686
			TypeInfo *tinfo, int numTypes)
2687
{
2688
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
2689 2690
	PQExpBuffer fn = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
B
Bruce,  
Bruce Momjian 已提交
2691
	PQExpBuffer fnlist = createPQExpBuffer();
B
Bruce Momjian 已提交
2692
	int			j;
2693
	PQExpBuffer asPart = createPQExpBuffer();
2694
	char		func_lang[NAMEDATALEN + 1];
2695 2696 2697 2698
	PGresult   *res;
	int			nlangs;
	int			i_lanname;
	char		query[256];
2699 2700 2701 2702 2703 2704

	if (finfo[i].dumped)
		return;
	else
		finfo[i].dumped = 1;

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

2707 2708 2709 2710 2711
	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 已提交
2712
  	{
2713 2714
		fprintf(stderr, "dumpOneFunc(): SELECT for procedural language failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
		exit_nicely(g_conn);
B
Bruce Momjian 已提交
2715
  	}
2716 2717 2718
	nlangs = PQntuples(res);

	if (nlangs != 1)
B
Bruce Momjian 已提交
2719
  	{
2720 2721
		fprintf(stderr, "dumpOneFunc(): procedural language for function %s not found\n", finfo[i].proname);
		exit_nicely(g_conn);
B
Bruce Momjian 已提交
2722 2723
  	}
  
2724
	i_lanname = PQfnumber(res, "lanname");
2725

2726
	/*
2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742
	 * 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);
	}

2743
	strcpy(func_lang, PQgetvalue(res, 0, i_lanname));
B
Bruce Momjian 已提交
2744
  
2745
	PQclear(res);
B
Bruce Momjian 已提交
2746 2747 2748
 
	resetPQExpBuffer(fn);
	appendPQExpBuffer(fn, "%s (", fmtId(finfo[i].proname, force_quotes));
2749 2750
	for (j = 0; j < finfo[i].nargs; j++)
	{
B
Bruce Momjian 已提交
2751
		char			*typname;
2752 2753

		typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]);
B
Bruce Momjian 已提交
2754 2755 2756
		appendPQExpBuffer(fn, "%s%s",
							(j > 0) ? "," : "",
							fmtId(typname, false));
B
Bruce,  
Bruce Momjian 已提交
2757
		appendPQExpBuffer(fnlist, "%s%s",
B
Bruce Momjian 已提交
2758 2759
							(j > 0) ? "," : "",
							fmtId(typname, false));
2760
	}
B
Bruce Momjian 已提交
2761 2762 2763 2764 2765 2766 2767
	appendPQExpBuffer(fn, ")");

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

	resetPQExpBuffer(q);
	appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data );
2768
	appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE '%s';\n",
2769
					  (finfo[i].retset) ? " SETOF " : "",
B
Bruce Momjian 已提交
2770
					  fmtId(findTypeByOid(tinfo, numTypes, finfo[i].prorettype), false),
2771
					  asPart->data, func_lang);
2772

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

B
Bruce,  
Bruce Momjian 已提交
2776 2777 2778 2779 2780 2781 2782 2783
	/*** 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);

2784 2785 2786 2787
}

/*
 * dumpOprs
2788
 *	  writes out to fout the queries to recreate all the user-defined operators
2789 2790
 *
 */
2791
void
B
Bruce Momjian 已提交
2792
dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
2793
		 TypeInfo *tinfo, int numTypes)
2794
{
B
Bruce Momjian 已提交
2795
	int			i;
2796
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
2797
	PQExpBuffer delq = createPQExpBuffer();
2798 2799 2800 2801 2802 2803 2804 2805
	PQExpBuffer leftarg = createPQExpBuffer();
	PQExpBuffer rightarg = createPQExpBuffer();
	PQExpBuffer commutator = createPQExpBuffer();
	PQExpBuffer negator = createPQExpBuffer();
	PQExpBuffer restrictor = createPQExpBuffer();
	PQExpBuffer join = createPQExpBuffer();
	PQExpBuffer sort1 = createPQExpBuffer();
	PQExpBuffer sort2 = createPQExpBuffer();
2806 2807 2808 2809

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

B
Hi, all  
Bruce Momjian 已提交
2810 2811 2812 2813 2814 2815 2816 2817 2818
		resetPQExpBuffer(leftarg);
		resetPQExpBuffer(rightarg);
		resetPQExpBuffer(commutator);
		resetPQExpBuffer(negator);
		resetPQExpBuffer(restrictor);
		resetPQExpBuffer(join);
		resetPQExpBuffer(sort1);
		resetPQExpBuffer(sort2);

2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836
		/* 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 已提交
2837
			appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ",
2838
							  fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft), false));
2839 2840 2841 2842
		}
		if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
			strcmp(oprinfo[i].oprkind, "b") == 0)
		{
B
Hi, all  
Bruce Momjian 已提交
2843
			appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ",
2844
							  fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprright), false));
2845
		}
B
Hi, all  
Bruce Momjian 已提交
2846 2847
		if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
			appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ",
2848 2849
				 findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom));

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

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

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

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

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

B
Bruce Momjian 已提交
2868 2869
		resetPQExpBuffer(delq);
		appendPQExpBuffer(delq, "DROP OPERATOR %s (%s", oprinfo[i].oprname,
2870 2871
				fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft),
					  false));
B
Bruce Momjian 已提交
2872 2873
		appendPQExpBuffer(delq, ", %s);\n",
				fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprright),
2874
					 false));
2875

B
Hi, all  
Bruce Momjian 已提交
2876 2877
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
2878 2879 2880 2881 2882 2883 2884 2885 2886
						  "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 已提交
2887
						(strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
2888 2889 2890
						  join->data,
						  sort1->data,
						  sort2->data);
2891

B
Bruce Momjian 已提交
2892
		ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
2893
						q->data, delq->data, "", oprinfo[i].usename, NULL, NULL);
2894
	}
2895 2896 2897 2898
}

/*
 * dumpAggs
2899
 *	  writes out to fout the queries to create all the user-defined aggregates
2900 2901 2902
 *
 */
void
B
Bruce Momjian 已提交
2903
dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
2904
		 TypeInfo *tinfo, int numTypes)
2905
{
B
Bruce Momjian 已提交
2906
	int			i;
2907
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
2908 2909
	PQExpBuffer delq = createPQExpBuffer();
	PQExpBuffer aggSig = createPQExpBuffer();
2910
	PQExpBuffer details = createPQExpBuffer();
2911 2912 2913

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

2916 2917 2918
		/* skip all the builtin oids */
		if (atoi(agginfo[i].oid) < g_last_builtin_oid)
			continue;
2919

2920
		appendPQExpBuffer(details,
2921 2922
						  "BASETYPE = %s, ",
						  fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
2923

2924 2925 2926 2927
		appendPQExpBuffer(details,
						  "SFUNC = %s, STYPE = %s",
						  agginfo[i].aggtransfn,
						  fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype), false));
2928

2929 2930 2931
		if (agginfo[i].agginitval)
			appendPQExpBuffer(details, ", INITCOND = '%s'",
							  agginfo[i].agginitval);
2932

B
Hi, all  
Bruce Momjian 已提交
2933
		if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
2934 2935
			appendPQExpBuffer(details, ", FINALFUNC = %s",
							  agginfo[i].aggfinalfn);
2936

B
Bruce Momjian 已提交
2937 2938 2939
		resetPQExpBuffer(aggSig);
		appendPQExpBuffer(aggSig, "%s %s", agginfo[i].aggname,
							fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
2940

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

B
Hi, all  
Bruce Momjian 已提交
2944
		resetPQExpBuffer(q);
2945
		appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
2946
						  agginfo[i].aggname,
2947
						  details->data);
2948

B
Bruce Momjian 已提交
2949
		ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
2950
						q->data, delq->data, "", agginfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
2951 2952 2953 2954

		/*** Dump Aggregate Comments ***/

		resetPQExpBuffer(q);
2955
		appendPQExpBuffer(q, "AGGREGATE %s %s", agginfo[i].aggname,
B
Bruce,  
Bruce Momjian 已提交
2956 2957 2958
						  fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
		dumpComment(fout, q->data, agginfo[i].oid);

2959
	}
2960 2961
}

2962 2963 2964 2965 2966
/*
 * These are some support functions to fix the acl problem of pg_dump
 *
 * Matthew C. Aycock 12/02/97
 */
2967 2968 2969

/* Append a keyword to a keyword list, inserting comma if needed.
 * Caller must make aclbuf big enough for all possible keywords.
2970
 */
2971
static void
B
Bruce Momjian 已提交
2972
AddAcl(char *aclbuf, const char *keyword)
2973
{
2974 2975 2976
	if (*aclbuf)
		strcat(aclbuf, ",");
	strcat(aclbuf, keyword);
2977
}
2978

2979
/*
2980
 * This will take a string of 'arwR' and return a malloced,
2981 2982
 * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
 */
V
Vadim B. Mikheev 已提交
2983
static char *
2984
GetPrivileges(const char *s)
2985
{
2986
	char		aclbuf[100];
2987

2988
	aclbuf[0] = '\0';
2989

B
Bruce Momjian 已提交
2990
	if (strchr(s, 'a'))
2991
		AddAcl(aclbuf, "INSERT");
2992

B
Bruce Momjian 已提交
2993
	if (strchr(s, 'w'))
2994
		AddAcl(aclbuf, "UPDATE,DELETE");
B
Bruce Momjian 已提交
2995 2996

	if (strchr(s, 'r'))
2997
		AddAcl(aclbuf, "SELECT");
2998

2999
	if (strchr(s, 'R'))
3000
		AddAcl(aclbuf, "RULE");
3001

3002 3003 3004
	/* Special-case when they're all there */
	if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
		return strdup("ALL");
3005

3006
	return strdup(aclbuf);
3007
}
3008

B
Bruce Momjian 已提交
3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024
/*
 * 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 已提交
3025 3026
/*
 * dumpACL:
3027 3028
 *	  Write out grant/revoke information
 *	  Called for sequences and tables
B
Bruce Momjian 已提交
3029 3030
 */

3031
static void
B
Bruce Momjian 已提交
3032
dumpACL(Archive *fout, TableInfo tbinfo)
B
Bruce Momjian 已提交
3033
{
B
Bruce Momjian 已提交
3034 3035
	const char 	*acls = tbinfo.relacl;
	char	   	*aclbuf,
B
Bruce Momjian 已提交
3036 3037 3038
			   *tok,
			   *eqpos,
			   *priv;
B
Bruce Momjian 已提交
3039 3040 3041
	char		*sql;
	char		tmp[1024];
	int		sSize = 4096;
3042 3043 3044 3045

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

B
Bruce Momjian 已提交
3046 3047 3048 3049 3050
	/*
	 * Allocate a larginsh buffer for the output SQL.
	 */
	sql = (char*)malloc(sSize);

B
Bruce Momjian 已提交
3051 3052 3053
	/*
	 * Revoke Default permissions for PUBLIC. Is this actually necessary,
	 * or is it just a waste of time?
3054
	 */
B
Bruce Momjian 已提交
3055
	sprintf(sql,	"REVOKE ALL on %s from PUBLIC;\n",
3056
			fmtId(tbinfo.relname, force_quotes));
3057 3058 3059

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

3061 3062
	/* Scan comma-separated ACL items */
	for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
3063
	{
3064

B
Bruce Momjian 已提交
3065 3066 3067
		/*
		 * Token may start with '{' and/or '"'.  Actually only the start
		 * of the string should have '{', but we don't verify that.
3068 3069 3070 3071 3072 3073 3074 3075
		 */
		if (*tok == '{')
			tok++;
		if (*tok == '"')
			tok++;

		/* User name is string up to = in tok */
		eqpos = strchr(tok, '=');
B
Bruce Momjian 已提交
3076
		if (!eqpos)
B
Bruce Momjian 已提交
3077
		{
3078
			fprintf(stderr, "Could not parse ACL list for '%s'...Exiting!\n",
B
Bruce Momjian 已提交
3079 3080 3081 3082
					tbinfo.relname);
			exit_nicely(g_conn);
		}

B
Bruce Momjian 已提交
3083 3084 3085 3086
		/*
		 * Parse the privileges (right-hand side).	Skip if there are
		 * none.
		 */
3087 3088
		priv = GetPrivileges(eqpos + 1);
		if (*priv)
3089
		{
B
Bruce Momjian 已提交
3090
			sprintf(tmp,	"GRANT %s on %s to ",
3091
					priv, fmtId(tbinfo.relname, force_quotes));
B
Bruce Momjian 已提交
3092
			strcatalloc(&sql, &sSize, tmp);
B
Bruce Momjian 已提交
3093 3094 3095

			/*
			 * Note: fmtId() can only be called once per printf, so don't
3096 3097 3098 3099 3100
			 * try to merge printing of username into the above printf.
			 */
			if (eqpos == tok)
			{
				/* Empty left-hand side means "PUBLIC" */
B
Bruce Momjian 已提交
3101
				strcatalloc(&sql, &sSize, "PUBLIC;\n");
3102
			}
3103
			else
3104 3105
			{
				*eqpos = '\0';	/* it's ok to clobber aclbuf */
3106
				if (strncmp(tok, "group ", strlen("group ")) == 0)
B
Bruce Momjian 已提交
3107
					sprintf(tmp, "GROUP %s;\n",
3108 3109
							fmtId(tok + strlen("group "), force_quotes));
				else
B
Bruce Momjian 已提交
3110 3111
					sprintf(tmp, "%s;\n", fmtId(tok, force_quotes));
				strcatalloc(&sql, &sSize, tmp);
3112
			}
3113
		}
3114
		free(priv);
B
Bruce Momjian 已提交
3115
	}
3116 3117

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

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

B
Bruce Momjian 已提交
3121 3122
}

3123

3124 3125
/*
 * dumpTables:
3126
 *	  write out to fout all the user-define tables
3127
 */
3128

3129
void
B
Bruce Momjian 已提交
3130
dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
3131 3132
		   InhInfo *inhinfo, int numInherits,
		   TypeInfo *tinfo, int numTypes, const char *tablename,
B
Bruce Momjian 已提交
3133 3134
		   const bool aclsSkip, const bool oids,
		   const bool schemaOnly, const bool dataOnly)
3135
{
3136 3137
	int			i,
				j,
B
Bruce Momjian 已提交
3138
				k;
3139
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3140
	PQExpBuffer delq = createPQExpBuffer();
3141
	char	   *serialSeq = NULL;		/* implicit sequence name created
B
Bruce Momjian 已提交
3142 3143 3144 3145
										 * by SERIAL datatype */
	const char *serialSeqSuffix = "_id_seq";	/* suffix for implicit
												 * SERIAL sequences */
	char	  **parentRels;		/* list of names of parent relations */
3146
	int			numParents;
B
Bruce Momjian 已提交
3147 3148
	int			actual_atts;	/* number of attrs in this CREATE statment */
	int32		tmp_typmod;
3149 3150 3151
	int			precision;
	int			scale;

V
Vadim B. Mikheev 已提交
3152
	/* First - dump SEQUENCEs */
B
Bruce Momjian 已提交
3153
	if (tablename)
B
Bruce Momjian 已提交
3154 3155 3156 3157 3158
	{
		serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
		strcpy(serialSeq, tablename);
		strcat(serialSeq, serialSeqSuffix);
	}
V
Vadim B. Mikheev 已提交
3159 3160 3161 3162
	for (i = 0; i < numTables; i++)
	{
		if (!(tblinfo[i].sequence))
			continue;
B
Bruce Momjian 已提交
3163
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
B
Bruce Momjian 已提交
3164
			|| (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
V
Vadim B. Mikheev 已提交
3165
		{
B
Bruce Momjian 已提交
3166
			/* becomeUser(fout, tblinfo[i].usename); */
V
Vadim B. Mikheev 已提交
3167
			dumpSequence(fout, tblinfo[i]);
3168
			if (!aclsSkip)
B
Bruce Momjian 已提交
3169
				dumpACL(fout, tblinfo[i]);
V
Vadim B. Mikheev 已提交
3170 3171
		}
	}
B
Bruce Momjian 已提交
3172
	if (tablename)
B
Bruce Momjian 已提交
3173
		free(serialSeq);
3174

3175 3176
	for (i = 0; i < numTables; i++)
	{
3177
		if (tblinfo[i].sequence)/* already dumped */
V
Vadim B. Mikheev 已提交
3178
			continue;
3179 3180 3181 3182

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

3183
			/* Skip VIEW relations */
3184 3185 3186
			
			/* if (isViewRule(tblinfo[i].relname)) continue; */
			
3187

3188 3189
			parentRels = tblinfo[i].parentRels;
			numParents = tblinfo[i].numParents;
3190

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

B
Hi, all  
Bruce Momjian 已提交
3194 3195
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "CREATE TABLE %s (\n\t", fmtId(tblinfo[i].relname, force_quotes));
3196 3197 3198 3199
			actual_atts = 0;
			for (j = 0; j < tblinfo[i].numatts; j++)
			{
				if (tblinfo[i].inhAttrs[j] == 0)
B
Hi all  
Bruce Momjian 已提交
3200
				{
3201
					if (actual_atts > 0)
B
Hi, all  
Bruce Momjian 已提交
3202 3203
						appendPQExpBuffer(q, ",\n\t");
					appendPQExpBuffer(q, "%s ",
3204
							fmtId(tblinfo[i].attnames[j], force_quotes));
3205 3206 3207

					/* Show lengths on bpchar and varchar */
					if (!strcmp(tblinfo[i].typnames[j], "bpchar"))
3208
					{
B
Bruce Momjian 已提交
3209 3210
						int			len = (tblinfo[i].atttypmod[j] - VARHDRSZ);

B
Hi, all  
Bruce Momjian 已提交
3211
						appendPQExpBuffer(q, "character");
3212
						if (len > 1)
B
Hi, all  
Bruce Momjian 已提交
3213
							appendPQExpBuffer(q, "(%d)",
3214
									 tblinfo[i].atttypmod[j] - VARHDRSZ);
3215
					}
3216 3217
					else if (!strcmp(tblinfo[i].typnames[j], "varchar"))
					{
B
Hi, all  
Bruce Momjian 已提交
3218
						appendPQExpBuffer(q, "character varying");
3219 3220
						if (tblinfo[i].atttypmod[j] != -1)
						{
B
Hi, all  
Bruce Momjian 已提交
3221
							appendPQExpBuffer(q, "(%d)",
3222
									 tblinfo[i].atttypmod[j] - VARHDRSZ);
3223
						}
3224
					}
3225 3226
					else if (!strcmp(tblinfo[i].typnames[j], "numeric"))
					{
B
Hi, all  
Bruce Momjian 已提交
3227
						appendPQExpBuffer(q, "numeric");
3228 3229 3230 3231
						if (tblinfo[i].atttypmod[j] != -1)
						{
							tmp_typmod = tblinfo[i].atttypmod[j] - VARHDRSZ;
							precision = (tmp_typmod >> 16) & 0xffff;
B
Bruce Momjian 已提交
3232
							scale = tmp_typmod & 0xffff;
B
Hi, all  
Bruce Momjian 已提交
3233
							appendPQExpBuffer(q, "(%d,%d)",
3234
											  precision, scale);
3235 3236
						}
					}
B
Bruce Momjian 已提交
3237 3238 3239 3240 3241

					/*
					 * char is an internal single-byte data type; Let's
					 * make sure we force it through with quotes. - thomas
					 * 1998-12-13
3242 3243 3244
					 */
					else if (!strcmp(tblinfo[i].typnames[j], "char"))
					{
B
Hi, all  
Bruce Momjian 已提交
3245
						appendPQExpBuffer(q, "%s",
3246
									fmtId(tblinfo[i].typnames[j], true));
3247
					}
3248 3249
					else
					{
B
Hi, all  
Bruce Momjian 已提交
3250
						appendPQExpBuffer(q, "%s",
3251
								   fmtId(tblinfo[i].typnames[j], false));
3252 3253
					}
					if (tblinfo[i].adef_expr[j] != NULL)
B
Hi, all  
Bruce Momjian 已提交
3254
						appendPQExpBuffer(q, " DEFAULT %s",
3255
										  tblinfo[i].adef_expr[j]);
3256
					if (tblinfo[i].notnull[j])
B
Hi, all  
Bruce Momjian 已提交
3257
						appendPQExpBuffer(q, " NOT NULL");
3258
					actual_atts++;
3259
				}
3260
			}
B
Hi all  
Bruce Momjian 已提交
3261

3262 3263 3264
			/* put the CONSTRAINTS inside the table def */
			for (k = 0; k < tblinfo[i].ncheck; k++)
			{
3265
				if (actual_atts + k > 0)
B
Hi, all  
Bruce Momjian 已提交
3266 3267
					appendPQExpBuffer(q, ",\n\t");
				appendPQExpBuffer(q, "%s",
3268
								  tblinfo[i].check_expr[k]);
3269
			}
3270

3271 3272 3273 3274 3275 3276 3277
			/* 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 已提交
3278

3279
			appendPQExpBuffer(q, "\n)");
3280 3281 3282

			if (numParents > 0)
			{
B
Hi, all  
Bruce Momjian 已提交
3283
				appendPQExpBuffer(q, "\ninherits (");
3284
				for (k = 0; k < numParents; k++)
B
Hi all  
Bruce Momjian 已提交
3285
				{
B
Hi, all  
Bruce Momjian 已提交
3286
					appendPQExpBuffer(q, "%s%s",
3287 3288
									  (k > 0) ? ", " : "",
									  fmtId(parentRels[k], force_quotes));
B
Hi all  
Bruce Momjian 已提交
3289
				}
B
Hi, all  
Bruce Momjian 已提交
3290
				appendPQExpBuffer(q, ")");
3291
			}
B
Hi all  
Bruce Momjian 已提交
3292

B
Hi, all  
Bruce Momjian 已提交
3293
			appendPQExpBuffer(q, ";\n");
B
Bruce Momjian 已提交
3294 3295 3296

			if (!dataOnly) {
				ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
3297
								"TABLE", NULL, q->data, delq->data, "", tblinfo[i].usename,
B
Bruce Momjian 已提交
3298 3299 3300 3301
								NULL, NULL);
			}

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

3304
			/* Dump Field Comments */
B
Bruce,  
Bruce Momjian 已提交
3305

3306 3307
			for (j = 0; j < tblinfo[i].numatts; j++)
			{
B
Bruce,  
Bruce Momjian 已提交
3308 3309 3310 3311 3312 3313
				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]);
			}
3314

B
Bruce,  
Bruce Momjian 已提交
3315
			/* Dump Table Comments */
3316

B
Bruce,  
Bruce Momjian 已提交
3317 3318 3319
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "TABLE %s", fmtId(tblinfo[i].relname, force_quotes));
			dumpComment(fout, q->data, tblinfo[i].oid);
3320

3321 3322
		}
	}
3323 3324 3325 3326
}

/*
 * dumpIndices:
3327
 *	  write out to fout all the user-define indices
3328
 */
3329
void
B
Bruce Momjian 已提交
3330
dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
3331
			TableInfo *tblinfo, int numTables, const char *tablename)
3332
{
3333 3334 3335
	int			i,
				k;
	int			tableInd;
3336
	PQExpBuffer attlist = createPQExpBuffer();
B
Bruce Momjian 已提交
3337 3338 3339
	char	   *classname[INDEX_MAX_KEYS];
	char	   *funcname;		/* the name of the function to comput the
								 * index key from */
3340 3341 3342
	int			indkey,
				indclass;
	int			nclass;
3343

3344
	PQExpBuffer q = createPQExpBuffer(),
B
Bruce Momjian 已提交
3345
				delq = createPQExpBuffer(),
B
Hi, all  
Bruce Momjian 已提交
3346 3347
				id1 = createPQExpBuffer(),
				id2 = createPQExpBuffer();
3348
	PGresult   *res;
3349 3350 3351 3352

	for (i = 0; i < numIndices; i++)
	{
		tableInd = findTableByName(tblinfo, numTables,
3353 3354 3355 3356 3357
								   indinfo[i].indrelname);
		if (tableInd < 0)
		{
			fprintf(stderr, "failed sanity check, table %s was not found\n",
					indinfo[i].indrelname);
3358
			exit(1);
3359
		}
3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371

		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 已提交
3372 3373
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
3374 3375 3376
							  "SELECT proname from pg_proc "
							  "where pg_proc.oid = '%s'::oid",
							  indinfo[i].indproc);
B
Hi, all  
Bruce Momjian 已提交
3377
			res = PQexec(g_conn, q->data);
3378 3379
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
3380 3381
				fprintf(stderr, "dumpIndices(): SELECT (funcname) failed.  "
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3382 3383
				exit_nicely(g_conn);
			}
B
Bruce Momjian 已提交
3384
			funcname = strdup(PQgetvalue(res, 0, PQfnumber(res, "proname")));
3385 3386 3387 3388 3389 3390 3391 3392 3393
			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 已提交
3394 3395
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
3396 3397 3398
							  "SELECT opcname from pg_opclass "
							  "where pg_opclass.oid = '%u'::oid",
							  indclass);
B
Hi, all  
Bruce Momjian 已提交
3399
			res = PQexec(g_conn, q->data);
3400 3401
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
3402 3403
				fprintf(stderr, "dumpIndices(): SELECT (classname) failed.  "
									"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3404 3405
				exit_nicely(g_conn);
			}
B
Bruce Momjian 已提交
3406
			classname[nclass] = strdup(PQgetvalue(res, 0, PQfnumber(res, "opcname")));
3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417
			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 已提交
3418 3419
		resetPQExpBuffer(attlist);
		for (k = 0; k < INDEX_MAX_KEYS; k++)
3420
		{
3421
			char	   *attname;
3422 3423

			indkey = atoi(indinfo[i].indkey[k]);
B
Bruce Momjian 已提交
3424
			if (indkey == InvalidAttrNumber)
3425 3426 3427 3428 3429 3430 3431
				break;
			indkey--;
			if (indkey == ObjectIdAttributeNumber - 1)
				attname = "oid";
			else
				attname = tblinfo[tableInd].attnames[indkey];
			if (funcname)
B
Hi, all  
Bruce Momjian 已提交
3432
				appendPQExpBuffer(attlist, "%s%s",
B
Bruce Momjian 已提交
3433
					 (k == 0) ? "" : ", ", fmtId(attname, force_quotes));
3434 3435 3436 3437 3438
			else
			{
				if (k >= nclass)
				{
					fprintf(stderr, "dumpIndices(): OpClass not found for "
3439
							"attribute '%s' of index '%s'\n",
3440 3441 3442
							attname, indinfo[i].indexrelname);
					exit_nicely(g_conn);
				}
B
Hi, all  
Bruce Momjian 已提交
3443 3444 3445 3446 3447
				resetPQExpBuffer(id1);
				resetPQExpBuffer(id2);
				appendPQExpBuffer(id1, fmtId(attname, force_quotes));
				appendPQExpBuffer(id2, fmtId(classname[k], force_quotes));
				appendPQExpBuffer(attlist, "%s%s %s",
3448
							 (k == 0) ? "" : ", ", id1->data, id2->data);
3449 3450 3451 3452 3453 3454
				free(classname[k]);
			}
		}

		if (!tablename || (!strcmp(indinfo[i].indrelname, tablename)))
		{
B
Bruce Momjian 已提交
3455 3456 3457 3458 3459

			/*
			 * 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.
3460
			 */
3461

B
Hi, all  
Bruce Momjian 已提交
3462 3463 3464 3465
			resetPQExpBuffer(id1);
			resetPQExpBuffer(id2);
			appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
			appendPQExpBuffer(id2, fmtId(indinfo[i].indrelname, force_quotes));
3466

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

B
Bruce Momjian 已提交
3470 3471 3472
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "CREATE %s INDEX %s on %s using %s (",
					(strcmp(indinfo[i].indisunique, "t") == 0) ? "UNIQUE" : "",
B
Hi, all  
Bruce Momjian 已提交
3473 3474
					id1->data,
					id2->data,
3475 3476 3477
					indinfo[i].indamname);
			if (funcname)
			{
3478
				/* need 2 printf's here cuz fmtId has static return area */
B
Bruce Momjian 已提交
3479 3480 3481
				appendPQExpBuffer(q, " %s", fmtId(funcname, false));
				appendPQExpBuffer(q, " (%s) %s );\n", attlist->data, 
									fmtId(classname[0], force_quotes));
3482 3483 3484 3485
				free(funcname);
				free(classname[0]);
			}
			else
B
Bruce Momjian 已提交
3486
				appendPQExpBuffer(q, " %s );\n", attlist->data);
B
Bruce,  
Bruce Momjian 已提交
3487 3488 3489

			/* Dump Index Comments */

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

B
Bruce,  
Bruce Momjian 已提交
3493 3494 3495
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "INDEX %s", id1->data);
			dumpComment(fout, q->data, indinfo[i].indoid);
3496

3497 3498
		}
	}
3499 3500

}
3501

3502
/*
B
Bruce Momjian 已提交
3503
 * dumpTuples
3504 3505 3506 3507 3508
 *	  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
3509
 *	  in PostgreSQL.
3510 3511 3512 3513
 *
 * the attrmap passed in tells how to map the attributes copied in to the
 * attributes copied out
 */
3514
#ifdef NOT_USED
3515
void
3516
dumpTuples(PGresult *res, FILE *fout, int *attrmap)
3517
{
3518 3519 3520 3521
	int			j,
				k;
	int			m,
				n;
B
Bruce Momjian 已提交
3522
	char	  **outVals = NULL; /* values to copy out */
3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541

	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++)
			{
3542
				char	   *pval = outVals[k];
3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562

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

3565
#endif
3566

3567 3568 3569 3570
/*
 * setMaxOid -
 * find the maximum oid and generate a COPY statement to set it
*/
3571

3572
static void
B
Bruce Momjian 已提交
3573
setMaxOid(Archive *fout)
3574
{
B
Bruce Momjian 已提交
3575 3576 3577 3578
	PGresult   	*res;
	Oid		max_oid;
	char		sql[1024];
	int		pos;
3579

B
Bruce Momjian 已提交
3580
	res = PQexec(g_conn, "CREATE TEMPORARY TABLE pg_dump_oid (dummy int4)");
3581 3582 3583
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
3584
		fprintf(stderr, "Can not create pg_dump_oid table.  "
B
Bruce Momjian 已提交
3585
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3586 3587 3588
		exit_nicely(g_conn);
	}
	PQclear(res);
3589
	res = PQexec(g_conn, "INSERT INTO pg_dump_oid VALUES (0)");
3590 3591 3592
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
3593
		fprintf(stderr, "Can not insert into pg_dump_oid table.  "
B
Bruce Momjian 已提交
3594
					"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3595 3596 3597 3598 3599 3600 3601 3602 3603
		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);
3604
	res = PQexec(g_conn, "DROP TABLE pg_dump_oid;");
3605 3606 3607
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
3608
		fprintf(stderr, "Can not drop pg_dump_oid table.  "
B
Bruce Momjian 已提交
3609
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3610 3611 3612 3613
		exit_nicely(g_conn);
	}
	PQclear(res);
	if (g_verbose)
3614
		fprintf(stderr, "%s maximum system oid is %u %s\n",
3615
				g_comment_start, max_oid, g_comment_end);
B
Bruce Momjian 已提交
3616
	pos = snprintf(sql, 1024, "CREATE TEMPORARY TABLE pg_dump_oid (dummy int4);\n");
3617
	pos = pos + snprintf(sql+pos, 1024-pos, "COPY pg_dump_oid WITH OIDS FROM stdin;\n");
B
Bruce Momjian 已提交
3618 3619
	pos = pos + snprintf(sql+pos, 1024-pos, "%-d\t0\n", max_oid);
	pos = pos + snprintf(sql+pos, 1024-pos, "\\.\n");
3620
	pos = pos + snprintf(sql+pos, 1024-pos, "DROP TABLE pg_dump_oid;\n");
B
Bruce Momjian 已提交
3621

3622
	ArchiveEntry(fout, "0", "Max OID", "<Init>", NULL, sql, "", "", "", NULL, NULL);
3623
}
3624 3625 3626

/*
 * findLastBuiltInOid -
3627
 * find the last built in oid
3628
 * we do this by looking up the oid of 'template1' in pg_database,
3629
 * this is probably not foolproof but comes close
3630 3631
*/

3632
static int
3633
findLastBuiltinOid(void)
3634
{
B
Bruce Momjian 已提交
3635
	PGresult   *res;
3636 3637
	int			ntups;
	int			last_oid;
3638 3639 3640 3641 3642 3643

	res = PQexec(g_conn,
			  "SELECT oid from pg_database where datname = 'template1'");
	if (res == NULL ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
3644 3645
		fprintf(stderr, "pg_dump error in finding the template1 database.");
		fprintf(stderr, "Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3646 3647 3648
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);
3649
	if (ntups < 1)
3650
	{
3651 3652
		fprintf(stderr, "pg_dump: couldn't find the template1 database.\n");
		fprintf(stderr, "There is no 'template1' entry in the 'pg_database' table.\n");
3653 3654 3655 3656
		exit_nicely(g_conn);
	}
	if (ntups > 1)
	{
3657 3658
		fprintf(stderr, "pg_dump: found more than one template1 database.\n");
		fprintf(stderr, "There is more than one 'template1' entry in the 'pg_database' table\n");
3659 3660 3661 3662 3663
		exit_nicely(g_conn);
	}
	last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "oid")));
	PQclear(res);
	return last_oid;
3664 3665 3666 3667 3668
}


/*
 * checkForQuote:
3669
 *	  checks a string for quote characters and quotes them
3670
 */
3671
static char *
3672
checkForQuote(const char *s)
3673
{
B
Bruce Momjian 已提交
3674
	char	   *r;
3675
	char		c;
B
Bruce Momjian 已提交
3676
	char	   *result;
3677

3678
	int			j = 0;
3679

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

3682 3683
	while ((c = *s) != '\0')
	{
3684

3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695
		if (c == '\'')
		{
			r[j++] = '\'';		/* quote the single quotes */
		}
		r[j++] = c;
		s++;
	}
	r[j] = '\0';

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

3697
	return result;
3698 3699

}
3700 3701


3702
static void
B
Bruce Momjian 已提交
3703
dumpSequence(Archive *fout, TableInfo tbinfo)
3704
{
3705
	PGresult   *res;
B
Bruce Momjian 已提交
3706
	int4		last,
3707 3708 3709 3710
				incby,
				maxv,
				minv,
				cache;
B
Bruce Momjian 已提交
3711
	char		cycled,
B
Bruce Momjian 已提交
3712
				called;
3713 3714
	const char *t;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
3715
	PQExpBuffer delqry = createPQExpBuffer();
3716

B
Hi, all  
Bruce Momjian 已提交
3717
	appendPQExpBuffer(query,
3718
			"SELECT sequence_name, last_value, increment_by, max_value, "
3719 3720
				  "min_value, cache_value, is_cycled, is_called from %s",
					  fmtId(tbinfo.relname, force_quotes));
3721

B
Hi, all  
Bruce Momjian 已提交
3722
	res = PQexec(g_conn, query->data);
3723 3724
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
3725 3726
		fprintf(stderr, "dumpSequence(%s): SELECT failed.  "
					"Explanation from backend: '%s'.\n", tbinfo.relname, PQerrorMessage(g_conn));
3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757
		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 已提交
3758 3759
	resetPQExpBuffer(delqry);
	appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n", fmtId(tbinfo.relname, force_quotes));
3760

B
Hi, all  
Bruce Momjian 已提交
3761 3762
	resetPQExpBuffer(query);
	appendPQExpBuffer(query,
3763 3764
				  "CREATE SEQUENCE %s start %d increment %d maxvalue %d "
					  "minvalue %d  cache %d %s;\n",
B
Bruce Momjian 已提交
3765
					fmtId(tbinfo.relname, force_quotes), last, incby, maxv, minv, cache,
3766
					  (cycled == 't') ? "cycle" : "");
3767

B
Bruce Momjian 已提交
3768 3769 3770 3771 3772
	if (called != 'f') {
		appendPQExpBuffer(query, "SELECT nextval ('%s');\n", fmtId(tbinfo.relname, force_quotes));
	}

	ArchiveEntry(fout, tbinfo.oid, fmtId(tbinfo.relname, force_quotes), "SEQUENCE", NULL,
3773
					query->data, delqry->data, "", tbinfo.usename, NULL, NULL);
3774

B
Bruce,  
Bruce Momjian 已提交
3775 3776 3777 3778 3779 3780
	/* Dump Sequence Comments */

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

3781
}
V
Vadim B. Mikheev 已提交
3782 3783


3784
static void
B
Bruce Momjian 已提交
3785
dumpTriggers(Archive *fout, const char *tablename,
3786
			 TableInfo *tblinfo, int numTables)
V
Vadim B. Mikheev 已提交
3787
{
3788 3789 3790
	int			i,
				j;

V
Vadim B. Mikheev 已提交
3791 3792 3793
	if (g_verbose)
		fprintf(stderr, "%s dumping out triggers %s\n",
				g_comment_start, g_comment_end);
3794

V
Vadim B. Mikheev 已提交
3795 3796 3797 3798 3799 3800
	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 已提交
3801
			ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
3802
						"TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "", "", 
B
Bruce Momjian 已提交
3803 3804
						tblinfo[i].usename, NULL, NULL);
			dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid);
V
Vadim B. Mikheev 已提交
3805 3806 3807
		}
	}
}
3808 3809


3810
static void
B
Bruce Momjian 已提交
3811
dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
3812
		  TableInfo *tblinfo, int numTables)
3813
{
B
Bruce Momjian 已提交
3814 3815 3816 3817
	PGresult   *res;
	int			nrules;
	int			i,
				t;
3818
	PQExpBuffer query = createPQExpBuffer();
3819

B
Bruce Momjian 已提交
3820
	int			i_definition;
3821 3822
	int			i_oid;
	int			i_rulename;
3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838

	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
		 */
B
Hi, all  
Bruce Momjian 已提交
3839 3840
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "SELECT pg_get_ruledef(pg_rewrite.rulename) "
3841 3842 3843 3844 3845
						  "AS definition, pg_rewrite.oid, pg_rewrite.rulename FROM pg_rewrite, pg_class "
						  "WHERE pg_class.relname = '%s' "
						  "AND pg_rewrite.ev_class = pg_class.oid "
						  "ORDER BY pg_rewrite.oid",
						  tblinfo[t].relname);
B
Hi, all  
Bruce Momjian 已提交
3846
		res = PQexec(g_conn, query->data);
3847 3848 3849
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
B
Bruce Momjian 已提交
3850 3851
			fprintf(stderr, "dumpRules(): SELECT failed for table %s.  Explanation from backend: '%s'.\n",
					tblinfo[t].relname, PQerrorMessage(g_conn));
3852 3853 3854 3855 3856
			exit_nicely(g_conn);
		}

		nrules = PQntuples(res);
		i_definition = PQfnumber(res, "definition");
B
Bruce,  
Bruce Momjian 已提交
3857 3858
		i_oid = PQfnumber(res, "oid");
		i_rulename = PQfnumber(res, "rulename");
3859 3860 3861 3862

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

3864 3865 3866
		for (i = 0; i < nrules; i++)
		{

B
Bruce Momjian 已提交
3867 3868
			ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
							"RULE", NULL, PQgetvalue(res, i, i_definition),
3869
							"", "", "", NULL, NULL);
3870

B
Bruce,  
Bruce Momjian 已提交
3871 3872 3873 3874 3875
			/* 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));
3876

B
Bruce,  
Bruce Momjian 已提交
3877 3878
		}

3879 3880 3881 3882
		PQclear(res);
	}
}