pg_dump.c 134.5 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * pg_dump.c
4
 *	  pg_dump is a utility for dumping out a postgres database
B
Bruce Momjian 已提交
5
 *	  into a script file.
6 7 8
 *
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
9
 *
10 11 12 13 14 15
 *	pg_dump will read the system catalogs in a database and
 *	dump out a script that reproduces
 *	the schema of the database in terms of
 *		  user-defined types
 *		  user-defined functions
 *		  tables
16
 *		  indexes
17 18 19
 *		  aggregates
 *		  operators
 *		  ACL - grant/revoke
20
 *
21
 * the output script is SQL that is understood by PostgreSQL
22 23 24
 *
 *
 * IDENTIFICATION
25
 *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.218 2001/08/03 20:47:40 tgl 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
 *	 indexes,tables,inheritance,types,functions and aggregates.
47
 *	 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
 *
 * 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
B
Bruce Momjian 已提交
58
 *		   commands, but pg_restore can be told not to output them).
B
Bruce Momjian 已提交
59 60 61 62 63
 *		 - Added RI warnings to the 'as insert strings' output mode
 *		 - Added a small number of comments
 *		 - Added a -Z option for compression level on compressed formats
 *		 - Restored '-f' in usage output
 *
64 65 66 67 68
 *
 * Modifications - 17-Jul-2000 - Philip Warner pjw@rhyme.com.au
 *		 - Support for BLOB output.
 *		 - Sort archive by OID, put some items at end (out of OID order)
 *
69 70
 * Modifications - 28-Jul-2000 - pjw@rhyme.com.au (1.45)
 *
B
Bruce Momjian 已提交
71
 *		Added --create, --no-owner, --superuser, --no-reconnect (pg_dump & pg_restore)
72 73 74 75 76 77 78 79 80 81
 *		Added code to dump 'Create Schema' statement (pg_dump)
 *		Don't bother to disable/enable triggers if we don't have a superuser (pg_restore)
 *		Cleaned up code for reconnecting to database.
 *		Force a reconnect as superuser before enabling/disabling triggers.
 *
 * Modifications - 31-Jul-2000 - pjw@rhyme.com.au (1.46, 1.47)
 *		Added & Removed --throttle (pg_dump)
 *		Fixed minor bug in language dumping code: expbuffres were not being reset.
 *		Fixed version number initialization in _allocAH (pg_backup_archiver.c)
 *
B
Bruce Momjian 已提交
82
 * Modifications - 14-Sep-2000 - pjw@rhyme.com.au
83
 *		Use symbols for tests on relkind (ie. use RELKIND_VIEW, not 'v')
B
Bruce Momjian 已提交
84 85
 *		Support for relkind = RELKIND_VIEW.
 *		Fix bug in support for -b option (== --blobs).
86 87 88 89
 *		Dump views as views (using 'create view').
 *		Remove 'isViewRule' since we check the relkind when getting tables.
 *		Now uses temp table 'pgdump_oid' rather than 'pg_dump_oid' (errors otherwise).
 *
90 91 92 93
 * Modifications - 02-Oct-2000 - pjw@rhyme.com.au
 *
 *	  - Be more paranoid when getting views: call get_viewdef in separate statement
 *		so we can be more informative in error messages.
B
Bruce Momjian 已提交
94 95
 *	  - Support for 'isstrict' procedure attribute.
 *	  - Disable --blobs and --table since (a) it's a pain to get ONLY the blobs for the
96 97 98
 *		table with the currently implementation, and (b) it's not clear how to restore
 *		a partial BLOB backup (given the current OID-based BLOB implementation).
 *
99
 * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
100 101 102 103
 *
 *	  - Check ntuples == 1 for various SELECT statements.
 *	  - Fix handling of --tables=* (multiple tables never worked properly, AFAICT)
 *
104 105
 * Modifications - 13-Feb-2001 - pjw@rhyme.com.au
 *
B
Bruce Momjian 已提交
106 107 108
 *	  - Fix help output: replace 'f' with 't' and change desc.
 *	  - Add extra arg to formatStringLiteral to specify how to handle LF & TAB.
 *		I opted for encoding them except in procedure bodies.
109 110
 *	  - Dump relevant parts of sequences only when doing schemaOnly & dataOnly
 *	  - Prevent double-dumping of sequences when dataOnly.
P
Philip Warner 已提交
111
 *
B
Bruce Momjian 已提交
112
 * Modifications - 19-Mar-2001 - pjw@rhyme.com.au
P
Philip Warner 已提交
113 114 115 116 117
 *
 *	  - Remove fmtId calls for all ArchiveEntry name fields. This fixes
 *		quoting problems in trigger enable/disable code for mixed case
 *		table names, and avoids commands like 'pg_restore -t '"TblA"''
 *
118 119 120 121
 * Modifications - 31-Mar-2001 - pjw@rhyme.com.au
 *
 *	  - Dump dependency information in dumpType. This is necessary
 *		because placeholder types will have an OID less than the
122
 *		OID of the type functions, but type must be created after
123 124
 *		the functions.
 *
125 126 127 128 129
 * Modifications - 4-Apr-2001 - pjw@rhyme.com.au
 *
 *	  - Don't dump CHECK constraints with same source and names both
 *		starting with '$'.
 *
130 131 132 133 134 135
 * Modifications - 10-May-2001 - pjw@rhyme.com.au
 *
 *	  - Don't dump COMMENTs in data-only dumps
 *	  - Fix view dumping SQL for V7.0
 *	  - Fix bug when getting view oid with long view names
 *
136
 *-------------------------------------------------------------------------
137 138
 */

139 140 141 142 143 144 145
/*
 * Although this is not a backend module, we must include postgres.h anyway
 * so that we can include a bunch of backend include files.  pg_dump has
 * never pretended to be very independent of the backend anyhow ...
 */
#include "postgres.h"

146
#include <unistd.h>				/* for getopt() */
147
#include <ctype.h>
148 149 150
#ifdef ENABLE_NLS
#include <locale.h>
#endif
151 152 153 154 155 156 157
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif

158 159 160 161
#ifndef HAVE_STRDUP
#include "strdup.h"
#endif

162
#include "access/attnum.h"
163
#include "access/htup.h"
164
#include "catalog/pg_class.h"
V
Vadim B. Mikheev 已提交
165
#include "catalog/pg_trigger.h"
166
#include "catalog/pg_type.h"
167

168
#include "libpq-fe.h"
169
#include "libpq/libpq-fs.h"
170 171

#include "pg_dump.h"
B
Bruce Momjian 已提交
172
#include "pg_backup.h"
173
#include "pg_backup_archiver.h"
174

B
Bruce Momjian 已提交
175 176 177 178 179 180 181 182
typedef enum _formatLiteralOptions
{
	CONV_ALL = 0,
	PASS_LFTAB = 3				/* NOTE: 1 and 2 are reserved in case we
								 * want to make a mask. */
	/* We could make this a bit mask for control chars, but I don't */
	/* see any value in making it more complex...the current code */
	/* only checks for 'opts == CONV_ALL' anyway. */
183 184
} formatLiteralOptions;

185 186
static void dumpComment(Archive *outfile, const char *target, const char *oid,
						const char *((*deps)[]));
187
static void dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool dataOnly);
B
Bruce Momjian 已提交
188 189
static void dumpACL(Archive *fout, TableInfo tbinfo);
static void dumpTriggers(Archive *fout, const char *tablename,
190
			 TableInfo *tblinfo, int numTables);
B
Bruce Momjian 已提交
191
static void dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
192
		  TableInfo *tblinfo, int numTables);
193
static void formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts);
194
static void clearTableInfo(TableInfo *, int);
B
Bruce Momjian 已提交
195
static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
196
			TypeInfo *tinfo, int numTypes);
197 198
static Oid	findLastBuiltinOid_V71(const char *);
static Oid	findLastBuiltinOid_V70(void);
B
Bruce Momjian 已提交
199
static void setMaxOid(Archive *fout);
200

201 202
static void AddAcl(char *aclbuf, const char *keyword);
static char *GetPrivileges(const char *s);
V
Vadim B. Mikheev 已提交
203

B
Bruce Momjian 已提交
204 205
static int	dumpBlobs(Archive *AH, char *, void *);
static int	dumpDatabase(Archive *AH);
206
static PQExpBuffer getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo);
207
static const char *getAttrName(int attrnum, TableInfo *tblInfo);
208

B
Bruce Momjian 已提交
209
extern char *optarg;
210
extern int	optind,
B
Bruce Momjian 已提交
211
			opterr;
212 213

/* global decls */
214
bool		g_verbose;			/* User wants verbose narration of our
B
Bruce Momjian 已提交
215
								 * activities. */
216
Oid			g_last_builtin_oid; /* value of the last builtin oid */
B
Bruce Momjian 已提交
217
Archive    *g_fout;				/* the script file */
B
Bruce Momjian 已提交
218 219 220
PGconn	   *g_conn;				/* the database connection */

bool		force_quotes;		/* User wants to suppress double-quotes */
221 222 223 224
bool		dumpData;			/* dump data using proper insert strings */
bool		attrNames;			/* put attr names into insert strings */
bool		schemaOnly;
bool		dataOnly;
225
bool		aclsSkip;
226

B
Bruce Momjian 已提交
227
char		g_opaque_type[10];	/* name for the opaque type */
228 229

/* placeholders for the delimiters for comments */
230 231
char		g_comment_start[10];
char		g_comment_end[10];
232 233


B
Bruce Momjian 已提交
234 235 236 237
typedef struct _dumpContext
{
	TableInfo  *tblinfo;
	int			tblidx;
B
Bruce Momjian 已提交
238 239 240
	bool		oids;
} DumpContext;

241
static void
242
help(const char *progname)
243
{
244 245 246 247
	printf(gettext("%s dumps a database as a text file or to other formats.\n\n"), progname);
	puts(gettext("Usage:"));
	printf(gettext("  %s [options] dbname\n\n"), progname);
	puts(gettext("Options:"));
B
Hi,  
Bruce Momjian 已提交
248 249

#ifdef HAVE_GETOPT_LONG
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
	puts(gettext(
		"  -a, --data-only          dump only the data, not the schema\n"
		"  -b, --blobs              include BLOB data in dump\n"
		"  -c, --clean              clean (drop) schema prior to create\n"
		"  -C, --create             include commands to create database in dump\n"
		"  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"
		"  -D, --attribute-inserts  dump data as INSERT commands with column names\n"
		"  -f, --file=FILENAME      output file name\n"
		"  -F, --format {c|t|p}     output file format (custom, tar, plain text)\n"
		"  -h, --host=HOSTNAME      database server host name\n"
		"  -i, --ignore-version     proceed even when server version mismatches\n"
		"                           pg_dump version\n"
		"  -n, --no-quotes          suppress most quotes around identifiers\n"
		"  -N, --quotes             enable most quotes around identifiers\n"
		"  -o, --oids               include oids in dump\n"
		"  -O, --no-owner           do not output \\connect commands in plain\n"
		"                           text format\n"
		"  -p, --port=PORT          database server port number\n"
		"  -R, --no-reconnect       disable ALL reconnections to the database in\n"
		"                           plain text format\n"
		"  -s, --schema-only        dump only the schema, no data\n"
		"  -S, --superuser=NAME     specify the superuser user name to use in\n"
		"                           plain text format\n"
		"  -t, --table=TABLE        dump this table only (* for all)\n"
		"  -U, --username=NAME      connect as specified database user\n"
		"  -v, --verbose            verbose mode\n"
		"  -W, --password           force password prompt (should happen automatically)\n"
		"  -x, --no-acl             do not dump privileges (grant/revoke)\n"
		"  -Z, --compress {0-9}     compression level for compressed formats\n"
		));
B
Hi,  
Bruce Momjian 已提交
280
#else
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	puts(gettext(
		"  -a                       dump only the data, not the schema\n"
		"  -b                       include BLOB data in dump\n"
		"  -c                       clean (drop) schema prior to create\n"
		"  -C                       include commands to create database in dump\n"
		"  -d                       dump data as INSERT, rather than COPY, commands\n"
		"  -D                       dump data as INSERT commands with column names\n"
		"  -f FILENAME              output file name\n"
		"  -F {c|t|p}               output file format (custom, tar, plain text)\n"
		"  -h HOSTNAME              database server host name\n"
		"  -i                       proceed even when server version mismatches\n"
		"                           pg_dump version\n"
		"  -n                       suppress most quotes around identifiers\n"
		"  -N                       enable most quotes around identifiers\n"
		"  -o                       include oids in dump\n"
		"  -O                       do not output \\connect commands in plain\n"
		"                           text format\n"
		"  -p PORT                  database server port number\n"
		"  -R                       disable ALL reconnections to the database in\n"
		"                           plain text format\n"
		"  -s                       dump only the schema, no data\n"
		"  -S NAME                  specify the superuser user name to use in\n"
		"                           plain text format\n"
		"  -t TABLE                 dump this table only (* for all)\n"
		"  -U NAME                  connect as specified database user\n"
		"  -v                       verbose mode\n"
		"  -W                       force password prompt (should happen automatically)\n"
		"  -x                       do not dump privileges (grant/revoke)\n"
		"  -Z {0-9}                 compression level for compressed formats\n"
		));
B
Hi,  
Bruce Momjian 已提交
311
#endif
312 313 314
	puts(gettext("If no database name is not supplied, then the PGDATABASE environment\n"
				 "variable value is used.\n\n"
				 "Report bugs to <pgsql-bugs@postgresql.org>."));
315 316
}

317

318 319
void
exit_nicely(void)
320
{
321 322 323
	PQfinish(g_conn);
	if (g_verbose)
		write_msg(NULL, "*** aborted because of error\n");
324
	exit(1);
325 326 327
}


328 329
#define COPYBUFSIZ		8192

B
Bruce Momjian 已提交
330 331 332 333 334
/*
 *	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.
 */
335

B
Bruce Momjian 已提交
336 337
static int
dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv)
338
{
B
Bruce Momjian 已提交
339 340
	const DumpContext *dctx = (DumpContext *) dctxv;
	const char *classname = dctx->tblinfo[dctx->tblidx].relname;
B
Bruce Momjian 已提交
341
	const bool	oids = dctx->oids;
342

343 344 345 346 347
	PGresult   *res;
	char		query[255];
	int			ret;
	bool		copydone;
	char		copybuf[COPYBUFSIZ];
348

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

352
	if (oids == true)
353
	{
B
Bruce Momjian 已提交
354 355

		/*
356
		 * archprintf(fout, "COPY %s WITH OIDS FROM stdin;\n",
B
Bruce Momjian 已提交
357
		 * fmtId(classname, force_quotes));
358
		 *
B
Bruce Momjian 已提交
359
		 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
360 361 362
		 *
		 */

363
		sprintf(query, "COPY %s WITH OIDS TO stdout;",
364
				fmtId(classname, force_quotes));
365 366 367
	}
	else
	{
B
Bruce Momjian 已提交
368 369 370 371

		/*
		 * archprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname,
		 * force_quotes));
372 373 374 375 376
		 *
		 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
		 *
		 */

377
		sprintf(query, "COPY %s TO stdout;", fmtId(classname, force_quotes));
378 379
	}
	res = PQexec(g_conn, query);
380 381
	if (!res ||
		PQresultStatus(res) == PGRES_FATAL_ERROR)
382
	{
383 384 385 386
		write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed\n",
				  classname);
		write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
		write_msg(NULL, "The command was: %s\n", query);
387
		exit_nicely();
388 389 390 391 392
	}
	else
	{
		if (PQresultStatus(res) != PGRES_COPY_OUT)
		{
393 394 395 396 397
			write_msg(NULL, "SQL command to dump the contents of table \"%s\" executed abnormally.\n",
					  classname);
			write_msg(NULL, "The server returned status %d when %d was expected.\n", 
					  PQresultStatus(res), PGRES_COPY_OUT);
			write_msg(NULL, "The command was: %s\n", query);
398
			exit_nicely();
399 400 401 402
		}
		else
		{
			copydone = false;
403

404 405
			while (!copydone)
			{
406
				ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
407 408 409 410 411 412 413 414 415

				if (copybuf[0] == '\\' &&
					copybuf[1] == '.' &&
					copybuf[2] == '\0')
				{
					copydone = true;	/* don't print this... */
				}
				else
				{
B
Bruce Momjian 已提交
416
					archputs(copybuf, fout);
417 418
					switch (ret)
					{
419 420 421 422
						case EOF:
							copydone = true;
							/* FALLTHROUGH */
						case 0:
B
Bruce Momjian 已提交
423
							archputc('\n', fout);
424 425 426
							break;
						case 1:
							break;
427 428
					}
				}
429

B
Bruce Momjian 已提交
430
				/*
431 432
				 * THROTTLE:
				 *
B
Bruce Momjian 已提交
433 434 435 436 437
				 * There was considerable discussion in late July, 2000
				 * regarding slowing down pg_dump when backing up large
				 * tables. Users with both slow & fast (muti-processor)
				 * machines experienced performance degradation when doing
				 * a backup.
438
				 *
B
Bruce Momjian 已提交
439 440 441 442 443
				 * Initial attempts based on sleeping for a number of ms for
				 * each ms of work were deemed too complex, then a simple
				 * 'sleep in each loop' implementation was suggested. The
				 * latter failed because the loop was too tight. Finally,
				 * the following was implemented:
444
				 *
B
Bruce Momjian 已提交
445 446 447
				 * If throttle is non-zero, then See how long since the last
				 * sleep. Work out how long to sleep (based on ratio). If
				 * sleep is more than 100ms, then sleep reset timer EndIf
448 449
				 * EndIf
				 *
B
Bruce Momjian 已提交
450 451
				 * where the throttle value was the number of ms to sleep per
				 * ms of work. The calculation was done in each loop.
452
				 *
B
Bruce Momjian 已提交
453 454 455 456 457
				 * Most of the hard work is done in the backend, and this
				 * solution still did not work particularly well: on slow
				 * machines, the ratio was 50:1, and on medium paced
				 * machines, 1:1, and on fast multi-processor machines, it
				 * had little or no effect, for reasons that were unclear.
458 459 460
				 *
				 * Further discussion ensued, and the proposal was dropped.
				 *
B
Bruce Momjian 已提交
461 462 463 464 465 466
				 * For those people who want this feature, it can be
				 * implemented using gettimeofday in each loop,
				 * calculating the time since last sleep, multiplying that
				 * by the sleep ratio, then if the result is more than a
				 * preset 'minimum sleep time' (say 100ms), call the
				 * 'select' function to sleep for a subsecond period ie.
467
				 *
B
Bruce Momjian 已提交
468
				 * select(0, NULL, NULL, NULL, &tvi);
469
				 *
B
Bruce Momjian 已提交
470 471 472 473
				 * This will return after the interval specified in the
				 * structure tvi. Fianally, call gettimeofday again to
				 * save the 'last sleep time'.
				 */
474
			}
B
Bruce Momjian 已提交
475
			archprintf(fout, "\\.\n");
476
		}
477
		ret = PQendcopy(g_conn);
478 479
		if (ret != 0)
		{
480 481 482
			write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed: PQendcopy() failed.\n", classname);
			write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
			write_msg(NULL, "The command was: %s\n", query);
B
Bruce Momjian 已提交
483
			PQclear(res);
484
			exit_nicely();
485 486
		}
	}
487

B
Bruce Momjian 已提交
488
	return 1;
489 490
}

B
Bruce Momjian 已提交
491
static int
B
Bruce Momjian 已提交
492
dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
493
{
B
Bruce Momjian 已提交
494 495
	const DumpContext *dctx = (DumpContext *) dctxv;
	const char *classname = dctx->tblinfo[dctx->tblidx].relname;
B
Bruce Momjian 已提交
496

497 498
	PGresult   *res;
	PQExpBuffer q = createPQExpBuffer();
499 500
	int			tuple;
	int			field;
501

502 503 504 505 506 507 508
	if (fout->remoteVersion >= 70100)
	{
		appendPQExpBuffer(q, "SELECT * FROM ONLY %s", fmtId(classname, force_quotes));
	} else {
		appendPQExpBuffer(q, "SELECT * FROM %s", fmtId(classname, force_quotes));
	}

B
Hi, all  
Bruce Momjian 已提交
509
	res = PQexec(g_conn, q->data);
510 511 512
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
513 514 515
		write_msg(NULL, "dumpClasses(): SQL command failed\n");
		write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
		write_msg(NULL, "The command was: %s\n", q->data);
516
		exit_nicely();
517
	}
518
	for (tuple = 0; tuple < PQntuples(res); tuple++)
519
	{
B
Bruce Momjian 已提交
520
		archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
521
		if (attrNames == true)
522
		{
B
Hi, all  
Bruce Momjian 已提交
523 524
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "(");
525
			for (field = 0; field < PQnfields(res); field++)
526
			{
527
				if (field > 0)
B
Hi, all  
Bruce Momjian 已提交
528 529
					appendPQExpBuffer(q, ",");
				appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
530
			}
B
Hi, all  
Bruce Momjian 已提交
531
			appendPQExpBuffer(q, ") ");
B
Bruce Momjian 已提交
532
			archprintf(fout, "%s", q->data);
533
		}
B
Bruce Momjian 已提交
534
		archprintf(fout, "VALUES (");
535
		for (field = 0; field < PQnfields(res); field++)
536
		{
537
			if (field > 0)
B
Bruce Momjian 已提交
538
				archprintf(fout, ",");
539
			if (PQgetisnull(res, tuple, field))
540
			{
B
Bruce Momjian 已提交
541
				archprintf(fout, "NULL");
542 543 544
				continue;
			}
			switch (PQftype(res, field))
545
			{
546 547
				case INT2OID:
				case INT4OID:
548
				case OIDOID:	/* int types */
549
				case FLOAT4OID:
550
				case FLOAT8OID:/* float types */
551
					/* These types are printed without quotes */
B
Bruce Momjian 已提交
552
					archprintf(fout, "%s",
B
Bruce Momjian 已提交
553
							   PQgetvalue(res, tuple, field));
554
					break;
555
				case BITOID:
556 557 558 559
				case VARBITOID:
					archprintf(fout, "B'%s'",
							   PQgetvalue(res, tuple, field));
					break;
560
				default:
561

562 563
					/*
					 * All other types are printed as string literals,
564
					 * with appropriate escaping of special characters.
565
					 */
566
					resetPQExpBuffer(q);
567
					formatStringLiteral(q, PQgetvalue(res, tuple, field), CONV_ALL);
568
					archprintf(fout, "%s", q->data);
569
					break;
570
			}
571
		}
B
Bruce Momjian 已提交
572
		archprintf(fout, ");\n");
573 574
	}
	PQclear(res);
575
	destroyPQExpBuffer(q);
B
Bruce Momjian 已提交
576
	return 1;
577 578
}

579 580 581 582 583 584 585 586
/*
 * Convert a string value to an SQL string literal,
 * with appropriate escaping of special characters.
 * Quote mark ' goes to '' per SQL standard, other
 * stuff goes to \ sequences.
 * The literal is appended to the given PQExpBuffer.
 */
static void
587
formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts)
588 589 590 591
{
	appendPQExpBufferChar(buf, '\'');
	while (*str)
	{
B
Bruce Momjian 已提交
592
		char		ch = *str++;
593 594 595

		if (ch == '\\' || ch == '\'')
		{
B
Bruce Momjian 已提交
596
			appendPQExpBufferChar(buf, ch);		/* double these */
597 598 599
			appendPQExpBufferChar(buf, ch);
		}
		else if ((unsigned char) ch < (unsigned char) ' ' &&
B
Bruce Momjian 已提交
600 601 602
				 (opts == CONV_ALL
				  || (ch != '\n' && ch != '\t')
				  ))
603
		{
B
Bruce Momjian 已提交
604 605 606 607 608

			/*
			 * generate octal escape for control chars other than
			 * whitespace
			 */
609 610 611 612 613 614 615 616 617 618 619
			appendPQExpBufferChar(buf, '\\');
			appendPQExpBufferChar(buf, ((ch >> 6) & 3) + '0');
			appendPQExpBufferChar(buf, ((ch >> 3) & 7) + '0');
			appendPQExpBufferChar(buf, (ch & 7) + '0');
		}
		else
			appendPQExpBufferChar(buf, ch);
	}
	appendPQExpBufferChar(buf, '\'');
}

620 621
/*
 * DumpClasses -
622
 *	  dump the contents of all the classes.
623 624
 */
static void
B
Bruce Momjian 已提交
625
dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
B
Bruce Momjian 已提交
626
		 const char *onlytable, const bool oids, const bool force_quotes)
627 628
{

B
Bruce Momjian 已提交
629 630 631 632 633 634 635
	int			i;
	DataDumperPtr dumpFn;
	DumpContext *dumpCtx;
	char	   *oidsPart;
	char		copyBuf[512];
	char	   *copyStmt;

636 637 638 639 640 641
	if (oids == true)
		oidsPart = "WITH OIDS ";
	else
		oidsPart = "";


642
	if (g_verbose)
643 644 645 646 647 648
	{
		if (onlytable == NULL || (strlen(onlytable) == 0))
			write_msg(NULL, "preparing to dump the contents of all %d tables/sequences\n", numTables);
		else
			write_msg(NULL, "preparing to dump the contents of only one table/sequence\n");
	}
649

650 651
	for (i = 0; i < numTables; i++)
	{
652
		const char *classname = tblinfo[i].relname;
653 654

		/* Skip VIEW relations */
655
		if (tblinfo[i].viewdef != NULL)
656
			continue;
657 658

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

661
		if (!onlytable || (strcmp(classname, onlytable) == 0) || (strlen(onlytable) == 0))
662 663
		{
			if (g_verbose)
664
				write_msg(NULL, "preparing to dump the contents of table %s\n", classname);
665

666 667 668
#if 0
			becomeUser(fout, tblinfo[i].usename);
#endif
B
Bruce Momjian 已提交
669

B
Bruce Momjian 已提交
670 671
			dumpCtx = (DumpContext *) malloc(sizeof(DumpContext));
			dumpCtx->tblinfo = (TableInfo *) tblinfo;
B
Bruce Momjian 已提交
672 673
			dumpCtx->tblidx = i;
			dumpCtx->oids = oids;
674

B
Bruce Momjian 已提交
675
			if (!dumpData)		/* Dump/restore using COPY */
676
			{
B
Bruce Momjian 已提交
677 678
				dumpFn = dumpClasses_nodumpData;
				/* dumpClasses_nodumpData(fout, classname, oids); */
B
Bruce Momjian 已提交
679
				sprintf(copyBuf, "COPY %s %sFROM stdin;\n", fmtId(tblinfo[i].relname, force_quotes),
680 681 682
						oidsPart);
				copyStmt = copyBuf;
			}
B
Bruce Momjian 已提交
683 684
			else
/* Restore using INSERT */
685
			{
B
Bruce Momjian 已提交
686 687
				dumpFn = dumpClasses_dumpData;
				/* dumpClasses_dumpData(fout, classname); */
688 689
				copyStmt = NULL;
			}
B
Bruce Momjian 已提交
690

P
Philip Warner 已提交
691
			ArchiveEntry(fout, tblinfo[i].oid, tblinfo[i].relname,
B
Bruce Momjian 已提交
692 693
				"TABLE DATA", NULL, "", "", copyStmt, tblinfo[i].usename,
						 dumpFn, dumpCtx);
694
		}
695
	}
696 697
}

698
int
699
main(int argc, char **argv)
700
{
B
Bruce Momjian 已提交
701 702
	int			c;
	const char *filename = NULL;
B
Bruce Momjian 已提交
703
	const char *format = "p";
B
Bruce Momjian 已提交
704 705 706
	const char *dbname = NULL;
	const char *pghost = NULL;
	const char *pgport = NULL;
707
	const char *username = NULL;
B
Bruce Momjian 已提交
708
	char	   *tablename = NULL;
709
	bool		oids = false;
B
Bruce Momjian 已提交
710 711
	TableInfo  *tblinfo;
	int			numTables;
712
	bool		force_password = false;
B
Bruce Momjian 已提交
713
	int			compressLevel = -1;
714
	bool		ignore_version = false;
715 716
	int			plainText = 0;
	int			outputClean = 0;
717
	int			outputCreate = 0;
718
	int			outputBlobs = 0;
719 720
	int			outputNoOwner = 0;
	int			outputNoReconnect = 0;
B
Bruce Momjian 已提交
721
	char	   *outputSuperuser = NULL;
722

B
Bruce Momjian 已提交
723
	RestoreOptions *ropt;
724

B
Hi,  
Bruce Momjian 已提交
725 726 727
#ifdef HAVE_GETOPT_LONG
	static struct option long_options[] = {
		{"data-only", no_argument, NULL, 'a'},
B
Bruce Momjian 已提交
728
		{"blobs", no_argument, NULL, 'b'},
B
Hi,  
Bruce Momjian 已提交
729
		{"clean", no_argument, NULL, 'c'},
730
		{"create", no_argument, NULL, 'C'},
B
Bruce Momjian 已提交
731 732
		{"file", required_argument, NULL, 'f'},
		{"format", required_argument, NULL, 'F'},
733
		{"inserts", no_argument, NULL, 'd'},
734
		{"attribute-inserts", no_argument, NULL, 'D'},
B
Hi,  
Bruce Momjian 已提交
735
		{"host", required_argument, NULL, 'h'},
736
		{"ignore-version", no_argument, NULL, 'i'},
737
		{"no-reconnect", no_argument, NULL, 'R'},
B
Hi,  
Bruce Momjian 已提交
738 739
		{"no-quotes", no_argument, NULL, 'n'},
		{"quotes", no_argument, NULL, 'N'},
740
		{"oids", no_argument, NULL, 'o'},
741
		{"no-owner", no_argument, NULL, 'O'},
B
Hi,  
Bruce Momjian 已提交
742 743
		{"port", required_argument, NULL, 'p'},
		{"schema-only", no_argument, NULL, 's'},
744
		{"superuser", required_argument, NULL, 'S'},
B
Hi,  
Bruce Momjian 已提交
745
		{"table", required_argument, NULL, 't'},
746 747
		{"password", no_argument, NULL, 'W'},
		{"username", required_argument, NULL, 'U'},
B
Hi,  
Bruce Momjian 已提交
748 749
		{"verbose", no_argument, NULL, 'v'},
		{"no-acl", no_argument, NULL, 'x'},
B
Bruce Momjian 已提交
750
		{"compress", required_argument, NULL, 'Z'},
B
Hi,  
Bruce Momjian 已提交
751
		{"help", no_argument, NULL, '?'},
752
		{"version", no_argument, NULL, 'V'}
753
	};
754 755
	int			optindex;

B
Hi,  
Bruce Momjian 已提交
756 757
#endif

758 759 760 761 762 763
#ifdef ENABLE_NLS
	setlocale(LC_ALL, "");
	bindtextdomain("pg_dump", LOCALEDIR);
	textdomain("pg_dump");
#endif

764
	g_verbose = false;
765
	force_quotes = true;
766 767 768 769 770

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

771
	dataOnly = schemaOnly = dumpData = attrNames = false;
772

773
	if (!strrchr(argv[0], '/'))
774 775
		progname = argv[0];
	else
776
		progname = strrchr(argv[0], '/') + 1;
777

778 779 780 781
	/* Set defaulty options based on progname */
	if (strcmp(progname, "pg_backup") == 0)
	{
		format = "c";
P
Philip Warner 已提交
782
		outputBlobs = true;
783
	}
784

785 786
	if (argc > 1)
	{
B
Bruce Momjian 已提交
787
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
788 789 790 791
		{
			help(progname);
			exit(0);
		}
B
Bruce Momjian 已提交
792
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
793
		{
794
			puts("pg_dump (PostgreSQL) " PG_VERSION);
795 796 797 798
			exit(0);
		}
	}

B
Hi,  
Bruce Momjian 已提交
799
#ifdef HAVE_GETOPT_LONG
800
	while ((c = getopt_long(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uU:vWxzZ:V?", long_options, &optindex)) != -1)
B
Hi,  
Bruce Momjian 已提交
801
#else
802
	while ((c = getopt(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uU:vWxzZ:V?-")) != -1)
B
Hi,  
Bruce Momjian 已提交
803
#endif
804

805 806 807
	{
		switch (c)
		{
808
			case 'a':			/* Dump data only */
809
				dataOnly = true;
810
				break;
811

812 813 814 815
			case 'b':			/* Dump blobs */
				outputBlobs = true;
				break;

B
Bruce Momjian 已提交
816
			case 'c':			/* clean (i.e., drop) schema prior to
B
Bruce Momjian 已提交
817
								 * create */
B
Bruce Momjian 已提交
818
				outputClean = 1;
B
Bruce Momjian 已提交
819 820
				break;

821 822 823 824 825
			case 'C':			/* Create DB */

				outputCreate = 1;
				break;

826
			case 'd':			/* dump data as proper insert strings */
827
				dumpData = true;
828
				break;
829

830 831
			case 'D':			/* dump data as proper insert strings with
								 * attr names */
832 833
				dumpData = true;
				attrNames = true;
834
				break;
835

836
			case 'f':
837 838
				filename = optarg;
				break;
839

B
Bruce Momjian 已提交
840 841 842
			case 'F':
				format = optarg;
				break;
843

B
Bruce Momjian 已提交
844
			case 'h':			/* server host */
845 846
				pghost = optarg;
				break;
847

848 849 850
			case 'i':			/* ignore database version mismatch */
				ignore_version = true;
				break;
851

B
Bruce Momjian 已提交
852 853
			case 'n':			/* Do not force double-quotes on
								 * identifiers */
854
				force_quotes = false;
855
				break;
856

857
			case 'N':			/* Force double-quotes on identifiers */
858
				force_quotes = true;
859
				break;
860

861
			case 'o':			/* Dump oids */
862
				oids = true;
863
				break;
864 865


866 867 868
			case 'O':			/* Don't reconnect to match owner */
				outputNoOwner = 1;
				break;
869

870 871 872
			case 'p':			/* server port */
				pgport = optarg;
				break;
873

874 875 876
			case 'R':			/* No reconnect */
				outputNoReconnect = 1;
				break;
877

878
			case 's':			/* dump schema only */
879
				schemaOnly = true;
880
				break;
881

B
Bruce Momjian 已提交
882 883
			case 'S':			/* Username for superuser in plain text
								 * output */
884 885
				outputSuperuser = strdup(optarg);
				break;
886

887
			case 't':			/* Dump data for this table only */
888
				{
889
					int			i;
890 891

					tablename = strdup(optarg);
B
Bruce Momjian 已提交
892 893 894 895 896

					/*
					 * quoted string? Then strip quotes and preserve
					 * case...
					 */
897 898 899
					if (tablename[0] == '"')
					{
						strcpy(tablename, &tablename[1]);
B
Bruce Momjian 已提交
900 901
						if (*(tablename + strlen(tablename) - 1) == '"')
							*(tablename + strlen(tablename) - 1) = '\0';
902 903 904 905 906
					}
					/* otherwise, convert table name to lowercase... */
					else
					{
						for (i = 0; tablename[i]; i++)
907 908
							if (isupper((unsigned char) tablename[i]))
								tablename[i] = tolower((unsigned char) tablename[i]);
909

B
Bruce Momjian 已提交
910 911 912 913 914
						/*
						 * '*' is a special case meaning ALL tables, but
						 * only if unquoted
						 */
						if (strcmp(tablename, "*") == 0)
915 916
							tablename[0] = '\0';

917
					}
918
				}
919
				break;
920

921
			case 'u':
922
				force_password = true;
923
				username = simple_prompt("User name: ", 100, true);
924 925 926 927
				break;

			case 'U':
				username = optarg;
928
				break;
929

930 931
			case 'v':			/* verbose */
				g_verbose = true;
932
				break;
933

934 935 936 937
			case 'W':
				force_password = true;
				break;

938 939
			case 'x':			/* skip ACL dump */
				aclsSkip = true;
940
				break;
941

B
Bruce Momjian 已提交
942 943 944
			case 'Z':			/* Compression Level */
				compressLevel = atoi(optarg);
				break;
945

946 947
#ifndef HAVE_GETOPT_LONG
			case '-':
948 949 950 951
				fprintf(stderr,
						gettext("%s was compiled without support for long options.\n"
								"Use --help for help on invocation options.\n"),
						progname);
952 953 954
				exit(1);
				break;
#endif
955
			default:
956
				fprintf(stderr, gettext("Try '%s --help' for more information.\n"), progname);
957
				exit(1);
958 959 960
		}
	}

B
Bruce Momjian 已提交
961 962
	if (optind < (argc - 1))
	{
P
Philip Warner 已提交
963
		fprintf(stderr,
964 965 966
				gettext("%s: too many command line options (first is '%s')\n"
						"Try '%s --help' for more information.\n"),
				progname, argv[optind + 1], progname);
P
Philip Warner 已提交
967 968 969
		exit(1);
	}

970 971 972 973 974 975 976
	/* Get the target database name */
	if (optind < argc)
		dbname = argv[optind];
	else
		dbname = getenv("PGDATABASE");
	if (!dbname)
	{
977
		write_msg(NULL, "no database name specified\n");
978 979 980
		exit(1);
	}

B
Bruce Momjian 已提交
981 982
	if (dataOnly && schemaOnly)
	{
983
		write_msg(NULL, "The options \"schema only\" (-s) and \"data only\" (-a) cannot be used together.\n");
B
Bruce Momjian 已提交
984 985 986
		exit(1);
	}

B
Bruce Momjian 已提交
987
	if (outputBlobs && tablename != NULL && strlen(tablename) > 0)
988
	{
989 990
		write_msg(NULL, "BLOB output is not supported for a single table.\n");
		write_msg(NULL, "Use all tables or a full dump instead.\n");
991 992 993
		exit(1);
	}

994 995
	if (dumpData == true && oids == true)
	{
996 997
		write_msg(NULL, "INSERT (-d, -D) and OID (-o) options cannot be used together.\n");
		write_msg(NULL, "(The INSERT command cannot set oids.)\n");
998
		exit(1);
999
	}
1000

B
Bruce Momjian 已提交
1001
	if (outputBlobs == true && (format[0] == 'p' || format[0] == 'P'))
P
Philip Warner 已提交
1002
	{
1003 1004
		write_msg(NULL, "BLOB output is not supported for plain text dump files.\n");
		write_msg(NULL, "(Use a different output format.)\n");
P
Philip Warner 已提交
1005 1006 1007
		exit(1);
	}

1008
	/* open the output file */
B
Bruce Momjian 已提交
1009 1010
	switch (format[0])
	{
B
Bruce Momjian 已提交
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024

		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;
1025 1026 1027 1028 1029 1030
			g_fout = CreateArchive(filename, archNull, 0);
			break;

		case 't':
		case 'T':
			g_fout = CreateArchive(filename, archTar, compressLevel);
B
Bruce Momjian 已提交
1031 1032 1033
			break;

		default:
1034
			write_msg(NULL, "invalid output format '%s' specified\n", format);
B
Bruce Momjian 已提交
1035
			exit(1);
B
Bruce Momjian 已提交
1036 1037 1038 1039
	}

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

1044 1045
	/* Let the archiver know how noisy to be */
	g_fout->verbose = g_verbose;
1046

B
Bruce Momjian 已提交
1047 1048
	/*
	 * Open the database using the Archiver, so it knows about it. Errors
1049
	 * mean death. Accept 7.0 & 7.1 database versions.
B
Bruce Momjian 已提交
1050
	 */
1051 1052
	g_fout->minRemoteVersion = 70000;
	g_fout->maxRemoteVersion = 70199;
1053
	g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, username, force_password, ignore_version);
1054

1055 1056 1057 1058 1059 1060 1061 1062
	/*
	 * Start serializable transaction to dump consistent data
	 */
	{
		PGresult   *res;

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

1066 1067 1068
		PQclear(res);
		res = PQexec(g_conn, "set transaction isolation level serializable");
		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
1069
			exit_horribly(g_fout, NULL, "could not set transaction isolation level to serializable: %s",
B
Bruce Momjian 已提交
1070
						  PQerrorMessage(g_conn));
1071

1072 1073 1074
		PQclear(res);
	}

1075 1076 1077 1078
	if (g_fout->remoteVersion >= 70100)
		g_last_builtin_oid = findLastBuiltinOid_V71(dbname);
	else
		g_last_builtin_oid = findLastBuiltinOid_V70();
1079

1080 1081 1082 1083
	/* Dump the database definition */
	if (!dataOnly)
		dumpDatabase(g_fout);

1084
	if (oids == true)
1085
		setMaxOid(g_fout);
B
Bruce Momjian 已提交
1086 1087

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

1091
	if (!schemaOnly)
B
Bruce Momjian 已提交
1092
		dumpClasses(tblinfo, numTables, g_fout, tablename, oids, force_quotes);
1093 1094

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

1097 1098
	if (!dataOnly)				/* dump indexes and triggers at the end
								 * for performance */
V
Vadim B. Mikheev 已提交
1099 1100
	{
		dumpTriggers(g_fout, tablename, tblinfo, numTables);
1101
		dumpRules(g_fout, tablename, tblinfo, numTables);
V
Vadim B. Mikheev 已提交
1102
	}
1103

1104 1105
	/* Now sort the output nicely */
	SortTocByOID(g_fout);
1106
	MoveToStart(g_fout, "DATABASE");
1107 1108 1109
	MoveToEnd(g_fout, "TABLE DATA");
	MoveToEnd(g_fout, "BLOBS");
	MoveToEnd(g_fout, "INDEX");
1110
	MoveToEnd(g_fout, "CONSTRAINT");
1111 1112
	MoveToEnd(g_fout, "TRIGGER");
	MoveToEnd(g_fout, "RULE");
1113
	MoveToEnd(g_fout, "SEQUENCE SET");
1114

B
Bruce Momjian 已提交
1115
	if (plainText)
B
Bruce Momjian 已提交
1116 1117
	{
		ropt = NewRestoreOptions();
B
Bruce Momjian 已提交
1118
		ropt->filename = (char *) filename;
B
Bruce Momjian 已提交
1119 1120
		ropt->dropSchema = outputClean;
		ropt->aclsSkip = aclsSkip;
1121 1122 1123 1124 1125 1126 1127 1128 1129
		ropt->superuser = outputSuperuser;
		ropt->create = outputCreate;
		ropt->noOwner = outputNoOwner;
		ropt->noReconnect = outputNoReconnect;

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

		if (compressLevel == -1)
B
Bruce Momjian 已提交
1132
			ropt->compression = 0;
B
Bruce Momjian 已提交
1133
		else
B
Bruce Momjian 已提交
1134
			ropt->compression = compressLevel;
B
Bruce Momjian 已提交
1135

1136 1137
		ropt->suppressDumpWarnings = true; /* We've already shown them */

B
Bruce Momjian 已提交
1138 1139 1140 1141
		RestoreArchive(g_fout, ropt);
	}

	CloseArchive(g_fout);
1142

1143 1144 1145
	clearTableInfo(tblinfo, numTables);
	PQfinish(g_conn);
	exit(0);
1146 1147
}

1148 1149 1150 1151 1152
/*
 * dumpDatabase:
 *	dump the database definition
 *
 */
B
Bruce Momjian 已提交
1153
static int
1154 1155
dumpDatabase(Archive *AH)
{
B
Bruce Momjian 已提交
1156 1157 1158 1159 1160 1161
	PQExpBuffer dbQry = createPQExpBuffer();
	PQExpBuffer delQry = createPQExpBuffer();
	PQExpBuffer creaQry = createPQExpBuffer();
	PGresult   *res;
	int			ntups;
	int			i_dba;
1162 1163

	if (g_verbose)
1164
		write_msg(NULL, "saving database definition\n");
1165 1166

	/* Get the dba */
1167
	appendPQExpBuffer(dbQry, "select (select usename from pg_user where datdba = usesysid) as dba from pg_database"
B
Bruce Momjian 已提交
1168
					  " where datname = ");
1169
	formatStringLiteral(dbQry, PQdb(g_conn), CONV_ALL);
1170 1171 1172 1173 1174

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

	ntups = PQntuples(res);

1183 1184 1185
	if (ntups <= 0)
	{
		write_msg(NULL, "missing pg_database entry for database \"%s\"\n", PQdb(g_conn));
1186
		exit_nicely();
1187 1188
	}

1189 1190
	if (ntups != 1)
	{
1191 1192
		write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
				  ntups, PQdb(g_conn));
1193
		exit_nicely();
1194 1195 1196 1197 1198 1199
	}

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

B
Bruce Momjian 已提交
1200 1201 1202 1203
	ArchiveEntry(AH, "0" /* OID */ , PQdb(g_conn) /* Name */ , "DATABASE", NULL,
				 creaQry->data /* Create */ , delQry->data /* Del */ ,
				 "" /* Copy */ , PQgetvalue(res, 0, i_dba) /* Owner */ ,
				 NULL /* Dumper */ , NULL /* Dumper Arg */ );
1204 1205 1206

	PQclear(res);

1207 1208 1209 1210
	destroyPQExpBuffer(dbQry);
	destroyPQExpBuffer(delQry);
	destroyPQExpBuffer(creaQry);

1211 1212 1213 1214
	return 1;
}


1215 1216 1217 1218 1219 1220
/*
 * dumpBlobs:
 *	dump all blobs
 *
 */

B
Bruce Momjian 已提交
1221
#define loBufSize 16384
1222 1223
#define loFetchSize 1000

B
Bruce Momjian 已提交
1224 1225
static int
dumpBlobs(Archive *AH, char *junkOid, void *junkVal)
1226
{
B
Bruce Momjian 已提交
1227 1228 1229 1230 1231 1232 1233 1234
	PQExpBuffer oidQry = createPQExpBuffer();
	PQExpBuffer oidFetchQry = createPQExpBuffer();
	PGresult   *res;
	int			i;
	int			loFd;
	char		buf[loBufSize];
	int			cnt;
	int			blobOid;
1235 1236

	if (g_verbose)
1237
		write_msg(NULL, "saving BLOBs\n");
1238 1239

	/* Cursor to get all BLOB tables */
1240 1241 1242 1243 1244 1245
	if (AH->remoteVersion >= 70100)
	{
		appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject");
	} else {
		appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT oid from pg_class where relkind = 'l'");
	}
1246 1247 1248 1249

	res = PQexec(g_conn, oidQry->data);
	if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
	{
1250
		write_msg(NULL, "dumpBlobs(): cursor declaration failed: %s", PQerrorMessage(g_conn));
1251
		exit_nicely();
1252 1253 1254 1255 1256
	}

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

B
Bruce Momjian 已提交
1257 1258
	do
	{
1259 1260 1261 1262 1263 1264
		/* Do a fetch */
		PQclear(res);
		res = PQexec(g_conn, oidFetchQry->data);

		if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
		{
1265 1266
			write_msg(NULL, "dumpBlobs(): fetch from cursor failed: %s",
					  PQerrorMessage(g_conn));
1267
			exit_nicely();
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
		}

		/* 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)
			{
1278 1279
				write_msg(NULL, "dumpBlobs(): could not open large object: %s",
						  PQerrorMessage(g_conn));
1280
				exit_nicely();
1281 1282 1283 1284 1285
			}

			StartBlob(AH, blobOid);

			/* Now read it in chunks, sending data to archive */
B
Bruce Momjian 已提交
1286 1287
			do
			{
1288
				cnt = lo_read(g_conn, loFd, buf, loBufSize);
B
Bruce Momjian 已提交
1289 1290
				if (cnt < 0)
				{
1291 1292
					write_msg(NULL, "dumpBlobs(): error reading large object: %s",
							  PQerrorMessage(g_conn));
1293
					exit_nicely();
1294 1295
				}

B
Bruce Momjian 已提交
1296
				WriteData(AH, buf, cnt);
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306

			} while (cnt > 0);

			lo_close(g_conn, loFd);

			EndBlob(AH, blobOid);

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

1307 1308 1309
	destroyPQExpBuffer(oidQry);
	destroyPQExpBuffer(oidFetchQry);

1310 1311 1312
	return 1;
}

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

	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;
1343 1344
	int			i_typalign;
	int			i_typstorage;
1345
	int			i_typbyval;
1346
	int			i_typisdefined;
1347
	int			i_usename;
1348
	int			i_typedefn;
1349 1350 1351 1352 1353 1354

	/* find all base types */

	/*
	 * we include even the built-in types because those may be used as
	 * array elements by user-defined types
1355
	 *
1356 1357 1358
	 * we filter out the built-in types when we dump out the types
	 */

1359 1360 1361 1362
	if (g_fout->remoteVersion < 70100)
	{
		appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
						"typinput, typoutput, typreceive, typsend, typelem, typdelim, "
1363
						"typdefault, typrelid, typalign, 'p'::char as typstorage, typbyval, typisdefined, "
1364 1365 1366 1367 1368 1369
						"(select usename from pg_user where typowner = usesysid) as usename, "
						"typname as typedefn "
						"from pg_type");
	} else {
		appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
						"typinput, typoutput, typreceive, typsend, typelem, typdelim, "
1370
						"typdefault, typrelid, typalign, typstorage, typbyval, typisdefined, "
1371 1372 1373 1374
						"(select usename from pg_user where typowner = usesysid) as usename, "
						"format_type(pg_type.oid, NULL) as typedefn "
						"from pg_type");
	}
1375

B
Hi, all  
Bruce Momjian 已提交
1376
	res = PQexec(g_conn, query->data);
1377 1378 1379
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
1380
		write_msg(NULL, "query to obtain list of data types failed: %s", PQerrorMessage(g_conn));
1381
		exit_nicely();
1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400
	}

	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");
1401 1402
	i_typalign = PQfnumber(res, "typalign");
	i_typstorage = PQfnumber(res, "typstorage");
1403
	i_typbyval = PQfnumber(res, "typbyval");
1404
	i_typisdefined = PQfnumber(res, "typisdefined");
1405
	i_usename = PQfnumber(res, "usename");
1406
	i_typedefn = PQfnumber(res, "typedefn");
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422

	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));
1423 1424
		tinfo[i].typalign = strdup(PQgetvalue(res, i, i_typalign));
		tinfo[i].typstorage = strdup(PQgetvalue(res, i, i_typstorage));
1425
		tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1426
		tinfo[i].typedefn = strdup(PQgetvalue(res, i, i_typedefn));
1427

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

1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444
		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;
1445 1446 1447 1448 1449

		if (strcmp(PQgetvalue(res, i, i_typisdefined), "f") == 0)
			tinfo[i].isDefined = 0;
		else
			tinfo[i].isDefined = 1;
1450 1451 1452 1453 1454 1455
	}

	*numTypes = ntups;

	PQclear(res);

1456 1457
	destroyPQExpBuffer(query);

1458
	return tinfo;
1459 1460 1461 1462
}

/*
 * getOperators:
1463
 *	  read all operators in the system catalogs and return them in the
1464 1465
 * OprInfo* structure
 *
1466 1467
 *	numOprs is set to the number of operators read in
 *
1468 1469
 *
 */
1470
OprInfo    *
1471 1472
getOperators(int *numOprs)
{
1473
	PGresult   *res;
1474 1475
	int			ntups;
	int			i;
1476
	PQExpBuffer query = createPQExpBuffer();
1477

B
Bruce Momjian 已提交
1478
	OprInfo    *oprinfo;
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493

	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;
1494 1495 1496 1497 1498 1499

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

B
Hi, all  
Bruce Momjian 已提交
1500
	appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
1501
			   "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
B
Bruce Momjian 已提交
1502 1503 1504
					  "oprcanhash, oprlsortop, oprrsortop, "
	"(select usename from pg_user where oprowner = usesysid) as usename "
					  "from pg_operator");
1505

B
Hi, all  
Bruce Momjian 已提交
1506
	res = PQexec(g_conn, query->data);
1507 1508 1509
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
1510
		write_msg(NULL, "query to obtain list of operators failed: %s", PQerrorMessage(g_conn));
1511
		exit_nicely();
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
	}

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

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

1555 1556 1557 1558
	}

	PQclear(res);

1559 1560
	destroyPQExpBuffer(query);

1561
	return oprinfo;
1562 1563
}

1564
void
1565
clearTypeInfo(TypeInfo *tp, int numTypes)
1566
{
1567
	int			i;
1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596

	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);
1597 1598 1599 1600
		if (tp[i].typalign)
			free(tp[i].typalign);
		if (tp[i].typstorage)
			free(tp[i].typstorage);
1601 1602
		if (tp[i].usename)
			free(tp[i].usename);
1603 1604
		if (tp[i].typedefn)
			free(tp[i].typedefn);
1605 1606
	}
	free(tp);
1607 1608 1609
}

void
1610
clearFuncInfo(FuncInfo *fun, int numFuncs)
1611
{
1612 1613
	int			i,
				a;
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624

	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);
1625
		for (a = 0; a < FUNC_MAX_ARGS; ++a)
1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
			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);
1636 1637
}

1638
static void
1639
clearTableInfo(TableInfo *tblinfo, int numTables)
1640
{
1641 1642
	int			i,
				j;
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662

	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 已提交
1663 1664
			if (tblinfo[i].attoids[j])
				free(tblinfo[i].attoids[j]);
1665 1666 1667 1668 1669
			if (tblinfo[i].attnames[j])
				free(tblinfo[i].attnames[j]);
			if (tblinfo[i].typnames[j])
				free(tblinfo[i].typnames[j]);
		}
B
Bruce Momjian 已提交
1670

B
Bruce Momjian 已提交
1671 1672 1673
		if (tblinfo[i].triggers)
		{
			for (j = 0; j < tblinfo[i].ntrig; j++)
B
Bruce Momjian 已提交
1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
			{
				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);
		}

1687 1688
		if (tblinfo[i].atttypmod)
			free((int *) tblinfo[i].atttypmod);
1689 1690
		if (tblinfo[i].inhAttrs)
			free((int *) tblinfo[i].inhAttrs);
1691 1692 1693 1694
		if (tblinfo[i].inhAttrDef)
			free((int *) tblinfo[i].inhAttrDef);
		if (tblinfo[i].inhNotNull)
			free((int *) tblinfo[i].inhNotNull);
1695 1696
		if (tblinfo[i].attnames)
			free(tblinfo[i].attnames);
1697 1698
		if (tblinfo[i].atttypedefns)
			free(tblinfo[i].atttypedefns);
1699 1700 1701 1702
		if (tblinfo[i].typnames)
			free(tblinfo[i].typnames);
		if (tblinfo[i].notnull)
			free(tblinfo[i].notnull);
1703 1704
		if (tblinfo[i].primary_key_name)
			free(tblinfo[i].primary_key_name);
1705 1706
	}
	free(tblinfo);
1707 1708
}

1709
void
1710
clearInhInfo(InhInfo *inh, int numInherits)
1711
{
1712
	int			i;
1713 1714 1715 1716 1717

	if (!inh)
		return;
	for (i = 0; i < numInherits; ++i)
	{
1718 1719
		if (inh[i].inhrelid)
			free(inh[i].inhrelid);
1720 1721 1722 1723
		if (inh[i].inhparent)
			free(inh[i].inhparent);
	}
	free(inh);
1724 1725 1726
}

void
1727
clearOprInfo(OprInfo *opr, int numOprs)
1728
{
1729
	int			i;
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764

	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);
1765 1766 1767
}

void
1768
clearIndInfo(IndInfo *ind, int numIndexes)
1769
{
1770 1771
	int			i,
				a;
1772 1773 1774

	if (!ind)
		return;
1775
	for (i = 0; i < numIndexes; ++i)
1776
	{
1777 1778 1779 1780
		if (ind[i].indexreloid)
			free(ind[i].indexreloid);
		if (ind[i].indreloid)
			free(ind[i].indreloid);
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790
		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);
1791 1792
		if (ind[i].indisprimary)
			free(ind[i].indisprimary);
1793 1794
		if (ind[i].indhaspred)
			free(ind[i].indhaspred);
1795 1796 1797 1798 1799 1800 1801 1802 1803
		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);
1804 1805 1806
}

void
B
Bruce Momjian 已提交
1807
clearAggInfo(AggInfo *agginfo, int numArgs)
1808
{
1809
	int			i;
1810 1811 1812 1813 1814 1815 1816 1817 1818

	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);
1819 1820
		if (agginfo[i].aggtransfn)
			free(agginfo[i].aggtransfn);
1821 1822
		if (agginfo[i].aggfinalfn)
			free(agginfo[i].aggfinalfn);
1823 1824
		if (agginfo[i].aggtranstype)
			free(agginfo[i].aggtranstype);
1825 1826
		if (agginfo[i].aggbasetype)
			free(agginfo[i].aggbasetype);
1827 1828
		if (agginfo[i].agginitval)
			free(agginfo[i].agginitval);
1829 1830 1831 1832
		if (agginfo[i].usename)
			free(agginfo[i].usename);
	}
	free(agginfo);
1833
}
1834 1835 1836

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

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

	/* find all user-defined aggregates */

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

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

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

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

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

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

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

1922 1923 1924 1925
	}

	PQclear(res);

1926 1927
	destroyPQExpBuffer(query);

1928
	return agginfo;
1929 1930 1931 1932
}

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

	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;
1958
	int			i_iscachable;
1959
	int			i_isstrict;
1960
	int			i_usename;
1961 1962 1963

	/* find all user-defined funcs */

1964 1965 1966 1967 1968 1969
	if (g_fout->remoteVersion < 70100)
	{
		appendPQExpBuffer(query,
		   "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
					  "proretset, proargtypes, prosrc, probin, "
				"(select usename from pg_user where proowner = usesysid) as usename, "
1970
				"proiscachable, 'f'::boolean as proisstrict "
1971 1972 1973 1974 1975
				"from pg_proc "
				"where pg_proc.oid > '%u'::oid",
					  g_last_builtin_oid);
	} else {
		appendPQExpBuffer(query,
1976
		   "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
1977
					  "proretset, proargtypes, prosrc, probin, "
1978 1979 1980 1981
				"(select usename from pg_user where proowner = usesysid) as usename, "
				"proiscachable, proisstrict "
				"from pg_proc "
				"where pg_proc.oid > '%u'::oid",
1982
					  g_last_builtin_oid);
1983
	}
1984

B
Hi, all  
Bruce Momjian 已提交
1985
	res = PQexec(g_conn, query->data);
1986 1987 1988
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
1989 1990
		write_msg(NULL, "query to obtain list of functions failed: %s",
				  PQerrorMessage(g_conn));
1991
		exit_nicely();
1992 1993 1994 1995 1996 1997 1998 1999
	}

	ntups = PQntuples(res);

	*numFuncs = ntups;

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

2000 2001
	memset((char *) finfo, 0, ntups * sizeof(FuncInfo));

2002 2003 2004 2005 2006 2007 2008 2009 2010
	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");
2011
	i_iscachable = PQfnumber(res, "proiscachable");
2012
	i_isstrict = PQfnumber(res, "proisstrict");
2013 2014 2015 2016 2017 2018 2019
	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));

2020
		finfo[i].prosrc = strdup(PQgetvalue(res, i, i_prosrc));
2021 2022 2023 2024 2025
		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));
2026
		finfo[i].lang = atoi(PQgetvalue(res, i, i_prolang));
2027
		finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
B
Bruce Momjian 已提交
2028 2029
		finfo[i].iscachable = (strcmp(PQgetvalue(res, i, i_iscachable), "t") == 0);
		finfo[i].isstrict = (strcmp(PQgetvalue(res, i, i_isstrict), "t") == 0);
2030 2031

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

2035 2036
		if (finfo[i].nargs < 0 || finfo[i].nargs > FUNC_MAX_ARGS)
		{
2037 2038
			write_msg(NULL, "failed sanity check: function %s has more than %d (namely %d) arguments\n",
					  finfo[i].proname, FUNC_MAX_ARGS, finfo[i].nargs);
2039
			exit_nicely();
2040 2041 2042 2043
		}
		parseNumericArray(PQgetvalue(res, i, i_proargtypes),
						  finfo[i].argtypes,
						  finfo[i].nargs);
2044 2045 2046 2047 2048
		finfo[i].dumped = 0;
	}

	PQclear(res);

2049
	destroyPQExpBuffer(query);
2050

2051
	return finfo;
2052 2053 2054 2055
}

/*
 * getTables
2056
 *	  read all the user-defined tables (no indexes, no catalogs)
2057 2058
 * in the system catalogs return them in the TableInfo* structure
 *
2059 2060
 * numTables is set to the number of tables read in
 *
2061 2062
 *
 */
2063
TableInfo  *
V
Vadim B. Mikheev 已提交
2064
getTables(int *numTables, FuncInfo *finfo, int numFuncs)
2065
{
2066
	PGresult   *res;
2067 2068
	int			ntups;
	int			i;
2069
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2070
	PQExpBuffer delqry = createPQExpBuffer();
2071
	TableInfo  *tblinfo;
2072

B
Bruce Momjian 已提交
2073
	int			i_reloid;
2074 2075 2076 2077
	int			i_relname;
	int			i_relkind;
	int			i_relacl;
	int			i_usename;
V
Vadim B. Mikheev 已提交
2078 2079
	int			i_relchecks;
	int			i_reltriggers;
2080
	int			i_relhasindex;
2081 2082 2083 2084 2085

	char		relkindview[2];

	relkindview[0] = RELKIND_VIEW;
	relkindview[1] = '\0';
2086 2087

	/*
2088
	 * find all the user-defined tables (no indexes and no catalogs),
2089 2090 2091
	 * ordering by oid is important so that we always process the parent
	 * tables before the child tables when traversing the tblinfo*
	 *
2092
	 * we ignore tables that are not type 'r' (ordinary relation) or 'S'
2093
	 * (sequence) or 'v' (view).
2094 2095
	 */

2096 2097 2098
	if (g_fout->remoteVersion >= 70100)
	{
		appendPQExpBuffer(query,
2099
					  "SELECT pg_class.oid, relname, relacl, relkind, "
2100
					  "(select usename from pg_user where relowner = usesysid) as usename, "
2101
					  "relchecks, reltriggers, relhasindex "
2102 2103
					  "from pg_class "
					  "where relname !~ '^pg_' "
2104 2105
					  "and relkind in ('%c', '%c', '%c') "
					  "order by oid",
B
Bruce Momjian 已提交
2106
					  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2107
	} else {
2108
		/*
2109 2110
		 * Before 7.1, view relkind was not set to 'v', so we must check
		 * if we have a view by looking for a rule in pg_rewrite.
2111 2112 2113 2114
		 */
		appendPQExpBuffer(query,
					  "SELECT c.oid, relname, relacl, "
					  "CASE WHEN relhasrules and relkind = 'r' "
2115 2116 2117 2118 2119
					  "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
					  "             r.ev_class = c.oid AND r.ev_type = '1') "
					  "THEN '%c'::\"char\" "
					  "ELSE relkind END AS relkind,"
					  "(select usename from pg_user where relowner = usesysid) as usename, "
2120 2121 2122 2123 2124
					  "relchecks, reltriggers, relhasindex "
					  "from pg_class c "
					  "where relname !~ '^pg_' "
					  "and relkind in ('%c', '%c', '%c') "
					  "order by oid",
2125
					  RELKIND_VIEW,
2126 2127
					  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
	}
2128

B
Hi, all  
Bruce Momjian 已提交
2129
	res = PQexec(g_conn, query->data);
2130 2131 2132
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
2133 2134
		write_msg(NULL, "query to obtain list of tables failed: %s",
				  PQerrorMessage(g_conn));
2135
		exit_nicely();
2136 2137 2138 2139 2140 2141 2142 2143
	}

	ntups = PQntuples(res);

	*numTables = ntups;

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

B
Bruce Momjian 已提交
2144
	i_reloid = PQfnumber(res, "oid");
2145 2146
	i_relname = PQfnumber(res, "relname");
	i_relacl = PQfnumber(res, "relacl");
2147
	i_relkind = PQfnumber(res, "relkind");
2148
	i_usename = PQfnumber(res, "usename");
V
Vadim B. Mikheev 已提交
2149 2150
	i_relchecks = PQfnumber(res, "relchecks");
	i_reltriggers = PQfnumber(res, "reltriggers");
B
Hi, all  
Bruce Momjian 已提交
2151
	i_relhasindex = PQfnumber(res, "relhasindex");
2152 2153 2154

	for (i = 0; i < ntups; i++)
	{
B
Bruce Momjian 已提交
2155
		tblinfo[i].oid = strdup(PQgetvalue(res, i, i_reloid));
2156 2157 2158 2159
		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 已提交
2160 2161
		tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
		tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
2162

2163
		if (strlen(tblinfo[i].usename) == 0)
2164 2165
			write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
					  tblinfo[i].relname);
2166

2167 2168 2169 2170 2171 2172
		/* Get view definition */
		if (strcmp(PQgetvalue(res, i, i_relkind), relkindview) == 0)
		{
			PGresult   *res2;

			resetPQExpBuffer(query);
2173 2174
			appendPQExpBuffer(query, "SELECT definition as viewdef, ");
			/* XXX 7.2 - replace with att from pg_views or some other generic source */
2175 2176 2177
			appendPQExpBuffer(query, "(select oid from pg_rewrite where "
										" rulename=('_RET' || viewname)::name) as view_oid"
										" from pg_views where viewname = ");
2178
			formatStringLiteral(query, tblinfo[i].relname, CONV_ALL);
2179 2180
			appendPQExpBuffer(query, ";");

2181 2182 2183
			res2 = PQexec(g_conn, query->data);
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
2184 2185
				write_msg(NULL, "query to obtain definition of view \"%s\" failed: %s",
						  tblinfo[i].relname, PQerrorMessage(g_conn));
2186
				exit_nicely();
2187 2188
			}

B
Bruce Momjian 已提交
2189
			if (PQntuples(res2) != 1)
2190 2191
			{
				if (PQntuples(res2) < 1)
2192 2193
					write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
							  tblinfo[i].relname);
B
Bruce Momjian 已提交
2194
				else
2195
					write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
B
Bruce Momjian 已提交
2196
							tblinfo[i].relname);
2197
				exit_nicely();
2198 2199
			}

2200 2201
			if (PQgetisnull(res2, 0, 1))
			{
2202 2203
				write_msg(NULL, "query to obtain definition of view \"%s\" returned NULL oid\n",
						  tblinfo[i].relname);
2204
				exit_nicely();
2205 2206
			}

2207
			tblinfo[i].viewdef = strdup(PQgetvalue(res2, 0, 0));
2208
			tblinfo[i].viewoid = strdup(PQgetvalue(res2, 0, 1));
2209

B
Bruce Momjian 已提交
2210
			if (strlen(tblinfo[i].viewdef) == 0)
2211
			{
2212 2213
				write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
						  tblinfo[i].relname);
2214
				exit_nicely();
2215 2216 2217 2218 2219
			}
		}
		else
			tblinfo[i].viewdef = NULL;

2220
		/*
2221 2222
		 * Get non-inherited CHECK constraints, if any.
		 *
B
Bruce Momjian 已提交
2223 2224
		 * Exclude inherited CHECKs from CHECK constraints total. If a
		 * constraint matches by name and condition with a constraint
2225
		 * belonging to a parent class (OR conditions match and both
2226
		 * names start with '$', we assume it was inherited.
2227 2228
		 */
		if (tblinfo[i].ncheck > 0)
V
Vadim B. Mikheev 已提交
2229 2230
		{
			PGresult   *res2;
2231 2232
			int			i_rcname,
						i_rcsrc;
V
Vadim B. Mikheev 已提交
2233 2234
			int			ntups2;
			int			i2;
2235

V
Vadim B. Mikheev 已提交
2236
			if (g_verbose)
2237 2238
				write_msg(NULL, "finding CHECK constraints for table %s\n",
						  tblinfo[i].relname);
2239

B
Hi, all  
Bruce Momjian 已提交
2240 2241
			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
2242
							  " where rcrelid = '%s'::oid "
2243
							  "   and not exists "
2244 2245 2246 2247 2248 2249 2250 2251
							  "  (select * from pg_relcheck as c, pg_inherits as i "
							  "    where i.inhrelid = pg_relcheck.rcrelid "
							  "      and (c.rcname = pg_relcheck.rcname "
							  "          or (    c.rcname[0] = '$' "
							  "              and pg_relcheck.rcname[0] = '$')"
							  "          )"
							  "      and c.rcsrc = pg_relcheck.rcsrc "
							  "      and c.rcrelid = i.inhparent) "
2252
							  " Order By oid ",
2253
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2254
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2255
			if (!res2 ||
2256
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2257
			{
2258
				write_msg(NULL, "query to obtain check constraints failed: %s", PQerrorMessage(g_conn));
2259
				exit_nicely();
V
Vadim B. Mikheev 已提交
2260 2261
			}
			ntups2 = PQntuples(res2);
2262
			if (ntups2 > tblinfo[i].ncheck)
V
Vadim B. Mikheev 已提交
2263
			{
2264 2265 2266
				write_msg(NULL, "expected %d check constraints on table \"%s\" but found %d\n",
						  tblinfo[i].ncheck, tblinfo[i].relname, ntups2);
				write_msg(NULL, "(The system catalogs might be corrupted.)\n");
2267
				exit_nicely();
V
Vadim B. Mikheev 已提交
2268
			}
2269 2270 2271 2272

			/* Set ncheck to the number of *non-inherited* CHECK constraints */
			tblinfo[i].ncheck = ntups2;

V
Vadim B. Mikheev 已提交
2273 2274
			i_rcname = PQfnumber(res2, "rcname");
			i_rcsrc = PQfnumber(res2, "rcsrc");
2275
			tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
V
Vadim B. Mikheev 已提交
2276 2277
			for (i2 = 0; i2 < ntups2; i2++)
			{
B
Bruce Momjian 已提交
2278 2279
				const char *name = PQgetvalue(res2, i2, i_rcname);
				const char *expr = PQgetvalue(res2, i2, i_rcsrc);
2280

B
Hi, all  
Bruce Momjian 已提交
2281
				resetPQExpBuffer(query);
2282 2283
				if (name[0] != '$')
				{
2284 2285
					appendPQExpBuffer(query, "CONSTRAINT %s ",
									  fmtId(name, force_quotes));
B
Bruce Momjian 已提交
2286
				}
2287
				appendPQExpBuffer(query, "CHECK (%s)", expr);
B
Hi, all  
Bruce Momjian 已提交
2288
				tblinfo[i].check_expr[i2] = strdup(query->data);
V
Vadim B. Mikheev 已提交
2289 2290 2291 2292 2293
			}
			PQclear(res2);
		}
		else
			tblinfo[i].check_expr = NULL;
2294

2295 2296
		/* Get primary key */
		if (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0)
2297
		{
2298
			PGresult   *res2;
B
Bruce Momjian 已提交
2299

B
Hi, all  
Bruce Momjian 已提交
2300
			resetPQExpBuffer(query);
B
Bruce Momjian 已提交
2301
			appendPQExpBuffer(query,
2302
							  "SELECT indexrelid FROM pg_index i WHERE i.indisprimary AND i.indrelid = %s ",
2303
							  tblinfo[i].oid);
2304
			res2 = PQexec(g_conn, query->data);
B
Bruce Momjian 已提交
2305 2306
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
2307 2308
				write_msg(NULL, "query to obtain primary key of table \"%s\" failed: %s",
						  tblinfo[i].relname, PQerrorMessage(g_conn));
2309
				exit_nicely();
B
Bruce Momjian 已提交
2310
			}
2311

B
Bruce Momjian 已提交
2312 2313
			if (PQntuples(res2) > 1)
			{
2314
				write_msg(NULL, "query to obtain primary key of table \"%s\" produced more than one result\n",
2315
						tblinfo[i].relname);
2316
				exit_nicely();
2317 2318
			}

B
Bruce Momjian 已提交
2319
			if (PQntuples(res2) == 1)
2320
				tblinfo[i].pkIndexOid = strdup(PQgetvalue(res2, 0, 0));
B
Bruce Momjian 已提交
2321
			else
2322 2323
				tblinfo[i].pkIndexOid = NULL;

2324
		}
2325
		else
2326
			tblinfo[i].pkIndexOid = NULL;
B
Bruce Momjian 已提交
2327

2328
		/* Get primary key name (if primary key exist) */
2329
		if (tblinfo[i].pkIndexOid != NULL)
2330 2331
		{
			PGresult   *res2;
B
Bruce Momjian 已提交
2332
			int			n;
2333 2334

			resetPQExpBuffer(query);
2335 2336 2337 2338
			appendPQExpBuffer(query,
							  "SELECT relname FROM pg_class "
							  "WHERE oid = %s",
							  tblinfo[i].pkIndexOid);
2339

2340 2341 2342
			res2 = PQexec(g_conn, query->data);
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
2343 2344
				write_msg(NULL, "query to obtain name of primary key of table \"%s\" failed: %s",
						  tblinfo[i].relname, PQerrorMessage(g_conn));
2345
				exit_nicely();
2346 2347 2348 2349 2350
			}

			n = PQntuples(res2);
			if (n != 1)
			{
2351 2352
				write_msg(NULL, "query to obtain name of primary key of table \"%s\" did not return exactly one result\n",
						  tblinfo[i].relname);
2353
				exit_nicely();
2354 2355 2356 2357 2358 2359
			}

			tblinfo[i].primary_key_name =
				strdup(fmtId(PQgetvalue(res2, 0, 0), force_quotes));
			if (tblinfo[i].primary_key_name == NULL)
			{
2360
				write_msg(NULL, "out of memory\n");
2361
				exit_nicely();
2362 2363 2364 2365 2366
			}
		}
		else
			tblinfo[i].primary_key_name = NULL;

V
Vadim B. Mikheev 已提交
2367 2368 2369 2370
		/* Get Triggers */
		if (tblinfo[i].ntrig > 0)
		{
			PGresult   *res2;
B
Bruce,  
Bruce Momjian 已提交
2371
			int			i_tgoid,
2372
						i_tgname,
2373 2374 2375
						i_tgfoid,
						i_tgtype,
						i_tgnargs,
2376 2377 2378 2379
						i_tgargs,
						i_tgisconstraint,
						i_tgconstrname,
						i_tgdeferrable,
2380 2381
						i_tgconstrrelid,
						i_tgconstrrelname,
2382
						i_tginitdeferred;
V
Vadim B. Mikheev 已提交
2383 2384
			int			ntups2;
			int			i2;
2385

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

B
Hi, all  
Bruce Momjian 已提交
2389
			resetPQExpBuffer(query);
2390
			appendPQExpBuffer(query,
2391 2392 2393 2394 2395
								"SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, "
								"tgisconstraint, tgconstrname, tgdeferrable, "
								"tgconstrrelid, tginitdeferred, oid, "
								"(select relname from pg_class where oid = tgconstrrelid) "
								"		as tgconstrrelname "
2396 2397 2398
							  "from pg_trigger "
							  "where tgrelid = '%s'::oid ",
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2399
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2400
			if (!res2 ||
2401
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2402
			{
2403
				write_msg(NULL, "query to obtain list of triggers failed: %s", PQerrorMessage(g_conn));
2404
				exit_nicely();
V
Vadim B. Mikheev 已提交
2405 2406 2407 2408
			}
			ntups2 = PQntuples(res2);
			if (ntups2 != tblinfo[i].ntrig)
			{
2409 2410
				write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
						  tblinfo[i].ntrig, tblinfo[i].relname, ntups2);
2411
				exit_nicely();
V
Vadim B. Mikheev 已提交
2412 2413 2414 2415 2416 2417
			}
			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 已提交
2418
			i_tgoid = PQfnumber(res2, "oid");
2419 2420 2421
			i_tgisconstraint = PQfnumber(res2, "tgisconstraint");
			i_tgconstrname = PQfnumber(res2, "tgconstrname");
			i_tgdeferrable = PQfnumber(res2, "tgdeferrable");
2422 2423
			i_tgconstrrelid = PQfnumber(res2, "tgconstrrelid");
			i_tgconstrrelname = PQfnumber(res2, "tgconstrrelname");
2424 2425
			i_tginitdeferred = PQfnumber(res2, "tginitdeferred");

B
Bruce Momjian 已提交
2426
			tblinfo[i].triggers = (TrigInfo *) malloc(ntups2 * sizeof(TrigInfo));
B
Hi, all  
Bruce Momjian 已提交
2427 2428
			resetPQExpBuffer(query);
			for (i2 = 0; i2 < ntups2; i2++)
V
Vadim B. Mikheev 已提交
2429
			{
2430
				const char *tgfuncoid = PQgetvalue(res2, i2, i_tgfoid);
2431
				char	   *tgfunc = NULL;
2432 2433
				int2		tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
				int			tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
B
Bruce Momjian 已提交
2434
				const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
2435 2436 2437
				int			tgisconstraint;
				int			tgdeferrable;
				int			tginitdeferred;
2438 2439
				char	   *tgconstrrelid;
				char	   *tgname;
B
Bruce Momjian 已提交
2440
				const char *p;
2441 2442
				int			findx;

2443 2444
				tgname = PQgetvalue(res2, i2, i_tgname);

2445
				if (strcmp(PQgetvalue(res2, i2, i_tgisconstraint), "f") == 0)
2446
					tgisconstraint = 0;
2447
				else
2448
					tgisconstraint = 1;
2449 2450

				if (strcmp(PQgetvalue(res2, i2, i_tgdeferrable), "f") == 0)
2451
					tgdeferrable = 0;
2452
				else
2453
					tgdeferrable = 1;
2454 2455

				if (strcmp(PQgetvalue(res2, i2, i_tginitdeferred), "f") == 0)
2456
					tginitdeferred = 0;
2457
				else
2458
					tginitdeferred = 1;
2459

V
Vadim B. Mikheev 已提交
2460 2461
				for (findx = 0; findx < numFuncs; findx++)
				{
2462
					if (strcmp(finfo[findx].oid, tgfuncoid) == 0 &&
2463
						finfo[findx].nargs == 0 &&
V
Vadim B. Mikheev 已提交
2464 2465 2466
						strcmp(finfo[findx].prorettype, "0") == 0)
						break;
				}
2467

V
Vadim B. Mikheev 已提交
2468 2469
				if (findx == numFuncs)
				{
2470
					PGresult   *r;
2471
					int			numFuncs;
2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488

					/*
					 * 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)
					{
2489 2490
						write_msg(NULL, "query to obtain procedure name for trigger \"%s\" failed: %s",
								  tgname, PQerrorMessage(g_conn));
2491
						exit_nicely();
2492 2493 2494 2495
					}

					/* Sanity: Check we got only one tuple */
					numFuncs = PQntuples(r);
B
Bruce Momjian 已提交
2496 2497
					if (numFuncs != 1)
					{
2498 2499
						write_msg(NULL, "query to obtain procedure name for trigger \"%s\" did not return exactly one result\n",
								  tgname);
2500
						exit_nicely();
2501
					}
2502

2503
					tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
2504
					PQclear(r);
2505
				}
2506
				else
2507
					tgfunc = strdup(finfo[findx].proname);
B
Bruce Momjian 已提交
2508

2509
				appendPQExpBuffer(delqry, "DROP TRIGGER %s ", fmtId(tgname, force_quotes));
B
Bruce Momjian 已提交
2510
				appendPQExpBuffer(delqry, "ON %s;\n",
B
Bruce Momjian 已提交
2511
								fmtId(tblinfo[i].relname, force_quotes));
2512

B
Hi, all  
Bruce Momjian 已提交
2513
				resetPQExpBuffer(query);
2514 2515 2516 2517 2518
				if (tgisconstraint)
				{
					appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgconstrname), force_quotes));
				}
2519 2520
				else
				{
2521
					appendPQExpBuffer(query, "CREATE TRIGGER ");
2522
					appendPQExpBuffer(query, fmtId(tgname, force_quotes));
2523
				}
B
Bruce Momjian 已提交
2524
				appendPQExpBufferChar(query, ' ');
V
Vadim B. Mikheev 已提交
2525 2526 2527
				/* Trigger type */
				findx = 0;
				if (TRIGGER_FOR_BEFORE(tgtype))
B
Hi, all  
Bruce Momjian 已提交
2528
					appendPQExpBuffer(query, "BEFORE");
V
Vadim B. Mikheev 已提交
2529
				else
B
Hi, all  
Bruce Momjian 已提交
2530
					appendPQExpBuffer(query, "AFTER");
V
Vadim B. Mikheev 已提交
2531 2532
				if (TRIGGER_FOR_INSERT(tgtype))
				{
B
Hi, all  
Bruce Momjian 已提交
2533
					appendPQExpBuffer(query, " INSERT");
V
Vadim B. Mikheev 已提交
2534 2535 2536 2537 2538
					findx++;
				}
				if (TRIGGER_FOR_DELETE(tgtype))
				{
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2539
						appendPQExpBuffer(query, " OR DELETE");
V
Vadim B. Mikheev 已提交
2540
					else
B
Hi, all  
Bruce Momjian 已提交
2541
						appendPQExpBuffer(query, " DELETE");
V
Vadim B. Mikheev 已提交
2542 2543 2544
					findx++;
				}
				if (TRIGGER_FOR_UPDATE(tgtype))
2545
				{
V
Vadim B. Mikheev 已提交
2546
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2547
						appendPQExpBuffer(query, " OR UPDATE");
V
Vadim B. Mikheev 已提交
2548
					else
B
Hi, all  
Bruce Momjian 已提交
2549
						appendPQExpBuffer(query, " UPDATE");
2550
				}
2551 2552
				appendPQExpBuffer(query, " ON %s ", fmtId(tblinfo[i].relname, force_quotes));

2553
				if (tgisconstraint)
2554
				{
2555 2556 2557 2558 2559
					tgconstrrelid = PQgetvalue(res2, i2, i_tgconstrrelid);

					if (strcmp(tgconstrrelid, "0") != 0) {

						if (PQgetisnull(res2, i2, i_tgconstrrelname))
2560
						{
2561 2562
							write_msg(NULL, "query produced NULL referenced table name for trigger \"%s\" on table \"%s\" (oid was %s)\n",
									  tgname, tblinfo[i].relname, tgconstrrelid);
2563
							exit_nicely();
2564
						}
2565

2566
						appendPQExpBuffer(query, " FROM %s",
2567 2568
										fmtId(PQgetvalue(res2, i2, i_tgconstrrelname), force_quotes));
					}
2569
					if (!tgdeferrable)
2570 2571 2572 2573
						appendPQExpBuffer(query, " NOT");
					appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
					if (tginitdeferred)
						appendPQExpBuffer(query, "DEFERRED");
2574
					else
2575
						appendPQExpBuffer(query, "IMMEDIATE");
2576

2577 2578 2579
				}

				appendPQExpBuffer(query, " FOR EACH ROW");
2580 2581
				appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
								  fmtId(tgfunc, force_quotes));
V
Vadim B. Mikheev 已提交
2582 2583
				for (findx = 0; findx < tgnargs; findx++)
				{
2584
					const char *s;
2585 2586

					for (p = tgargs;;)
V
Vadim B. Mikheev 已提交
2587
					{
2588
						p = strchr(p, '\\');
V
Vadim B. Mikheev 已提交
2589 2590
						if (p == NULL)
						{
2591 2592 2593 2594
							write_msg(NULL, "bad argument string (%s) for trigger \"%s\" on table \"%s\"\n",
									  PQgetvalue(res2, i2, i_tgargs),
									  tgname,
									  tblinfo[i].relname);
2595
							exit_nicely();
V
Vadim B. Mikheev 已提交
2596 2597 2598 2599 2600 2601 2602
						}
						p++;
						if (*p == '\\')
						{
							p++;
							continue;
						}
2603
						if (p[0] == '0' && p[1] == '0' && p[2] == '0')
V
Vadim B. Mikheev 已提交
2604 2605 2606
							break;
					}
					p--;
2607
					appendPQExpBufferChar(query, '\'');
B
Bruce Momjian 已提交
2608
					for (s = tgargs; s < p;)
V
Vadim B. Mikheev 已提交
2609 2610
					{
						if (*s == '\'')
2611 2612
							appendPQExpBufferChar(query, '\\');
						appendPQExpBufferChar(query, *s++);
V
Vadim B. Mikheev 已提交
2613
					}
B
Bruce Momjian 已提交
2614 2615
					appendPQExpBufferChar(query, '\'');
					appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
V
Vadim B. Mikheev 已提交
2616 2617
					tgargs = p + 4;
				}
B
Hi, all  
Bruce Momjian 已提交
2618
				appendPQExpBuffer(query, ");\n");
2619

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

				/*** Initialize trcomments and troids ***/
2623

B
Bruce,  
Bruce Momjian 已提交
2624
				resetPQExpBuffer(query);
2625
				appendPQExpBuffer(query, "TRIGGER %s ",
2626
					fmtId(tgname, force_quotes));
B
Bruce,  
Bruce Momjian 已提交
2627
				appendPQExpBuffer(query, "ON %s",
2628
								fmtId(tblinfo[i].relname, force_quotes));
B
Bruce Momjian 已提交
2629 2630
				tblinfo[i].triggers[i2].tgcomment = strdup(query->data);
				tblinfo[i].triggers[i2].oid = strdup(PQgetvalue(res2, i2, i_tgoid));
2631
				tblinfo[i].triggers[i2].tgname = strdup(fmtId(tgname, false));
B
Bruce Momjian 已提交
2632
				tblinfo[i].triggers[i2].tgdel = strdup(delqry->data);
B
Bruce,  
Bruce Momjian 已提交
2633

2634 2635
				if (tgfunc)
					free(tgfunc);
V
Vadim B. Mikheev 已提交
2636 2637 2638 2639 2640
			}
			PQclear(res2);
		}
		else
			tblinfo[i].triggers = NULL;
2641

2642 2643 2644 2645
	}

	PQclear(res);

2646 2647
	destroyPQExpBuffer(query);
	destroyPQExpBuffer(delqry);
2648

2649
	return tblinfo;
2650 2651 2652 2653
}

/*
 * getInherits
2654
 *	  read all the inheritance information
2655 2656
 * from the system catalogs return them in the InhInfo* structure
 *
2657 2658
 * numInherits is set to the number of tables read in
 *
2659 2660
 *
 */
2661
InhInfo    *
2662 2663
getInherits(int *numInherits)
{
2664
	PGresult   *res;
2665 2666
	int			ntups;
	int			i;
2667 2668
	PQExpBuffer query = createPQExpBuffer();
	InhInfo    *inhinfo;
2669

2670
	int			i_inhrelid;
2671
	int			i_inhparent;
2672 2673 2674

	/* find all the inheritance information */

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

B
Hi, all  
Bruce Momjian 已提交
2677
	res = PQexec(g_conn, query->data);
2678 2679 2680
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
2681 2682
		write_msg(NULL, "query to obtain inheritance relationships failed: %s",
				  PQerrorMessage(g_conn));
2683
		exit_nicely();
2684 2685 2686 2687 2688 2689 2690 2691
	}

	ntups = PQntuples(res);

	*numInherits = ntups;

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

2692
	i_inhrelid = PQfnumber(res, "inhrelid");
2693 2694 2695 2696
	i_inhparent = PQfnumber(res, "inhparent");

	for (i = 0; i < ntups; i++)
	{
2697
		inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
2698 2699 2700 2701
		inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
	}

	PQclear(res);
2702 2703 2704

	destroyPQExpBuffer(query);

2705
	return inhinfo;
2706 2707 2708 2709
}

/*
 * getTableAttrs -
2710 2711
 *	  for each table in tblinfo, read its attributes types and names
 *
2712
 * this is implemented in a very inefficient way right now, looping
2713
 * through the tblinfo and doing a join per table to find the attrs and their
2714 2715
 * types
 *
2716
 *	modifies tblinfo
2717 2718
 */
void
2719
getTableAttrs(TableInfo *tblinfo, int numTables)
2720
{
2721 2722
	int			i,
				j;
2723
	PQExpBuffer q = createPQExpBuffer();
2724 2725
	int			i_attname;
	int			i_typname;
2726
	int			i_atttypmod;
2727
	int			i_attnotnull;
V
Vadim B. Mikheev 已提交
2728
	int			i_atthasdef;
2729
	int			i_attoid;
2730
	int			i_atttypedefn;
2731
	PGresult   *res;
2732
	int			ntups;
2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746

	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)
2747 2748
			write_msg(NULL, "finding the columns and types for table %s\n",
					  tblinfo[i].relname);
2749

B
Hi, all  
Bruce Momjian 已提交
2750
		resetPQExpBuffer(q);
2751 2752 2753 2754

		if (g_fout->remoteVersion < 70100)
		{
			/* Fake the LOJ below */
2755
			appendPQExpBuffer(q,
2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779
						"  SELECT a.oid as attoid, a.attnum, a.attname, t.typname, a.atttypmod, "
						"        a.attnotnull, a.atthasdef, NULL as atttypedefn "
						"    from pg_attribute a, pg_type t "
						"    where a.attrelid = '%s'::oid "
						"        and a.attnum > 0 "
						"        and a.atttypid = t.oid "
						" UNION ALL SELECT a.oid as attoid, a.attnum, a.attname, NULL as typname, a.atttypmod, "
						"        a.attnotnull, a.atthasdef, NULL as atttypedefn "
						"    from pg_attribute a "
						"    where a.attrelid = '%s'::oid "
						"        and a.attnum > 0 "
						"        and Not Exists(Select * From pg_type t where a.atttypid = t.oid)"
						"    order by attnum",
						tblinfo[i].oid, tblinfo[i].oid);

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

B
Hi, all  
Bruce Momjian 已提交
2780
		res = PQexec(g_conn, q->data);
2781 2782 2783
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
2784
			write_msg(NULL, "query to get table columns failed: %s", PQerrorMessage(g_conn));
2785
			exit_nicely();
2786 2787 2788 2789
		}

		ntups = PQntuples(res);

B
Bruce,  
Bruce Momjian 已提交
2790
		i_attoid = PQfnumber(res, "attoid");
2791 2792
		i_attname = PQfnumber(res, "attname");
		i_typname = PQfnumber(res, "typname");
2793
		i_atttypmod = PQfnumber(res, "atttypmod");
2794
		i_attnotnull = PQfnumber(res, "attnotnull");
V
Vadim B. Mikheev 已提交
2795
		i_atthasdef = PQfnumber(res, "atthasdef");
2796
		i_atttypedefn = PQfnumber(res, "atttypedefn");
2797 2798

		tblinfo[i].numatts = ntups;
B
Bruce,  
Bruce Momjian 已提交
2799
		tblinfo[i].attoids = (char **) malloc(ntups * sizeof(char *));
2800
		tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
2801
		tblinfo[i].atttypedefns = (char **) malloc(ntups * sizeof(char *));
2802
		tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
2803
		tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
2804
		tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
2805 2806
		tblinfo[i].inhAttrDef = (int *) malloc(ntups * sizeof(int));
		tblinfo[i].inhNotNull = (int *) malloc(ntups * sizeof(int));
2807
		tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
V
Vadim B. Mikheev 已提交
2808
		tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
2809 2810 2811 2812
		tblinfo[i].parentRels = NULL;
		tblinfo[i].numParents = 0;
		for (j = 0; j < ntups; j++)
		{
2813 2814 2815
			/* Sanity check on LOJ */
			if (PQgetisnull(res, j, i_typname))
			{
2816 2817
				write_msg(NULL, "query produced NULL name for data type of column %d of table %s\n",
						  j+1, tblinfo[i].relname);
2818
				exit_nicely();
2819 2820
			}

B
Bruce,  
Bruce Momjian 已提交
2821
			tblinfo[i].attoids[j] = strdup(PQgetvalue(res, j, i_attoid));
2822
			tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
2823
			tblinfo[i].atttypedefns[j] = strdup(PQgetvalue(res, j, i_atttypedefn));
2824
			tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
2825
			tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
2826 2827
			tblinfo[i].inhAttrs[j] = 0; /* this flag is set in
										 * flagInhAttrs() */
2828 2829 2830
			tblinfo[i].inhAttrDef[j] = 0;
			tblinfo[i].inhNotNull[j] = 0;

2831
			tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't') ? true : false;
V
Vadim B. Mikheev 已提交
2832 2833 2834
			if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
			{
				PGresult   *res2;
2835
				int			numAttr;
2836

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

B
Hi, all  
Bruce Momjian 已提交
2841 2842
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
2843 2844
							 "where adrelid = '%s'::oid and adnum = %d ",
								  tblinfo[i].oid, j + 1);
B
Hi, all  
Bruce Momjian 已提交
2845
				res2 = PQexec(g_conn, q->data);
V
Vadim B. Mikheev 已提交
2846
				if (!res2 ||
2847
					PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2848
				{
2849 2850
					write_msg(NULL, "query to get column default value failed: %s",
							  PQerrorMessage(g_conn));
2851
					exit_nicely();
V
Vadim B. Mikheev 已提交
2852
				}
2853 2854 2855

				/* Sanity: Check we got only one tuple */
				numAttr = PQntuples(res2);
B
Bruce Momjian 已提交
2856 2857
				if (numAttr != 1)
				{
2858 2859
					write_msg(NULL, "query to get default value for column \"%s\" returned %d rows; expected 1\n",
							  tblinfo[i].attnames[j], numAttr);
2860
					exit_nicely();
2861 2862
				}

V
Vadim B. Mikheev 已提交
2863 2864 2865 2866 2867
				tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
				PQclear(res2);
			}
			else
				tblinfo[i].adef_expr[j] = NULL;
2868 2869 2870
		}
		PQclear(res);
	}
2871 2872

	destroyPQExpBuffer(q);
2873 2874 2875 2876
}


/*
2877 2878
 * getIndexes
 *	  read all the user-defined indexes information
2879 2880
 * from the system catalogs return them in the InhInfo* structure
 *
2881
 * numIndexes is set to the number of indexes read in
2882
 *
2883 2884
 *
 */
2885
IndInfo    *
2886
getIndexes(int *numIndexes)
2887
{
2888
	int			i;
2889
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2890
	PGresult   *res;
2891
	int			ntups;
B
Bruce Momjian 已提交
2892
	IndInfo    *indinfo;
2893

2894 2895
	int			i_indexreloid;
	int			i_indreloid;
2896 2897 2898 2899 2900 2901 2902
	int			i_indexrelname;
	int			i_indrelname;
	int			i_indamname;
	int			i_indproc;
	int			i_indkey;
	int			i_indclass;
	int			i_indisunique;
2903
	int			i_indisprimary;
2904
	int			i_indhaspred;
2905 2906

	/*
2907
	 * find all the user-defined indexes.
2908
	 *
2909
	 * Notice we skip indexes on system classes
2910 2911
	 *
	 * this is a 4-way join !!
2912 2913
	 *
	 * XXXX: Use LOJ
2914 2915
	 */

B
Hi, all  
Bruce Momjian 已提交
2916
	appendPQExpBuffer(query,
2917 2918 2919
					  "SELECT i.indexrelid as indexreloid, "
					  "i.indrelid as indreloid, "
					  "t1.relname as indexrelname, t2.relname as indrelname, "
2920
					  "i.indproc, i.indkey, i.indclass, "
2921 2922 2923 2924
					  "a.amname as indamname, i.indisunique, i.indisprimary, "
					  "length(i.indpred) > 0 as indhaspred "
					  "from pg_index i, pg_class t1, pg_class t2, pg_am a "
					  "WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid "
2925
					  "and t1.relam = a.oid and i.indexrelid > '%u'::oid "
2926
					  "and t2.relname !~ '^pg_' ",
2927
					  g_last_builtin_oid);
2928

2929 2930 2931
	if (g_fout->remoteVersion < 70100)
		appendPQExpBuffer(query, " and t2.relkind != 'l'");

B
Hi, all  
Bruce Momjian 已提交
2932
	res = PQexec(g_conn, query->data);
2933 2934 2935
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
2936
		write_msg(NULL, "query to obtain list of indexes failed: %s", PQerrorMessage(g_conn));
2937
		exit_nicely();
2938 2939 2940 2941
	}

	ntups = PQntuples(res);

2942
	*numIndexes = ntups;
2943 2944 2945

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

2946 2947
	memset((char *) indinfo, 0, ntups * sizeof(IndInfo));

2948 2949
	i_indexreloid = PQfnumber(res, "indexreloid");
	i_indreloid = PQfnumber(res, "indreloid");
2950 2951 2952 2953 2954 2955 2956
	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");
2957
	i_indisprimary = PQfnumber(res, "indisprimary");
2958
	i_indhaspred = PQfnumber(res, "indhaspred");
2959 2960 2961

	for (i = 0; i < ntups; i++)
	{
2962 2963
		indinfo[i].indexreloid = strdup(PQgetvalue(res, i, i_indexreloid));
		indinfo[i].indreloid = strdup(PQgetvalue(res, i, i_indreloid));
2964 2965 2966 2967
		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));
2968 2969 2970 2971 2972 2973
		parseNumericArray(PQgetvalue(res, i, i_indkey),
						  indinfo[i].indkey,
						  INDEX_MAX_KEYS);
		parseNumericArray(PQgetvalue(res, i, i_indclass),
						  indinfo[i].indclass,
						  INDEX_MAX_KEYS);
2974
		indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
2975
		indinfo[i].indisprimary = strdup(PQgetvalue(res, i, i_indisprimary));
2976
		indinfo[i].indhaspred = strdup(PQgetvalue(res, i, i_indhaspred));
2977 2978
	}
	PQclear(res);
2979 2980 2981

	destroyPQExpBuffer(query);

2982
	return indinfo;
2983 2984
}

B
Bruce,  
Bruce Momjian 已提交
2985
/*------------------------------------------------------------------
2986
 * dumpComments --
B
Bruce,  
Bruce Momjian 已提交
2987
 *
2988
 * This routine is used to dump any comments associated with the
B
Bruce,  
Bruce Momjian 已提交
2989 2990 2991
 * 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
2992 2993 2994 2995
 * to hand an oid to this routine which has not been commented.  Additional
 * dependencies can be passed for the comment, too --- this is needed for
 * VIEWs, whose comments are filed under the table OID but which are dumped
 * in order by their rule OID.
B
Bruce,  
Bruce Momjian 已提交
2996 2997 2998
 *------------------------------------------------------------------
*/

T
Tom Lane 已提交
2999
static void
3000 3001
dumpComment(Archive *fout, const char *target, const char *oid,
			const char *((*deps)[]))
3002 3003
{
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
3004
	PQExpBuffer query;
3005
	int			i_description;
B
Bruce,  
Bruce Momjian 已提交
3006

3007 3008 3009 3010
	/* Comments are SCHEMA not data */
	if (dataOnly)
		return;

B
Bruce,  
Bruce Momjian 已提交
3011 3012 3013 3014 3015 3016 3017 3018 3019
	/*** 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);
3020 3021
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
3022 3023
		write_msg(NULL, "query to get comment on oid %s failed: %s",
				   oid, PQerrorMessage(g_conn));
3024
		exit_nicely();
B
Bruce,  
Bruce Momjian 已提交
3025 3026 3027 3028
	}

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

3029 3030
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
3031
		i_description = PQfnumber(res, "description");
B
Bruce Momjian 已提交
3032
		resetPQExpBuffer(query);
3033
		appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
3034
		formatStringLiteral(query, PQgetvalue(res, 0, i_description), PASS_LFTAB);
3035
		appendPQExpBuffer(query, ";\n");
B
Bruce Momjian 已提交
3036

3037 3038
		ArchiveEntry(fout, oid, target, "COMMENT", deps,
					 query->data, "" /* Del */ ,
B
Bruce Momjian 已提交
3039
					 "" /* Copy */ , "" /* Owner */ , NULL, NULL);
B
Bruce Momjian 已提交
3040

B
Bruce,  
Bruce Momjian 已提交
3041 3042 3043 3044 3045
	}

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

	PQclear(res);
3046
	destroyPQExpBuffer(query);
B
Bruce,  
Bruce Momjian 已提交
3047 3048 3049
}

/*------------------------------------------------------------------
3050
 * dumpDBComment --
B
Bruce,  
Bruce Momjian 已提交
3051
 *
3052 3053
 * 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 已提交
3054 3055 3056 3057 3058
 * to dump the schema of the database, then this is the first
 * statement issued.
 *------------------------------------------------------------------
*/

3059
void
B
Bruce Momjian 已提交
3060
dumpDBComment(Archive *fout)
3061 3062
{
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
3063
	PQExpBuffer query;
3064
	int			i_oid;
B
Bruce,  
Bruce Momjian 已提交
3065 3066 3067 3068

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

	query = createPQExpBuffer();
3069
	appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = ");
3070
	formatStringLiteral(query, PQdb(g_conn), CONV_ALL);
B
Bruce,  
Bruce Momjian 已提交
3071 3072 3073 3074

	/*** Execute query ***/

	res = PQexec(g_conn, query->data);
3075 3076
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
3077 3078
		write_msg(NULL, "query to get database oid failed: %s",
				   PQerrorMessage(g_conn));
3079
		exit_nicely();
B
Bruce,  
Bruce Momjian 已提交
3080 3081 3082 3083
	}

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

3084 3085
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
3086 3087 3088
		i_oid = PQfnumber(res, "oid");
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "DATABASE %s", fmtId(PQdb(g_conn), force_quotes));
3089
		dumpComment(fout, query->data, PQgetvalue(res, 0, i_oid), NULL);
B
Bruce,  
Bruce Momjian 已提交
3090 3091 3092 3093 3094
	}

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

	PQclear(res);
3095
	destroyPQExpBuffer(query);
B
Bruce,  
Bruce Momjian 已提交
3096 3097
}

3098 3099
/*
 * dumpTypes
3100
 *	  writes out to fout the queries to recreate all the user-defined types
3101 3102 3103
 *
 */
void
B
Bruce Momjian 已提交
3104
dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
3105
		  TypeInfo *tinfo, int numTypes)
3106
{
3107
	int			i;
3108
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3109
	PQExpBuffer delq = createPQExpBuffer();
3110
	int			funcInd;
3111
	const char *((*deps)[]);
3112
	int			depIdx;
3113 3114 3115 3116

	for (i = 0; i < numTypes; i++)
	{
		/* skip all the builtin types */
3117
		if (atooid(tinfo[i].oid) <= g_last_builtin_oid)
3118 3119 3120 3121 3122 3123
			continue;

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

3124 3125 3126 3127
		/* skip undefined placeholder types */
		if (!tinfo[i].isDefined)
			continue;

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

3133 3134 3135
		deps = malloc(sizeof(char*) * 10);
		depIdx = 0;

3136 3137 3138 3139 3140 3141
		/*
		 * 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)
3142 3143
		{
			(*deps)[depIdx++] = strdup(finfo[funcInd].oid);
3144
			dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
3145
		}
3146 3147 3148

		funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
		if (funcInd != -1)
3149 3150
		{
			(*deps)[depIdx++] = strdup(finfo[funcInd].oid);
3151
			dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
3152
		}
3153

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

B
Hi, all  
Bruce Momjian 已提交
3157 3158
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
3159
						  "CREATE TYPE %s "
3160
						  "( internallength = %s, externallength = %s,",
3161 3162
						  fmtId(tinfo[i].typname, force_quotes),
						  tinfo[i].typlen,
3163 3164 3165 3166 3167 3168 3169 3170 3171 3172
						  tinfo[i].typprtlen);
		/* cannot combine these because fmtId uses static result area */
		appendPQExpBuffer(q, " input = %s,",
						  fmtId(tinfo[i].typinput, force_quotes));
		appendPQExpBuffer(q, " output = %s,",
						  fmtId(tinfo[i].typoutput, force_quotes));
		appendPQExpBuffer(q, " send = %s,",
						  fmtId(tinfo[i].typsend, force_quotes));
		appendPQExpBuffer(q, " receive = %s, default = ",
						  fmtId(tinfo[i].typreceive, force_quotes));
3173
		formatStringLiteral(q, tinfo[i].typdefault, CONV_ALL);
3174 3175 3176

		if (tinfo[i].isArray)
		{
3177
			char	   *elemType;
3178

3179
			elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
3180 3181
			if (elemType == NULL)
			{
3182
				write_msg(NULL, "notice: array type %s - type for elements (oid %s) is not dumped\n",
3183
						  tinfo[i].typname, tinfo[i].typelem);
3184 3185 3186
				continue;
			}

3187
			appendPQExpBuffer(q, ", element = %s, delimiter = ", elemType);
3188
			formatStringLiteral(q, tinfo[i].typdelim, CONV_ALL);
3189 3190

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

3193 3194 3195 3196 3197
		if (strcmp(tinfo[i].typalign, "c") == 0)
			appendPQExpBuffer(q, ", alignment = char");
		else if (strcmp(tinfo[i].typalign, "s") == 0)
			appendPQExpBuffer(q, ", alignment = int2");
		else if (strcmp(tinfo[i].typalign, "i") == 0)
3198 3199 3200 3201 3202 3203
			appendPQExpBuffer(q, ", alignment = int4");
		else if (strcmp(tinfo[i].typalign, "d") == 0)
			appendPQExpBuffer(q, ", alignment = double");

		if (strcmp(tinfo[i].typstorage, "p") == 0)
			appendPQExpBuffer(q, ", storage = plain");
3204
		else if (strcmp(tinfo[i].typstorage, "e") == 0)
3205
			appendPQExpBuffer(q, ", storage = external");
3206
		else if (strcmp(tinfo[i].typstorage, "x") == 0)
3207
			appendPQExpBuffer(q, ", storage = extended");
3208
		else if (strcmp(tinfo[i].typstorage, "m") == 0)
3209 3210
			appendPQExpBuffer(q, ", storage = main");

3211
		if (tinfo[i].passedbyvalue)
3212
			appendPQExpBuffer(q, ", passedbyvalue);\n");
3213
		else
B
Hi, all  
Bruce Momjian 已提交
3214
			appendPQExpBuffer(q, ");\n");
3215

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

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

		/*** Dump Type Comments ***/

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

B
Bruce,  
Bruce Momjian 已提交
3225
		appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo[i].typname, force_quotes));
3226
		dumpComment(fout, q->data, tinfo[i].oid, NULL);
3227
	}
3228 3229 3230

	destroyPQExpBuffer(q);
	destroyPQExpBuffer(delq);
3231 3232
}

3233 3234
/*
 * dumpProcLangs
B
Bruce Momjian 已提交
3235
 *		  writes out to fout the queries to recreate user-defined procedural languages
3236 3237 3238
 *
 */
void
B
Bruce Momjian 已提交
3239
dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
B
Bruce Momjian 已提交
3240
			  TypeInfo *tinfo, int numTypes)
3241
{
3242 3243
	PGresult   *res;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
3244 3245
	PQExpBuffer defqry = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
3246
	int			ntups;
B
Bruce Momjian 已提交
3247
	int			i_oid;
3248 3249 3250 3251
	int			i_lanname;
	int			i_lanpltrusted;
	int			i_lanplcallfoid;
	int			i_lancompiler;
3252
	Oid			lanoid;
3253 3254 3255
	char	   *lanname;
	char	   *lancompiler;
	const char *lanplcallfoid;
3256 3257 3258
	int			i,
				fidx;

B
Bruce Momjian 已提交
3259
	appendPQExpBuffer(query, "SELECT oid, * FROM pg_language "
3260 3261
					  "WHERE lanispl "
					  "ORDER BY oid");
B
Hi, all  
Bruce Momjian 已提交
3262
	res = PQexec(g_conn, query->data);
3263 3264 3265
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
3266 3267
		write_msg(NULL, "query to obtain list of procedural languages failed: %s",
				   PQerrorMessage(g_conn));
3268
		exit_nicely();
3269 3270 3271
	}
	ntups = PQntuples(res);

B
Bruce Momjian 已提交
3272 3273 3274 3275
	i_lanname = PQfnumber(res, "lanname");
	i_lanpltrusted = PQfnumber(res, "lanpltrusted");
	i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
	i_lancompiler = PQfnumber(res, "lancompiler");
B
Bruce Momjian 已提交
3276
	i_oid = PQfnumber(res, "oid");
3277

B
Bruce Momjian 已提交
3278 3279
	for (i = 0; i < ntups; i++)
	{
3280
		lanoid = atooid(PQgetvalue(res, i, i_oid));
3281 3282 3283
		if (lanoid <= g_last_builtin_oid)
			continue;

3284
		lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
3285 3286


3287 3288 3289 3290 3291 3292 3293
		for (fidx = 0; fidx < numFuncs; fidx++)
		{
			if (!strcmp(finfo[fidx].oid, lanplcallfoid))
				break;
		}
		if (fidx >= numFuncs)
		{
3294 3295
			write_msg(NULL, "handler procedure for procedural language %s not found\n",
					   PQgetvalue(res, i, i_lanname));
3296
			exit_nicely();
3297 3298 3299 3300
		}

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

3301 3302
		lanname = PQgetvalue(res, i, i_lanname);
		lancompiler = PQgetvalue(res, i, i_lancompiler);
3303

3304
		appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE ");
3305
		formatStringLiteral(delqry, lanname, CONV_ALL);
3306
		appendPQExpBuffer(delqry, ";\n");
3307

3308 3309 3310
		appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE ",
						  (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
						  "TRUSTED " : "");
3311
		formatStringLiteral(defqry, lanname, CONV_ALL);
3312 3313
		appendPQExpBuffer(defqry, " HANDLER %s LANCOMPILER ",
						  fmtId(finfo[fidx].proname, force_quotes));
3314
		formatStringLiteral(defqry, lancompiler, CONV_ALL);
3315
		appendPQExpBuffer(defqry, ";\n");
3316

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

3320 3321
		resetPQExpBuffer(defqry);
		resetPQExpBuffer(delqry);
3322 3323 3324 3325
	}

	PQclear(res);

3326 3327 3328
	destroyPQExpBuffer(query);
	destroyPQExpBuffer(defqry);
	destroyPQExpBuffer(delqry);
3329 3330
}

3331 3332
/*
 * dumpFuncs
3333
 *	  writes out to fout the queries to recreate all the user-defined functions
3334 3335 3336
 *
 */
void
B
Bruce Momjian 已提交
3337
dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs,
3338
		  TypeInfo *tinfo, int numTypes)
3339
{
3340
	int			i;
3341 3342 3343

	for (i = 0; i < numFuncs; i++)
		dumpOneFunc(fout, finfo, i, tinfo, numTypes);
3344 3345 3346 3347
}

/*
 * dumpOneFunc:
3348 3349
 *	  dump out only one function,  the index of which is given in the third
 *	argument
3350 3351 3352
 *
 */

3353
static void
B
Bruce Momjian 已提交
3354
dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
3355
			TypeInfo *tinfo, int numTypes)
3356
{
3357
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3358 3359
	PQExpBuffer fn = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
B
Bruce,  
Bruce Momjian 已提交
3360
	PQExpBuffer fnlist = createPQExpBuffer();
3361
	PQExpBuffer asPart = createPQExpBuffer();
3362
	char		func_lang[NAMEDATALEN + 1];
3363 3364
	PGresult   *res;
	int			nlangs;
3365
	int			j;
3366 3367
	int			i_lanname;
	char		query[256];
3368

B
Bruce Momjian 已提交
3369 3370 3371 3372
	char	   *listSep;
	char	   *listSepComma = ",";
	char	   *listSepNone = "";
	char	   *rettypename;
3373

3374
	if (finfo[i].dumped)
3375 3376 3377
		goto done;

	finfo[i].dumped = 1;
3378

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

3381 3382 3383 3384 3385
	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 已提交
3386
	{
3387
		write_msg(NULL, "query to get name of procedural language failed: %s", PQerrorMessage(g_conn));
3388
		exit_nicely();
B
Bruce Momjian 已提交
3389
	}
3390 3391 3392
	nlangs = PQntuples(res);

	if (nlangs != 1)
B
Bruce Momjian 已提交
3393
	{
3394
		write_msg(NULL, "procedural language for function %s not found\n", finfo[i].proname);
3395
		exit_nicely();
B
Bruce Momjian 已提交
3396 3397
	}

3398
	i_lanname = PQfnumber(res, "lanname");
3399

3400
	/*
B
Bruce Momjian 已提交
3401 3402
	 * See backend/commands/define.c for details of how the 'AS' clause is
	 * used.
3403 3404 3405
	 */
	if (strcmp(finfo[i].probin, "-") != 0)
	{
3406
		appendPQExpBuffer(asPart, "AS ");
3407
		formatStringLiteral(asPart, finfo[i].probin, CONV_ALL);
3408
		if (strcmp(finfo[i].prosrc, "-") != 0)
3409 3410
		{
			appendPQExpBuffer(asPart, ", ");
3411
			formatStringLiteral(asPart, finfo[i].prosrc, PASS_LFTAB);
3412
		}
3413 3414 3415 3416
	}
	else
	{
		if (strcmp(finfo[i].prosrc, "-") != 0)
3417 3418
		{
			appendPQExpBuffer(asPart, "AS ");
3419
			formatStringLiteral(asPart, finfo[i].prosrc, PASS_LFTAB);
3420
		}
3421 3422
	}

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

3425
	PQclear(res);
B
Bruce Momjian 已提交
3426

B
Bruce Momjian 已提交
3427 3428
	resetPQExpBuffer(fn);
	appendPQExpBuffer(fn, "%s (", fmtId(finfo[i].proname, force_quotes));
3429 3430
	for (j = 0; j < finfo[i].nargs; j++)
	{
B
Bruce Momjian 已提交
3431
		char	   *typname;
3432

3433
		typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j], zeroAsOpaque);
3434 3435
		if (typname == NULL)
		{
3436 3437
			write_msg(NULL, "WARNING: function \"%s\" not dumped\n",
					  finfo[i].proname);
3438

3439
			write_msg(NULL, "reason: data type name of argument %d (oid %s) not found\n",
3440
					   j, finfo[i].argtypes[j]);
3441
			goto done;
3442 3443
		}

B
Bruce Momjian 已提交
3444 3445 3446
		appendPQExpBuffer(fn, "%s%s",
						  (j > 0) ? "," : "",
						  typname);
B
Bruce,  
Bruce Momjian 已提交
3447
		appendPQExpBuffer(fnlist, "%s%s",
B
Bruce Momjian 已提交
3448 3449
						  (j > 0) ? "," : "",
						  typname);
3450
	}
B
Bruce Momjian 已提交
3451 3452 3453
	appendPQExpBuffer(fn, ")");

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

3456 3457 3458 3459
	rettypename = findTypeByOid(tinfo, numTypes, finfo[i].prorettype, zeroAsOpaque);

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

3463 3464
		write_msg(NULL, "reason: name of return data type (oid %s) not found\n",
				  finfo[i].prorettype);
3465
		goto done;
3466 3467
	}

B
Bruce Momjian 已提交
3468
	resetPQExpBuffer(q);
B
Bruce Momjian 已提交
3469
	appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data);
3470 3471
	appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ",
					  (finfo[i].retset) ? "SETOF " : "",
3472
					  rettypename,
3473
					  asPart->data);
3474
	formatStringLiteral(q, func_lang, CONV_ALL);
3475

B
Bruce Momjian 已提交
3476
	if (finfo[i].iscachable || finfo[i].isstrict)		/* OR in new attrs here */
3477
	{
3478 3479 3480
		appendPQExpBuffer(q, " WITH (");
		listSep = listSepNone;

B
Bruce Momjian 已提交
3481 3482
		if (finfo[i].iscachable)
		{
3483 3484 3485 3486
			appendPQExpBuffer(q, "%s iscachable", listSep);
			listSep = listSepComma;
		}

B
Bruce Momjian 已提交
3487 3488
		if (finfo[i].isstrict)
		{
3489 3490 3491 3492
			appendPQExpBuffer(q, "%s isstrict", listSep);
			listSep = listSepComma;
		}
		appendPQExpBuffer(q, " )");
3493 3494 3495 3496
	}

	appendPQExpBuffer(q, ";\n");

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

B
Bruce,  
Bruce Momjian 已提交
3500 3501 3502 3503 3504 3505
	/*** Dump Function Comments ***/

	resetPQExpBuffer(q);
	appendPQExpBuffer(q, "FUNCTION %s ",
					  fmtId(finfo[i].proname, force_quotes));
	appendPQExpBuffer(q, "( %s )", fnlist->data);
3506 3507 3508 3509 3510 3511 3512 3513
	dumpComment(fout, q->data, finfo[i].oid, NULL);

done:
	destroyPQExpBuffer(q);
	destroyPQExpBuffer(fn);
	destroyPQExpBuffer(delqry);
	destroyPQExpBuffer(fnlist);
	destroyPQExpBuffer(asPart);
3514 3515 3516 3517
}

/*
 * dumpOprs
3518
 *	  writes out to fout the queries to recreate all the user-defined operators
3519 3520
 *
 */
3521
void
B
Bruce Momjian 已提交
3522
dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
3523
		 TypeInfo *tinfo, int numTypes)
3524
{
B
Bruce Momjian 已提交
3525
	int			i;
3526
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3527
	PQExpBuffer delq = createPQExpBuffer();
3528 3529 3530 3531 3532 3533 3534 3535
	PQExpBuffer leftarg = createPQExpBuffer();
	PQExpBuffer rightarg = createPQExpBuffer();
	PQExpBuffer commutator = createPQExpBuffer();
	PQExpBuffer negator = createPQExpBuffer();
	PQExpBuffer restrictor = createPQExpBuffer();
	PQExpBuffer join = createPQExpBuffer();
	PQExpBuffer sort1 = createPQExpBuffer();
	PQExpBuffer sort2 = createPQExpBuffer();
3536 3537 3538

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

B
Hi, all  
Bruce Momjian 已提交
3541 3542 3543 3544 3545 3546 3547 3548 3549
		resetPQExpBuffer(leftarg);
		resetPQExpBuffer(rightarg);
		resetPQExpBuffer(commutator);
		resetPQExpBuffer(negator);
		resetPQExpBuffer(restrictor);
		resetPQExpBuffer(join);
		resetPQExpBuffer(sort1);
		resetPQExpBuffer(sort2);

3550
		/* skip all the builtin oids */
3551
		if (atooid(oprinfo[i].oid) <= g_last_builtin_oid)
3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567
			continue;

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

		/*
		 * right unary means there's a left arg and left unary means
		 * there's a right arg
		 */
		if (strcmp(oprinfo[i].oprkind, "r") == 0 ||
			strcmp(oprinfo[i].oprkind, "b") == 0)
		{
B
Bruce Momjian 已提交
3568 3569
			name = findTypeByOid(tinfo, numTypes,
								 oprinfo[i].oprleft, zeroAsOpaque);
3570 3571
			if (name == NULL)
			{
3572 3573 3574 3575
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprleft (oid %s) not found\n",
						  oprinfo[i].oprleft);
3576 3577
				continue;
			}
B
Bruce Momjian 已提交
3578
			appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ", name);
3579
		}
3580

3581 3582 3583
		if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
			strcmp(oprinfo[i].oprkind, "b") == 0)
		{
B
Bruce Momjian 已提交
3584 3585
			name = findTypeByOid(tinfo, numTypes,
								 oprinfo[i].oprright, zeroAsOpaque);
3586 3587
			if (name == NULL)
			{
3588 3589 3590 3591
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprright (oid %s) not found\n",
						  oprinfo[i].oprright);
3592 3593 3594
				continue;
			}
			appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ", name);
3595
		}
3596

B
Hi, all  
Bruce Momjian 已提交
3597
		if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
3598 3599 3600 3601
		{
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom);
			if (name == NULL)
			{
3602 3603 3604 3605
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprcom (oid %s) not found\n",
						  oprinfo[i].oprcom);
3606 3607 3608 3609
				continue;
			}
			appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ", name);
		}
3610

B
Hi, all  
Bruce Momjian 已提交
3611
		if (!(strcmp(oprinfo[i].oprnegate, "0") == 0))
3612 3613 3614 3615
		{
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate);
			if (name == NULL)
			{
3616 3617 3618 3619
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprnegate (oid %s) not found\n",
						  oprinfo[i].oprnegate);
3620 3621 3622 3623
				continue;
			}
			appendPQExpBuffer(negator, ",\n\tNEGATOR = %s ", name);
		}
3624

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

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

B
Hi, all  
Bruce Momjian 已提交
3631
		if (!(strcmp(oprinfo[i].oprlsortop, "0") == 0))
3632
		{
B
Bruce Momjian 已提交
3633
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprlsortop);
3634 3635
			if (name == NULL)
			{
3636 3637 3638 3639
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprlsortop (oid %s) not found\n",
						  oprinfo[i].oprlsortop);
3640 3641 3642 3643
				continue;
			}
			appendPQExpBuffer(sort1, ",\n\tSORT1 = %s ", name);
		}
3644

B
Hi, all  
Bruce Momjian 已提交
3645
		if (!(strcmp(oprinfo[i].oprrsortop, "0") == 0))
3646
		{
B
Bruce Momjian 已提交
3647
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprrsortop);
3648 3649
			if (name == NULL)
			{
3650 3651 3652 3653
				write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
						  oprinfo[i].oprname, oprinfo[i].oid);
				write_msg(NULL, "reason: oprrsortop (oid %s) not found\n",
						  oprinfo[i].oprrsortop);
3654 3655 3656 3657
				continue;
			}
			appendPQExpBuffer(sort2, ",\n\tSORT2 = %s ", name);
		}
3658

B
Bruce Momjian 已提交
3659 3660
		resetPQExpBuffer(delq);
		appendPQExpBuffer(delq, "DROP OPERATOR %s (%s", oprinfo[i].oprname,
B
Bruce Momjian 已提交
3661
		findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft, zeroAsOpaque));
B
Bruce Momjian 已提交
3662
		appendPQExpBuffer(delq, ", %s);\n",
B
Bruce Momjian 已提交
3663
						  findTypeByOid(tinfo, numTypes, oprinfo[i].oprright, zeroAsOpaque));
3664

B
Hi, all  
Bruce Momjian 已提交
3665 3666
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
3667 3668 3669 3670 3671 3672 3673 3674 3675
						  "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 已提交
3676
		  (strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
3677 3678 3679
						  join->data,
						  sort1->data,
						  sort2->data);
3680

B
Bruce Momjian 已提交
3681
		ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
B
Bruce Momjian 已提交
3682
				q->data, delq->data, "", oprinfo[i].usename, NULL, NULL);
3683
	}
3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694

	destroyPQExpBuffer(q);
	destroyPQExpBuffer(delq);
	destroyPQExpBuffer(leftarg);
	destroyPQExpBuffer(rightarg);
	destroyPQExpBuffer(commutator);
	destroyPQExpBuffer(negator);
	destroyPQExpBuffer(restrictor);
	destroyPQExpBuffer(join);
	destroyPQExpBuffer(sort1);
	destroyPQExpBuffer(sort2);
3695 3696 3697 3698
}

/*
 * dumpAggs
3699
 *	  writes out to fout the queries to create all the user-defined aggregates
3700 3701 3702
 *
 */
void
B
Bruce Momjian 已提交
3703
dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
3704
		 TypeInfo *tinfo, int numTypes)
3705
{
B
Bruce Momjian 已提交
3706
	int			i;
3707
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3708 3709
	PQExpBuffer delq = createPQExpBuffer();
	PQExpBuffer aggSig = createPQExpBuffer();
3710
	PQExpBuffer details = createPQExpBuffer();
3711 3712 3713

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

3716
		resetPQExpBuffer(details);
B
Hi, all  
Bruce Momjian 已提交
3717

3718
		/* skip all the builtin oids */
3719 3720 3721 3722 3723 3724 3725 3726 3727
		if ( oidle( atooid(agginfo[i].oid), g_last_builtin_oid) )
			continue;

		resetPQExpBuffer(aggSig);
		appendPQExpBuffer(aggSig, "%s(%s)", agginfo[i].aggname,
						  findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsOpaque + useBaseTypeName));

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

3731
			resetPQExpBuffer(q);
3732
			appendPQExpBuffer(q, "-- WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
3733 3734 3735
									aggSig->data);
			ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
					q->data, "" /* Del */, "", agginfo[i].usename, NULL, NULL);
3736
			continue;
3737
		}
3738

3739 3740 3741
		name = findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsAny + useBaseTypeName);
		if (name == NULL)
		{
3742 3743 3744 3745 3746 3747 3748 3749 3750 3751
			write_msg(NULL, "WARNING: aggregate function \"%s\" (oid %s) not dumped\n",
					  agginfo[i].aggname, agginfo[i].oid);
			write_msg(NULL, "reason: aggbasetype (oid %s) not found\n",
					  agginfo[i].aggbasetype);

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

3756 3757 3758
		name = findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype, zeroAsOpaque + useBaseTypeName);
		if (name == NULL)
		{
3759 3760 3761 3762 3763 3764 3765 3766 3767 3768
			write_msg(NULL, "WARNING: aggregate function \"%s\" (oid %s) not dumped\n",
					  agginfo[i].aggname, agginfo[i].oid);
			write_msg(NULL, "reason: aggtranstype (oid %s) not found\n",
					  agginfo[i].aggtranstype);

			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "-- WARNING: aggregate function \"%s\" (oid %s) not dumped\n", agginfo[i].aggname, agginfo[i].oid);
			appendPQExpBuffer(q, "-- reason: aggtranstype (oid %s) not found\n", agginfo[i].aggtranstype);
			ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
						 q->data, "" /* Del */, "", agginfo[i].usename, NULL, NULL);
3769 3770
			continue;
		}
3771 3772
		appendPQExpBuffer(details,
						  "SFUNC = %s, STYPE = %s",
3773
						  agginfo[i].aggtransfn, name);
3774

3775
		if (agginfo[i].agginitval)
3776 3777
		{
			appendPQExpBuffer(details, ", INITCOND = ");
3778
			formatStringLiteral(details, agginfo[i].agginitval, CONV_ALL);
3779
		}
3780

B
Hi, all  
Bruce Momjian 已提交
3781
		if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
3782 3783
			appendPQExpBuffer(details, ", FINALFUNC = %s",
							  agginfo[i].aggfinalfn);
3784

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

B
Hi, all  
Bruce Momjian 已提交
3788
		resetPQExpBuffer(q);
3789
		appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
3790
						  agginfo[i].aggname,
3791
						  details->data);
3792

B
Bruce Momjian 已提交
3793
		ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
B
Bruce Momjian 已提交
3794
				q->data, delq->data, "", agginfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
3795 3796 3797 3798

		/*** Dump Aggregate Comments ***/

		resetPQExpBuffer(q);
3799
		appendPQExpBuffer(q, "AGGREGATE %s %s", agginfo[i].aggname,
3800
						  findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsOpaque + useBaseTypeName));
3801
		dumpComment(fout, q->data, agginfo[i].oid, NULL);
3802
	}
3803 3804 3805 3806 3807

	destroyPQExpBuffer(q);
	destroyPQExpBuffer(delq);
	destroyPQExpBuffer(aggSig);
	destroyPQExpBuffer(details);
3808 3809
}

3810 3811 3812 3813 3814
/*
 * These are some support functions to fix the acl problem of pg_dump
 *
 * Matthew C. Aycock 12/02/97
 */
3815 3816 3817

/* Append a keyword to a keyword list, inserting comma if needed.
 * Caller must make aclbuf big enough for all possible keywords.
3818
 */
3819
static void
B
Bruce Momjian 已提交
3820
AddAcl(char *aclbuf, const char *keyword)
3821
{
3822 3823 3824
	if (*aclbuf)
		strcat(aclbuf, ",");
	strcat(aclbuf, keyword);
3825
}
3826

3827
/*
3828
 * This will take a string of 'arwR' and return a malloced,
3829 3830
 * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
 */
V
Vadim B. Mikheev 已提交
3831
static char *
3832
GetPrivileges(const char *s)
3833
{
3834
	char		aclbuf[100];
3835

3836
	aclbuf[0] = '\0';
3837

B
Bruce Momjian 已提交
3838
	if (strchr(s, 'a'))
3839
		AddAcl(aclbuf, "INSERT");
3840

B
Bruce Momjian 已提交
3841
	if (strchr(s, 'w'))
3842
		AddAcl(aclbuf, "UPDATE,DELETE");
B
Bruce Momjian 已提交
3843 3844

	if (strchr(s, 'r'))
3845
		AddAcl(aclbuf, "SELECT");
3846

3847
	if (strchr(s, 'R'))
3848
		AddAcl(aclbuf, "RULE");
3849

3850 3851 3852
	/* Special-case when they're all there */
	if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
		return strdup("ALL");
3853

3854
	return strdup(aclbuf);
3855
}
3856

B
Bruce Momjian 已提交
3857
/*
B
Bruce Momjian 已提交
3858
 * The name says it all; a function to append a string is the dest
B
Bruce Momjian 已提交
3859 3860
 * is big enough. If not, it does a realloc.
 */
B
Bruce Momjian 已提交
3861 3862
static void
strcatalloc(char **dest, int *dSize, char *src)
B
Bruce Momjian 已提交
3863
{
B
Bruce Momjian 已提交
3864 3865 3866 3867 3868 3869 3870 3871 3872 3873
	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 已提交
3874 3875


B
Bruce Momjian 已提交
3876 3877
/*
 * dumpACL:
3878 3879
 *	  Write out grant/revoke information
 *	  Called for sequences and tables
B
Bruce Momjian 已提交
3880 3881
 */

3882
static void
B
Bruce Momjian 已提交
3883
dumpACL(Archive *fout, TableInfo tbinfo)
B
Bruce Momjian 已提交
3884
{
B
Bruce Momjian 已提交
3885 3886
	const char *acls = tbinfo.relacl;
	char	   *aclbuf,
B
Bruce Momjian 已提交
3887 3888 3889
			   *tok,
			   *eqpos,
			   *priv;
3890
	char	   *objoid;
B
Bruce Momjian 已提交
3891
	char	   *sql;
B
Bruce Momjian 已提交
3892
	char		tmp[1024];
B
Bruce Momjian 已提交
3893
	int			sSize = 4096;
3894 3895 3896 3897

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

B
Bruce Momjian 已提交
3898 3899 3900
	/*
	 * Allocate a larginsh buffer for the output SQL.
	 */
B
Bruce Momjian 已提交
3901
	sql = (char *) malloc(sSize);
B
Bruce Momjian 已提交
3902

B
Bruce Momjian 已提交
3903 3904 3905
	/*
	 * Revoke Default permissions for PUBLIC. Is this actually necessary,
	 * or is it just a waste of time?
3906
	 */
B
Bruce Momjian 已提交
3907
	sprintf(sql, "REVOKE ALL on %s from PUBLIC;\n",
3908
			fmtId(tbinfo.relname, force_quotes));
3909 3910 3911

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

3913 3914
	/* Scan comma-separated ACL items */
	for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
3915
	{
3916

B
Bruce Momjian 已提交
3917 3918 3919
		/*
		 * Token may start with '{' and/or '"'.  Actually only the start
		 * of the string should have '{', but we don't verify that.
3920 3921 3922 3923 3924 3925 3926 3927
		 */
		if (*tok == '{')
			tok++;
		if (*tok == '"')
			tok++;

		/* User name is string up to = in tok */
		eqpos = strchr(tok, '=');
B
Bruce Momjian 已提交
3928
		if (!eqpos)
B
Bruce Momjian 已提交
3929
		{
3930 3931 3932
			write_msg(NULL, "could not parse ACL list ('%s') for relation %s\n",
					  acls, tbinfo.relname);
			exit_nicely();
B
Bruce Momjian 已提交
3933 3934
		}

B
Bruce Momjian 已提交
3935 3936 3937 3938
		/*
		 * Parse the privileges (right-hand side).	Skip if there are
		 * none.
		 */
3939 3940
		priv = GetPrivileges(eqpos + 1);
		if (*priv)
3941
		{
B
Bruce Momjian 已提交
3942
			sprintf(tmp, "GRANT %s on %s to ",
3943
					priv, fmtId(tbinfo.relname, force_quotes));
B
Bruce Momjian 已提交
3944
			strcatalloc(&sql, &sSize, tmp);
B
Bruce Momjian 已提交
3945 3946 3947

			/*
			 * Note: fmtId() can only be called once per printf, so don't
3948 3949 3950 3951 3952
			 * try to merge printing of username into the above printf.
			 */
			if (eqpos == tok)
			{
				/* Empty left-hand side means "PUBLIC" */
B
Bruce Momjian 已提交
3953
				strcatalloc(&sql, &sSize, "PUBLIC;\n");
3954
			}
3955
			else
3956 3957
			{
				*eqpos = '\0';	/* it's ok to clobber aclbuf */
3958
				if (strncmp(tok, "group ", strlen("group ")) == 0)
B
Bruce Momjian 已提交
3959
					sprintf(tmp, "GROUP %s;\n",
3960 3961
							fmtId(tok + strlen("group "), force_quotes));
				else
B
Bruce Momjian 已提交
3962 3963
					sprintf(tmp, "%s;\n", fmtId(tok, force_quotes));
				strcatalloc(&sql, &sSize, tmp);
3964
			}
3965
		}
3966
		free(priv);
B
Bruce Momjian 已提交
3967
	}
3968 3969

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

3971 3972 3973 3974 3975 3976
	if (tbinfo.viewdef != NULL)
		objoid = tbinfo.viewoid;
	else
		objoid = tbinfo.oid;

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

B
Bruce Momjian 已提交
3978 3979
}

3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034
static void
_dumpTableAttr70(Archive *fout, TableInfo *tblinfo, int i, int j, PQExpBuffer q)
{
	int32				tmp_typmod;
	int					precision;
	int					scale;

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

		appendPQExpBuffer(q, "character");
		if (len > 1)
			appendPQExpBuffer(q, "(%d)",
					 tblinfo[i].atttypmod[j] - VARHDRSZ);
	}
	else if (!strcmp(tblinfo[i].typnames[j], "varchar"))
	{
		appendPQExpBuffer(q, "character varying");
		if (tblinfo[i].atttypmod[j] != -1)
		{
			appendPQExpBuffer(q, "(%d)",
					 tblinfo[i].atttypmod[j] - VARHDRSZ);
		}
	}
	else if (!strcmp(tblinfo[i].typnames[j], "numeric"))
	{
		appendPQExpBuffer(q, "numeric");
		if (tblinfo[i].atttypmod[j] != -1)
		{
			tmp_typmod = tblinfo[i].atttypmod[j] - VARHDRSZ;
			precision = (tmp_typmod >> 16) & 0xffff;
			scale = tmp_typmod & 0xffff;
			appendPQExpBuffer(q, "(%d,%d)",
							  precision, scale);
		}
	}

	/*
	 * char is an internal single-byte data type; Let's
	 * make sure we force it through with quotes. - thomas
	 * 1998-12-13
	 */
	else if (!strcmp(tblinfo[i].typnames[j], "char"))
	{
		appendPQExpBuffer(q, "%s",
					fmtId(tblinfo[i].typnames[j], true));
	}
	else
	{
		appendPQExpBuffer(q, "%s",
				   fmtId(tblinfo[i].typnames[j], false));
	}
}
4035

4036 4037
/*
 * dumpTables:
4038
 *	  write out to fout all the user-define tables
4039
 */
4040

4041
void
B
Bruce Momjian 已提交
4042
dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
4043
		   IndInfo *indinfo, int numIndexes,
4044 4045
		   InhInfo *inhinfo, int numInherits,
		   TypeInfo *tinfo, int numTypes, const char *tablename,
B
Bruce Momjian 已提交
4046 4047
		   const bool aclsSkip, const bool oids,
		   const bool schemaOnly, const bool dataOnly)
4048
{
4049 4050
	int			i,
				j,
B
Bruce Momjian 已提交
4051
				k;
4052
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
4053
	PQExpBuffer delq = createPQExpBuffer();
4054
	char	   *serialSeq = NULL;		/* implicit sequence name created
B
Bruce Momjian 已提交
4055 4056 4057 4058
										 * by SERIAL datatype */
	const char *serialSeqSuffix = "_id_seq";	/* suffix for implicit
												 * SERIAL sequences */
	char	  **parentRels;		/* list of names of parent relations */
4059
	int			numParents;
B
Bruce Momjian 已提交
4060
	int			actual_atts;	/* number of attrs in this CREATE statment */
4061
	char	   *reltypename;
4062
	char	   *objoid;
4063
	const char *((*commentDeps)[]);
4064

V
Vadim B. Mikheev 已提交
4065
	/* First - dump SEQUENCEs */
4066
	if (tablename && strlen(tablename) > 0)
B
Bruce Momjian 已提交
4067 4068 4069 4070 4071
	{
		serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
		strcpy(serialSeq, tablename);
		strcat(serialSeq, serialSeqSuffix);
	}
V
Vadim B. Mikheev 已提交
4072 4073 4074 4075
	for (i = 0; i < numTables; i++)
	{
		if (!(tblinfo[i].sequence))
			continue;
B
Bruce Momjian 已提交
4076
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
B
Bruce Momjian 已提交
4077
			|| (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
V
Vadim B. Mikheev 已提交
4078
		{
B
Bruce Momjian 已提交
4079
			/* becomeUser(fout, tblinfo[i].usename); */
4080
			dumpSequence(fout, tblinfo[i], schemaOnly, dataOnly);
4081
			if (!aclsSkip)
B
Bruce Momjian 已提交
4082
				dumpACL(fout, tblinfo[i]);
V
Vadim B. Mikheev 已提交
4083 4084
		}
	}
B
Bruce Momjian 已提交
4085
	if (tablename)
B
Bruce Momjian 已提交
4086
		free(serialSeq);
4087

4088 4089
	for (i = 0; i < numTables; i++)
	{
4090
		if (tblinfo[i].sequence)/* already dumped */
V
Vadim B. Mikheev 已提交
4091
			continue;
4092

4093
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename)) || (strlen(tablename) == 0))
4094 4095
		{

4096 4097
			resetPQExpBuffer(delq);
			resetPQExpBuffer(q);
4098

4099 4100 4101 4102
			/* Use the view definition if there is one */
			if (tblinfo[i].viewdef != NULL)
			{
				reltypename = "VIEW";
4103
				objoid = tblinfo[i].viewoid;
4104
				appendPQExpBuffer(delq, "DROP VIEW %s;\n", fmtId(tblinfo[i].relname, force_quotes));
4105
				appendPQExpBuffer(q, "CREATE VIEW %s as %s\n", fmtId(tblinfo[i].relname, force_quotes), tblinfo[i].viewdef);
4106 4107 4108
				commentDeps = malloc(sizeof(char*) * 2);
				(*commentDeps)[0] = strdup(objoid);
				(*commentDeps)[1] = NULL; /* end of list */
4109 4110
			}
			else
4111
			{
4112
				reltypename = "TABLE";
4113
				objoid = tblinfo[i].oid;
4114
				commentDeps = NULL;
4115 4116
				parentRels = tblinfo[i].parentRels;
				numParents = tblinfo[i].numParents;
B
Bruce Momjian 已提交
4117

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

4120 4121 4122 4123 4124 4125
				appendPQExpBuffer(q, "CREATE TABLE %s (\n\t", fmtId(tblinfo[i].relname, force_quotes));
				actual_atts = 0;
				for (j = 0; j < tblinfo[i].numatts; j++)
				{
					/* Is this one of the table's own attrs ? */
					if (tblinfo[i].inhAttrs[j] == 0)
4126
					{
4127 4128 4129 4130 4131
						/* Format properly if not first attr */
						if (actual_atts > 0)
							appendPQExpBuffer(q, ",\n\t");

						/* Attr name & type */
4132 4133 4134 4135 4136 4137 4138 4139
						appendPQExpBuffer(q, "%s ", fmtId(tblinfo[i].attnames[j], force_quotes));

						if (g_fout->remoteVersion >= 70100)
						{
							appendPQExpBuffer(q, "%s", tblinfo[i].atttypedefns[j]);
						} else {
							_dumpTableAttr70(fout, tblinfo, i, j, q);
						}
4140 4141

						/* Default value */
4142
						if (tblinfo[i].adef_expr[j] != NULL && tblinfo[i].inhAttrDef[j] == 0)
4143
							appendPQExpBuffer(q, " DEFAULT %s",
B
Bruce Momjian 已提交
4144
											  tblinfo[i].adef_expr[j]);
4145 4146

						/* Not Null constraint */
4147
						if (tblinfo[i].notnull[j] && tblinfo[i].inhNotNull[j] == 0)
4148 4149 4150 4151
							appendPQExpBuffer(q, " NOT NULL");

						actual_atts++;
					}
4152
				}
B
Hi all  
Bruce Momjian 已提交
4153

4154 4155


4156 4157 4158 4159 4160 4161 4162
				/* put the CONSTRAINTS inside the table def */
				for (k = 0; k < tblinfo[i].ncheck; k++)
				{
					if (actual_atts + k > 0)
						appendPQExpBuffer(q, ",\n\t");

					appendPQExpBuffer(q, "%s",
B
Bruce Momjian 已提交
4163
									  tblinfo[i].check_expr[k]);
4164
				}
4165

4166 4167
				/* Primary Key */
				if (tblinfo[i].pkIndexOid != NULL)
4168
				{
B
Bruce Momjian 已提交
4169
					PQExpBuffer consDef;
4170 4171

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

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

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

B
Bruce Momjian 已提交
4188
					if ((actual_atts + tblinfo[i].ncheck) > 0)
4189
						appendPQExpBuffer(q, ",\n\t");
4190 4191 4192 4193

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

					destroyPQExpBuffer(consDef);
4194
				}
B
Bruce Momjian 已提交
4195

4196

4197
				appendPQExpBuffer(q, "\n)");
4198

4199
				if (numParents > 0)
B
Hi all  
Bruce Momjian 已提交
4200
				{
4201
					appendPQExpBuffer(q, "\nINHERITS (");
4202 4203 4204
					for (k = 0; k < numParents; k++)
					{
						appendPQExpBuffer(q, "%s%s",
B
Bruce Momjian 已提交
4205 4206
										  (k > 0) ? ", " : "",
									 fmtId(parentRels[k], force_quotes));
4207 4208
					}
					appendPQExpBuffer(q, ")");
B
Hi all  
Bruce Momjian 已提交
4209 4210
				}

4211 4212
				appendPQExpBuffer(q, ";\n");
			}
B
Bruce Momjian 已提交
4213

B
Bruce Momjian 已提交
4214 4215
			if (!dataOnly)
			{
4216

4217
				ArchiveEntry(fout, objoid, tblinfo[i].relname,
B
Bruce Momjian 已提交
4218 4219
							 reltypename, NULL, q->data, delq->data, "", tblinfo[i].usename,
							 NULL, NULL);
B
Bruce Momjian 已提交
4220

4221 4222 4223 4224
				if (!aclsSkip)
					dumpACL(fout, tblinfo[i]);

			}
4225

4226
			/* Dump Field Comments */
B
Bruce,  
Bruce Momjian 已提交
4227

4228 4229
			for (j = 0; j < tblinfo[i].numatts; j++)
			{
B
Bruce,  
Bruce Momjian 已提交
4230 4231 4232 4233
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "COLUMN %s", fmtId(tblinfo[i].relname, force_quotes));
				appendPQExpBuffer(q, ".");
				appendPQExpBuffer(q, "%s", fmtId(tblinfo[i].attnames[j], force_quotes));
4234
				dumpComment(fout, q->data, tblinfo[i].attoids[j], NULL);
B
Bruce,  
Bruce Momjian 已提交
4235
			}
4236

B
Bruce,  
Bruce Momjian 已提交
4237
			/* Dump Table Comments */
4238

B
Bruce,  
Bruce Momjian 已提交
4239
			resetPQExpBuffer(q);
4240
			appendPQExpBuffer(q, "%s %s", reltypename, fmtId(tblinfo[i].relname, force_quotes));
4241
			dumpComment(fout, q->data, tblinfo[i].oid, commentDeps);
4242

4243 4244
		}
	}
4245 4246 4247

	destroyPQExpBuffer(q);
	destroyPQExpBuffer(delq);
4248 4249
}

B
Bruce Momjian 已提交
4250 4251
static PQExpBuffer
getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo)
4252
{
B
Bruce Momjian 已提交
4253 4254
	PQExpBuffer pkBuf = createPQExpBuffer();
	int			k;
4255 4256

	appendPQExpBuffer(pkBuf, "Constraint %s Primary Key (",
B
Bruce Momjian 已提交
4257
					  tblInfo->primary_key_name);
4258 4259 4260

	for (k = 0; k < INDEX_MAX_KEYS; k++)
	{
4261 4262
		int			indkey;
		const char *attname;
4263 4264 4265 4266

		indkey = atoi(indInfo->indkey[k]);
		if (indkey == InvalidAttrNumber)
			break;
4267
		attname = getAttrName(indkey, tblInfo);
4268 4269

		appendPQExpBuffer(pkBuf, "%s%s",
B
Bruce Momjian 已提交
4270 4271
						  (k == 0) ? "" : ", ",
						  fmtId(attname, force_quotes));
4272 4273 4274 4275 4276 4277 4278
	}

	appendPQExpBuffer(pkBuf, ")");

	return pkBuf;
}

4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307
/*
 * getAttrName: extract the correct name for an attribute
 *
 * The array tblInfo->attnames[] only provides names of user attributes;
 * if a system attribute number is supplied, we have to fake it.
 * We also do a little bit of bounds checking for safety's sake.
 */
static const char *
getAttrName(int attrnum, TableInfo *tblInfo)
{
	if (attrnum > 0 && attrnum <= tblInfo->numatts)
		return tblInfo->attnames[attrnum-1];
	switch (attrnum)
	{
		case SelfItemPointerAttributeNumber:
			return "ctid";
		case ObjectIdAttributeNumber:
			return "oid";
		case MinTransactionIdAttributeNumber:
			return "xmin";
		case MinCommandIdAttributeNumber:
			return "cmin";
		case MaxTransactionIdAttributeNumber:
			return "xmax";
		case MaxCommandIdAttributeNumber:
			return "cmax";
		case TableOidAttributeNumber:
			return "tableoid";
	}
4308 4309
	write_msg(NULL, "getAttrName(): invalid column number %d for table %s\n",
			   attrnum, tblInfo->relname);
4310
	exit_nicely();
4311 4312 4313
	return NULL;				/* keep compiler quiet */
}

4314
/*
4315
 * dumpIndexes:
4316
 *	  write out to fout all the user-defined indexes
4317
 */
4318
void
4319
dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes,
4320
			TableInfo *tblinfo, int numTables, const char *tablename)
4321
{
4322 4323 4324
	int			i,
				k;
	int			tableInd;
4325
	PQExpBuffer attlist = createPQExpBuffer();
4326 4327 4328 4329
	PQExpBuffer q = createPQExpBuffer();
	PQExpBuffer delq = createPQExpBuffer();
	PQExpBuffer id1 = createPQExpBuffer();
	PQExpBuffer id2 = createPQExpBuffer();
B
Bruce Momjian 已提交
4330 4331 4332
	char	   *classname[INDEX_MAX_KEYS];
	char	   *funcname;		/* the name of the function to comput the
								 * index key from */
4333
	int			indclass;
4334 4335
	int			nclass;
	PGresult   *res;
4336

4337
	for (i = 0; i < numIndexes; i++)
4338 4339
	{
		tableInd = findTableByName(tblinfo, numTables,
4340 4341 4342
								   indinfo[i].indrelname);
		if (tableInd < 0)
		{
4343 4344
			write_msg(NULL, "dumpIndexes(): failed sanity check, table %s was not found\n",
					   indinfo[i].indrelname);
4345
			exit_nicely();
4346
		}
4347

4348 4349 4350
		/* Handle PK indexes */
		if (strcmp(indinfo[i].indisprimary, "t") == 0)
		{
4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367
#if 0
			/* PK: Enable this code when ALTER TABLE supports PK constraints. */

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

			resetPQExpBuffer(attlist);

			appendPQExpBuffer(attlist, "Alter Table %s Add %s;",
							  fmtId(tblinfo[tableInd].relname, force_quotes),
							  consDef->data);

			ArchiveEntry(fout, indinfo[i].oid, tblinfo[tableInd].primary_key_name,
						 "CONSTRAINT", NULL, attlist->data, "",
						 "", tblinfo[tableInd].usename, NULL, NULL);

			destroyPQExpBuffer(consDef);
#endif
B
Bruce Momjian 已提交
4368 4369 4370 4371 4372

			/*
			 * Don't need to do anything else for this system-generated
			 * index
			 */
4373 4374 4375 4376
			continue;
		}


4377 4378 4379 4380
		if (strcmp(indinfo[i].indproc, "0") == 0)
			funcname = NULL;
		else
		{
B
Bruce Momjian 已提交
4381
			int			numFuncs;
4382 4383 4384 4385 4386 4387 4388

			/*
			 * 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 已提交
4389 4390
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
4391 4392 4393
							  "SELECT proname from pg_proc "
							  "where pg_proc.oid = '%s'::oid",
							  indinfo[i].indproc);
B
Hi, all  
Bruce Momjian 已提交
4394
			res = PQexec(g_conn, q->data);
4395 4396
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
4397 4398
				write_msg(NULL, "query to get function name of oid %s failed: %s",
						  indinfo[i].indproc, PQerrorMessage(g_conn));
4399
				exit_nicely();
4400
			}
4401 4402 4403

			/* Sanity: Check we got only one tuple */
			numFuncs = PQntuples(res);
B
Bruce Momjian 已提交
4404 4405
			if (numFuncs != 1)
			{
4406 4407
				write_msg(NULL, "query to get function name of oid %s returned %d rows; expected 1\n",
						  indinfo[i].indproc, numFuncs);
4408
				exit_nicely();
4409 4410
			}

B
Bruce Momjian 已提交
4411
			funcname = strdup(PQgetvalue(res, 0, PQfnumber(res, "proname")));
4412 4413 4414 4415 4416 4417
			PQclear(res);
		}

		/* convert opclass oid(s) into names */
		for (nclass = 0; nclass < INDEX_MAX_KEYS; nclass++)
		{
B
Bruce Momjian 已提交
4418
			int			numRows;
4419

4420 4421 4422
			indclass = atoi(indinfo[i].indclass[nclass]);
			if (indclass == 0)
				break;
B
Hi, all  
Bruce Momjian 已提交
4423 4424
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
4425 4426 4427
							  "SELECT opcname from pg_opclass "
							  "where pg_opclass.oid = '%u'::oid",
							  indclass);
B
Hi, all  
Bruce Momjian 已提交
4428
			res = PQexec(g_conn, q->data);
4429 4430
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
4431 4432
				write_msg(NULL, "query to get operator class name of oid %u failed: %s",
						  indclass, PQerrorMessage(g_conn));
4433
				exit_nicely();
4434
			}
4435 4436 4437

			/* Sanity: Check we got only one tuple */
			numRows = PQntuples(res);
B
Bruce Momjian 已提交
4438 4439
			if (numRows != 1)
			{
4440 4441
				write_msg(NULL, "query to get operator class name of oid %u returned %d rows; expected 1\n",
						  indclass, numRows);
4442
				exit_nicely();
4443 4444
			}

B
Bruce Momjian 已提交
4445
			classname[nclass] = strdup(PQgetvalue(res, 0, PQfnumber(res, "opcname")));
4446 4447 4448 4449 4450
			PQclear(res);
		}

		if (funcname && nclass != 1)
		{
4451 4452
			write_msg(NULL, "There must be exactly one OpClass for functional index \"%s\".\n",
					  indinfo[i].indexrelname);
4453
			exit_nicely();
4454 4455 4456
		}

		/* convert attribute numbers into attribute list */
B
Hi, all  
Bruce Momjian 已提交
4457 4458
		resetPQExpBuffer(attlist);
		for (k = 0; k < INDEX_MAX_KEYS; k++)
4459
		{
4460 4461
			int			indkey;
			const char *attname;
4462 4463

			indkey = atoi(indinfo[i].indkey[k]);
B
Bruce Momjian 已提交
4464
			if (indkey == InvalidAttrNumber)
4465
				break;
4466
			attname = getAttrName(indkey, &tblinfo[tableInd]);
4467
			if (funcname)
B
Hi, all  
Bruce Momjian 已提交
4468
				appendPQExpBuffer(attlist, "%s%s",
4469 4470
								  (k == 0) ? "" : ", ",
								  fmtId(attname, force_quotes));
4471 4472 4473 4474
			else
			{
				if (k >= nclass)
				{
4475
					write_msg(NULL, "no operator class found for column \"%s\" of index \"%s\"\n",
4476
							attname, indinfo[i].indexrelname);
4477
					exit_nicely();
4478
				}
B
Hi, all  
Bruce Momjian 已提交
4479 4480 4481 4482 4483
				resetPQExpBuffer(id1);
				resetPQExpBuffer(id2);
				appendPQExpBuffer(id1, fmtId(attname, force_quotes));
				appendPQExpBuffer(id2, fmtId(classname[k], force_quotes));
				appendPQExpBuffer(attlist, "%s%s %s",
4484 4485
								  (k == 0) ? "" : ", ",
								  id1->data, id2->data);
4486 4487 4488 4489
				free(classname[k]);
			}
		}

B
Bruce Momjian 已提交
4490
		if (!tablename || (strcmp(indinfo[i].indrelname, tablename) == 0) || (strlen(tablename) == 0))
4491
		{
B
Hi, all  
Bruce Momjian 已提交
4492 4493 4494 4495
			resetPQExpBuffer(id1);
			resetPQExpBuffer(id2);
			appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
			appendPQExpBuffer(id2, fmtId(indinfo[i].indrelname, force_quotes));
4496

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

B
Bruce Momjian 已提交
4500 4501
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "CREATE %s INDEX %s on %s using %s (",
B
Bruce Momjian 已提交
4502 4503 4504 4505
			  (strcmp(indinfo[i].indisunique, "t") == 0) ? "UNIQUE" : "",
							  id1->data,
							  id2->data,
							  indinfo[i].indamname);
4506 4507
			if (funcname)
			{
4508
				/* need 2 printf's here cuz fmtId has static return area */
B
Bruce Momjian 已提交
4509
				appendPQExpBuffer(q, " %s", fmtId(funcname, false));
4510
				appendPQExpBuffer(q, " (%s) %s )", attlist->data,
B
Bruce Momjian 已提交
4511
								  fmtId(classname[0], force_quotes));
4512 4513 4514 4515
				free(funcname);
				free(classname[0]);
			}
			else
4516 4517
				appendPQExpBuffer(q, " %s )", attlist->data);
				
4518
			if (strcmp(indinfo[i].indhaspred, "t") == 0)
4519
			{
4520
				/* There is an index predicate, so fetch and dump it */
4521 4522 4523
				int numRows;
				PQExpBuffer pred = createPQExpBuffer();
				
4524 4525
				appendPQExpBuffer(pred, "SELECT pg_get_expr(indpred,indrelid) as pred FROM pg_index WHERE indexrelid = %s",
								  indinfo[i].indexreloid);
4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550
				res = PQexec(g_conn, pred->data);
				if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
				{
					fprintf(stderr, "dumpIndices(): SELECT (indpred) failed.  "
							"Explanation from backend: '%s'.\n",
							PQerrorMessage(g_conn));
					exit_nicely();
				}
	
				/* Sanity: Check we got only one tuple */
				numRows = PQntuples(res);
				if (numRows != 1)
				{
					fprintf(stderr, "dumpIndices(): SELECT (indpred) for index %s returned %d tuples. Expected 1.\n",
							indinfo[i].indrelname, numRows);
					exit_nicely();
				}
	
				appendPQExpBuffer(q, " WHERE %s",
								  PQgetvalue(res, 0, PQfnumber(res, "pred")));

				PQclear(res);
				destroyPQExpBuffer( pred );
			}
			appendPQExpBuffer(q, ";\n");
B
Bruce,  
Bruce Momjian 已提交
4551

4552 4553 4554 4555 4556
			/*
			 * 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.
			 */
B
Bruce Momjian 已提交
4557
			ArchiveEntry(fout, tblinfo[tableInd].oid, id1->data, "INDEX", NULL, q->data, delq->data,
B
Bruce Momjian 已提交
4558
						 "", tblinfo[tableInd].usename, NULL, NULL);
B
Bruce Momjian 已提交
4559

4560
			/* Dump Index Comments */
B
Bruce,  
Bruce Momjian 已提交
4561 4562
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "INDEX %s", id1->data);
4563
			dumpComment(fout, q->data, indinfo[i].indexreloid, NULL);
4564

4565 4566
		}
	}
4567

4568 4569 4570 4571 4572
	destroyPQExpBuffer(attlist);
	destroyPQExpBuffer(q);
	destroyPQExpBuffer(delq);
	destroyPQExpBuffer(id1);
	destroyPQExpBuffer(id2);
4573
}
4574

4575
/*
B
Bruce Momjian 已提交
4576
 * dumpTuples
4577 4578 4579 4580 4581
 *	  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
4582
 *	  in PostgreSQL.
4583 4584 4585 4586
 *
 * the attrmap passed in tells how to map the attributes copied in to the
 * attributes copied out
 */
4587
#ifdef NOT_USED
4588
void
4589
dumpTuples(PGresult *res, FILE *fout, int *attrmap)
4590
{
4591 4592 4593 4594
	int			j,
				k;
	int			m,
				n;
B
Bruce Momjian 已提交
4595
	char	  **outVals = NULL; /* values to copy out */
4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614

	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++)
			{
4615
				char	   *pval = outVals[k];
4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635

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

4638
#endif
4639

4640 4641 4642 4643
/*
 * setMaxOid -
 * find the maximum oid and generate a COPY statement to set it
*/
4644

4645
static void
B
Bruce Momjian 已提交
4646
setMaxOid(Archive *fout)
4647
{
B
Bruce Momjian 已提交
4648 4649
	PGresult   *res;
	Oid			max_oid;
B
Bruce Momjian 已提交
4650
	char		sql[1024];
4651

4652
	res = PQexec(g_conn, "CREATE TEMPORARY TABLE pgdump_oid (dummy int4)");
4653 4654 4655
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4656
		write_msg(NULL, "could not create pgdump_oid table: %s", PQerrorMessage(g_conn));
4657
		exit_nicely();
4658 4659
	}
	PQclear(res);
4660
	res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
4661 4662 4663
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4664
		write_msg(NULL, "could not insert into pgdump_oid table: %s", PQerrorMessage(g_conn));
4665
		exit_nicely();
4666 4667 4668 4669
	}
	max_oid = atol(PQoidStatus(res));
	if (max_oid == 0)
	{
4670
		write_msg(NULL, "inserted invalid oid\n");
4671
		exit_nicely();
4672 4673
	}
	PQclear(res);
4674
	res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
4675 4676 4677
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4678
		write_msg(NULL, "could not drop pgdump_oid table: %s", PQerrorMessage(g_conn));
4679
		exit_nicely();
4680 4681 4682
	}
	PQclear(res);
	if (g_verbose)
4683
		write_msg(NULL, "maximum system oid is %u\n", max_oid);
4684 4685 4686 4687 4688 4689 4690
	snprintf(sql, 1024,
			 "CREATE TEMPORARY TABLE pgdump_oid (dummy int4);\n"
			 "COPY pgdump_oid WITH OIDS FROM stdin;\n"
			 "%-d\t0\n"
			 "\\.\n"
			 "DROP TABLE pgdump_oid;\n",
			 max_oid);
B
Bruce Momjian 已提交
4691

4692
	ArchiveEntry(fout, "0", "Max OID", "<Init>", NULL, sql, "", "", "", NULL, NULL);
4693
}
4694 4695 4696

/*
 * findLastBuiltInOid -
4697
 * find the last built in oid
4698 4699
 * we do this by retrieving datlastsysoid from the pg_database entry for this database,
 */
4700

4701
static Oid
4702
findLastBuiltinOid_V71(const char *dbname)
4703
{
B
Bruce Momjian 已提交
4704
	PGresult   *res;
4705
	int			ntups;
4706
	Oid			last_oid;
4707 4708 4709
	PQExpBuffer query = createPQExpBuffer();

	resetPQExpBuffer(query);
4710
	appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
4711
	formatStringLiteral(query, dbname, CONV_ALL);
4712

4713
	res = PQexec(g_conn, query->data);
4714 4715 4716
	if (res == NULL ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
4717
		write_msg(NULL, "error in finding the last system oid: %s", PQerrorMessage(g_conn));
4718
		exit_nicely();
4719 4720
	}
	ntups = PQntuples(res);
4721
	if (ntups < 1)
4722
	{
4723
		write_msg(NULL, "missing pg_database entry for this database\n");
4724
		exit_nicely();
4725 4726 4727
	}
	if (ntups > 1)
	{
4728
		write_msg(NULL, "found more than one pg_database entry for this database\n");
4729
		exit_nicely();
4730
	}
4731
	last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
4732
	PQclear(res);
4733
	destroyPQExpBuffer(query);
4734
	return last_oid;
4735 4736
}

4737 4738 4739 4740 4741 4742 4743
/*
 * findLastBuiltInOid -
 * find the last built in oid
 * we do this by looking up the oid of 'template1' in pg_database,
 * this is probably not foolproof but comes close
*/

4744
static Oid
4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755
findLastBuiltinOid_V70(void)
{
	PGresult   *res;
	int			ntups;
	int			last_oid;

	res = PQexec(g_conn,
			  "SELECT oid from pg_database where datname = 'template1'");
	if (res == NULL ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
4756
		write_msg(NULL, "error in finding the template1 database: %s", PQerrorMessage(g_conn));
4757
		exit_nicely();
4758 4759 4760 4761
	}
	ntups = PQntuples(res);
	if (ntups < 1)
	{
4762
		write_msg(NULL, "could not find template1 database entry in the pg_database table\n");
4763
		exit_nicely();
4764 4765 4766
	}
	if (ntups > 1)
	{
4767
		write_msg(NULL, "found more than one template1 database entry in the pg_database table\n");
4768
		exit_nicely();
4769 4770 4771 4772 4773
	}
	last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
	PQclear(res);
	return last_oid;
}
4774

4775
static void
4776
dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool dataOnly)
4777
{
4778
	PGresult   *res;
B
Bruce Momjian 已提交
4779
	int4		last,
4780 4781 4782 4783
				incby,
				maxv,
				minv,
				cache;
B
Bruce Momjian 已提交
4784
	char		cycled,
B
Bruce Momjian 已提交
4785
				called;
4786 4787
	const char *t;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
4788
	PQExpBuffer delqry = createPQExpBuffer();
4789

B
Hi, all  
Bruce Momjian 已提交
4790
	appendPQExpBuffer(query,
4791
			"SELECT sequence_name, last_value, increment_by, max_value, "
4792 4793
				  "min_value, cache_value, is_cycled, is_called from %s",
					  fmtId(tbinfo.relname, force_quotes));
4794

B
Hi, all  
Bruce Momjian 已提交
4795
	res = PQexec(g_conn, query->data);
4796 4797
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
4798
		write_msg(NULL, "query to get data of sequence \"%s\" failed: %s", tbinfo.relname, PQerrorMessage(g_conn));
4799
		exit_nicely();
4800 4801 4802 4803
	}

	if (PQntuples(res) != 1)
	{
4804 4805
		write_msg(NULL, "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
				   tbinfo.relname, PQntuples(res));
4806
		exit_nicely();
4807 4808 4809 4810
	}

	if (strcmp(PQgetvalue(res, 0, 0), tbinfo.relname) != 0)
	{
4811 4812
		write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
				   tbinfo.relname, PQgetvalue(res, 0, 0));
4813
		exit_nicely();
4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825
	}

	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;

4826
	/*
B
Bruce Momjian 已提交
4827 4828
	 * The logic we use for restoring sequences is as follows: -   Add a
	 * basic CREATE SEQUENCE statement (use last_val for start if called
4829 4830 4831 4832
	 * with 'f', else use min_val for start_val).
	 *
	 *	Add a 'SETVAL(seq, last_val, iscalled)' at restore-time iff
	 *  we load data
4833
	 */
4834

4835 4836 4837
	if (!dataOnly)
	{
		PQclear(res);
4838

4839 4840
		resetPQExpBuffer(delqry);
		appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n", fmtId(tbinfo.relname, force_quotes));
4841

4842 4843
		resetPQExpBuffer(query);
		appendPQExpBuffer(query,
B
Bruce Momjian 已提交
4844
				  "CREATE SEQUENCE %s start %d increment %d maxvalue %d "
4845
						  "minvalue %d  cache %d %s;\n",
B
Bruce Momjian 已提交
4846
						  fmtId(tbinfo.relname, force_quotes),
4847 4848 4849 4850
						  (called == 't') ? minv : last,
						  incby, maxv, minv, cache,
						  (cycled == 't') ? "cycle" : "");

P
Philip Warner 已提交
4851
		ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "SEQUENCE", NULL,
B
Bruce Momjian 已提交
4852
			  query->data, delqry->data, "", tbinfo.usename, NULL, NULL);
4853
	}
4854

4855 4856 4857 4858 4859 4860
	if (!schemaOnly)
	{
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "SELECT setval (");
		formatStringLiteral(query, fmtId(tbinfo.relname, force_quotes), CONV_ALL);
		appendPQExpBuffer(query, ", %d, '%c');\n", last, called);
4861

P
Philip Warner 已提交
4862
		ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "SEQUENCE SET", NULL,
B
Bruce Momjian 已提交
4863
					 query->data, "" /* Del */ , "", "", NULL, NULL);
4864
	}
B
Bruce,  
Bruce Momjian 已提交
4865

4866 4867 4868
	if (!dataOnly)
	{
		/* Dump Sequence Comments */
B
Bruce,  
Bruce Momjian 已提交
4869

4870 4871
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo.relname, force_quotes));
4872
		dumpComment(fout, query->data, tbinfo.oid, NULL);
4873
	}
4874 4875 4876

	destroyPQExpBuffer(query);
	destroyPQExpBuffer(delqry);
4877
}
V
Vadim B. Mikheev 已提交
4878 4879


4880
static void
B
Bruce Momjian 已提交
4881
dumpTriggers(Archive *fout, const char *tablename,
4882
			 TableInfo *tblinfo, int numTables)
V
Vadim B. Mikheev 已提交
4883
{
4884 4885 4886
	int			i,
				j;

V
Vadim B. Mikheev 已提交
4887
	if (g_verbose)
4888
		write_msg(NULL, "dumping out triggers\n");
4889

V
Vadim B. Mikheev 已提交
4890 4891
	for (i = 0; i < numTables; i++)
	{
B
Bruce Momjian 已提交
4892
		if (tablename && (strcmp(tblinfo[i].relname, tablename) != 0) && (strlen(tablename) > 0))
V
Vadim B. Mikheev 已提交
4893
			continue;
4894

V
Vadim B. Mikheev 已提交
4895 4896
		for (j = 0; j < tblinfo[i].ntrig; j++)
		{
B
Bruce Momjian 已提交
4897
			ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
B
Bruce Momjian 已提交
4898 4899
				   "TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "", "",
						 tblinfo[i].usename, NULL, NULL);
4900
			dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid, NULL);
V
Vadim B. Mikheev 已提交
4901 4902 4903
		}
	}
}
4904 4905


4906
static void
B
Bruce Momjian 已提交
4907
dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
4908
		  TableInfo *tblinfo, int numTables)
4909
{
B
Bruce Momjian 已提交
4910 4911 4912 4913
	PGresult   *res;
	int			nrules;
	int			i,
				t;
4914
	PQExpBuffer query = createPQExpBuffer();
4915

B
Bruce Momjian 已提交
4916
	int			i_definition;
4917
	int			i_oid;
4918
	int			i_owner;
4919
	int			i_rulename;
4920 4921

	if (g_verbose)
4922
		write_msg(NULL, "dumping out rules\n");
4923 4924 4925 4926 4927 4928

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

		/*
B
Bruce Momjian 已提交
4933 4934
		 * Get all rules defined for this table We include pg_rules in the
		 * cross since it filters out all view rules (pjw 15-Sep-2000).
4935 4936
		 *
		 * XXXX: Use LOJ here
4937
		 */
B
Hi, all  
Bruce Momjian 已提交
4938
		resetPQExpBuffer(query);
4939
		appendPQExpBuffer(query, "SELECT definition,"
4940
						  "   (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
4941 4942
						  "   pg_rewrite.oid, pg_rewrite.rulename "
						  "FROM pg_rewrite, pg_class, pg_rules "
4943
						  "WHERE pg_class.relname = ");
4944
		formatStringLiteral(query, tblinfo[t].relname, CONV_ALL);
4945
		appendPQExpBuffer(query,
4946 4947
						  "    AND pg_rewrite.ev_class = pg_class.oid "
						  "    AND pg_rules.tablename = pg_class.relname "
B
Bruce Momjian 已提交
4948
					   "    AND pg_rules.rulename = pg_rewrite.rulename "
4949
						  "ORDER BY pg_rewrite.oid");
B
Hi, all  
Bruce Momjian 已提交
4950
		res = PQexec(g_conn, query->data);
4951 4952 4953
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
4954 4955
			write_msg(NULL, "query to get rules associated with table \"%s\" failed: %s",
					   tblinfo[t].relname, PQerrorMessage(g_conn));
4956
			exit_nicely();
4957 4958 4959 4960
		}

		nrules = PQntuples(res);
		i_definition = PQfnumber(res, "definition");
4961
		i_owner = PQfnumber(res, "viewowner");
B
Bruce,  
Bruce Momjian 已提交
4962 4963
		i_oid = PQfnumber(res, "oid");
		i_rulename = PQfnumber(res, "rulename");
4964 4965 4966 4967

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

4969 4970
		for (i = 0; i < nrules; i++)
		{
B
Bruce Momjian 已提交
4971
			ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
B
Bruce Momjian 已提交
4972 4973
						 "RULE", NULL, PQgetvalue(res, i, i_definition),
						 "", "", PQgetvalue(res, i, i_owner), NULL, NULL);
4974

B
Bruce,  
Bruce Momjian 已提交
4975 4976 4977 4978
			/* Dump rule comments */

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

B
Bruce,  
Bruce Momjian 已提交
4981 4982
		}

4983 4984
		PQclear(res);
	}
4985 4986

	destroyPQExpBuffer(query);
4987
}