pg_dump.c 121.1 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * pg_dump.c
4
 *	  pg_dump is an 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 16 17 18 19
 *	pg_dump will read the system catalogs in a database and
 *	dump out a script that reproduces
 *	the schema of the database in terms of
 *		  user-defined types
 *		  user-defined functions
 *		  tables
 *		  indices
 *		  aggregates
 *		  operators
 *		  ACL - grant/revoke
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.201 2001/04/05 02:50:01 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 47
 *	 indices,tables,inheritance,types,functions and aggregates.
 *	 No more leaks reported by Purify.
48 49 50
 *
 *
 * Modifications - 1/26/98 - pjlobo@euitt.upm.es
51
 *		 - Added support for password authentication
B
Bruce Momjian 已提交
52 53 54 55 56 57
 *
 * 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 122 123 124
 * 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
 *		OID of the type functions, but type must be created after 
 *		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 136 137 138 139
/*
 * 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"

140
#include <unistd.h>				/* for getopt() */
141
#include <ctype.h>
142

143 144
#include "pg_backup.h"

145 146 147 148 149 150 151 152
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif

#include "access/attnum.h"
153
#include "access/htup.h"
154
#include "catalog/pg_class.h"
V
Vadim B. Mikheev 已提交
155
#include "catalog/pg_trigger.h"
156
#include "catalog/pg_type.h"
157

158
#include "libpq-fe.h"
159
#include "libpq/libpq-fs.h"
160
#ifndef HAVE_STRDUP
161 162
#include "strdup.h"
#endif
163 164

#include "pg_dump.h"
B
Bruce Momjian 已提交
165
#include "pg_backup.h"
166

B
Bruce Momjian 已提交
167 168 169 170 171 172 173 174
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. */
175 176
} formatLiteralOptions;

B
Bruce Momjian 已提交
177
static void dumpComment(Archive *outfile, const char *target, const char *oid);
178
static void dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool dataOnly);
B
Bruce Momjian 已提交
179 180
static void dumpACL(Archive *fout, TableInfo tbinfo);
static void dumpTriggers(Archive *fout, const char *tablename,
181
			 TableInfo *tblinfo, int numTables);
B
Bruce Momjian 已提交
182
static void dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
183
		  TableInfo *tblinfo, int numTables);
184
static void formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts);
185
static void clearTableInfo(TableInfo *, int);
B
Bruce Momjian 已提交
186
static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
187
			TypeInfo *tinfo, int numTypes);
B
Bruce Momjian 已提交
188
static Oid	findLastBuiltinOid(const char *);
B
Bruce Momjian 已提交
189
static void setMaxOid(Archive *fout);
190

191 192
static void AddAcl(char *aclbuf, const char *keyword);
static char *GetPrivileges(const char *s);
V
Vadim B. Mikheev 已提交
193

B
Bruce Momjian 已提交
194 195
static int	dumpBlobs(Archive *AH, char *, void *);
static int	dumpDatabase(Archive *AH);
196
static PQExpBuffer getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo);
197

B
Bruce Momjian 已提交
198
extern char *optarg;
199
extern int	optind,
B
Bruce Momjian 已提交
200
			opterr;
201 202

/* global decls */
203
bool		g_verbose;			/* User wants verbose narration of our
B
Bruce Momjian 已提交
204
								 * activities. */
205
Oid			g_last_builtin_oid; /* value of the last builtin oid */
B
Bruce Momjian 已提交
206
Archive    *g_fout;				/* the script file */
B
Bruce Momjian 已提交
207 208 209
PGconn	   *g_conn;				/* the database connection */

bool		force_quotes;		/* User wants to suppress double-quotes */
210 211 212 213
bool		dumpData;			/* dump data using proper insert strings */
bool		attrNames;			/* put attr names into insert strings */
bool		schemaOnly;
bool		dataOnly;
214
bool		aclsSkip;
215

B
Bruce Momjian 已提交
216
char		g_opaque_type[10];	/* name for the opaque type */
217 218

/* placeholders for the delimiters for comments */
219 220
char		g_comment_start[10];
char		g_comment_end[10];
221 222


B
Bruce Momjian 已提交
223 224 225 226
typedef struct _dumpContext
{
	TableInfo  *tblinfo;
	int			tblidx;
B
Bruce Momjian 已提交
227 228 229
	bool		oids;
} DumpContext;

230
static void
231
help(const char *progname)
232
{
P
Peter Eisentraut 已提交
233
	printf("%s dumps a database as a text file.\n\n", progname);
234 235 236
	puts("Usage:");
	printf("  %s [options] dbname\n\n", progname);
	puts("Options:");
B
Hi,  
Bruce Momjian 已提交
237 238

#ifdef HAVE_GETOPT_LONG
239
	puts(
B
Bruce Momjian 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
	"  -a, --data-only          dump out only the data, not the schema\n"
		 "  -b, --blobs              dump out blob data\n"
	   "  -c, --clean              clean (drop) schema prior to create\n"
		 "  -C, --create             output commands to create database\n"
		 "  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"
		 "  -D, --attribute-inserts  dump data as INSERT commands with attribute names\n"
		 "  -f, --file=FILENAME      specify output file name\n"
		 "  -F, --format {c|t|p}     output file format (custom, tar, plain text)\n"
		 "  -h, --host=HOSTNAME      server host name\n"
		 "  -i, --ignore-version     proceed when database version != pg_dump version\n"
	"  -n, --no-quotes          suppress most quotes around identifiers\n"
	 "  -N, --quotes             enable most quotes around identifiers\n"
		 "  -o, --oids               dump object ids (oids)\n"
		 "  -O, --no-owner           do not output \\connect commands in plain text\n"
		 "                           format\n"
		 "  -p, --port=PORT          server port number\n"
		 "  -R, --no-reconnect       disable ALL reconnections to the database in\n"
		 "                           plain text format\n"
		 "  -s, --schema-only        dump out only the schema, no data\n"
		 "  -S, --superuser=NAME     specify the superuser user name to use in plain\n"
		 "                           text format\n"
	  "  -t, --table=TABLE        dump for this table only (* for all)\n"
		 "  -u, --password           use password authentication\n"
		 "  -v, --verbose            verbose\n"
		 "  -x, --no-acl             do not dump ACL's (grant/revoke)\n"
		 "  -Z, --compress {0-9}     compression level for compressed formats\n"
266
		);
B
Hi,  
Bruce Momjian 已提交
267
#else
268
	puts(
B
Bruce Momjian 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
		 "  -a                       dump out only the data, no schema\n"
		 "  -b                       dump out blob data\n"
	   "  -c                       clean (drop) schema prior to create\n"
		 "  -C                       output commands to create database\n"
		 "  -d                       dump data as INSERT, rather than COPY, commands\n"
		 "  -D                       dump data as INSERT commands with attribute names\n"
		 "  -f FILENAME              specify output file name\n"
		 "  -F {c|t|p}               output file format (custom, tar, plain text)\n"
		 "  -h HOSTNAME              server host name\n"
		 "  -i                       proceed when database version != pg_dump version\n"
	"  -n                       suppress most quotes around identifiers\n"
	 "  -N                       enable most quotes around identifiers\n"
		 "  -o                       dump object ids (oids)\n"
		 "  -O                       do not output \\connect commands in plain text\n"
		 "                           format\n"
		 "  -p PORT                  server port number\n"
		 "  -R                       disable ALL reconnections to the database in\n"
		 "                           plain text format\n"
		 "  -s                       dump out only the schema, no data\n"
		 "  -S NAME                  specify the superuser user name to use in plain\n"
		 "                           text format\n"
	  "  -t TABLE                 dump for this table only (* for all)\n"
		 "  -u                       use password authentication\n"
		 "  -v                       verbose\n"
		 "  -x                       do not dump ACL's (grant/revoke)\n"
		 "  -Z {0-9}                 compression level for compressed formats\n"
295
		);
B
Hi,  
Bruce Momjian 已提交
296
#endif
297 298
	puts("If no database name is not supplied, then the PGDATABASE environment\nvariable value is used.\n");
	puts("Report bugs to <pgsql-bugs@postgresql.org>.");
299
}
300

301

302 303 304
static void
version(void)
{
305
	puts("pg_dump (PostgreSQL) " PG_VERSION);
306
	puts("Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group");
307
	puts("Portions Copyright (c) 1996 Regents of the University of California");
308
	puts("Read the file COPYRIGHT to see the usage and distribution terms.");
309 310
}

311

312
static void
313
exit_nicely(PGconn *conn)
314
{
315 316
	PQfinish(conn);
	exit(1);
317 318 319
}


320 321
#define COPYBUFSIZ		8192

B
Bruce Momjian 已提交
322 323 324 325 326
/*
 *	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.
 */
327

B
Bruce Momjian 已提交
328 329
static int
dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv)
330
{
B
Bruce Momjian 已提交
331 332
	const DumpContext *dctx = (DumpContext *) dctxv;
	const char *classname = dctx->tblinfo[dctx->tblidx].relname;
B
Bruce Momjian 已提交
333
	const bool	oids = dctx->oids;
334

335 336 337 338 339
	PGresult   *res;
	char		query[255];
	int			ret;
	bool		copydone;
	char		copybuf[COPYBUFSIZ];
340

B
Bruce Momjian 已提交
341 342
	if (g_verbose)
		fprintf(stderr, "%s dumping out the contents of table %s\n", g_comment_start, classname);
343

344
	if (oids == true)
345
	{
B
Bruce Momjian 已提交
346 347

		/*
348
		 * archprintf(fout, "COPY %s WITH OIDS FROM stdin;\n",
B
Bruce Momjian 已提交
349
		 * fmtId(classname, force_quotes));
350
		 *
B
Bruce Momjian 已提交
351
		 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
352 353 354
		 *
		 */

355
		sprintf(query, "COPY %s WITH OIDS TO stdout;\n",
356
				fmtId(classname, force_quotes));
357 358 359
	}
	else
	{
B
Bruce Momjian 已提交
360 361 362 363

		/*
		 * archprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname,
		 * force_quotes));
364 365 366 367 368
		 *
		 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
		 *
		 */

369
		sprintf(query, "COPY %s TO stdout;\n", fmtId(classname, force_quotes));
370 371
	}
	res = PQexec(g_conn, query);
372 373
	if (!res ||
		PQresultStatus(res) == PGRES_FATAL_ERROR)
374
	{
375
		fprintf(stderr, "SQL query to dump the contents of Table '%s' "
376 377 378 379 380 381 382 383 384
				"did not execute.  Explanation from backend: '%s'.\n"
				"The query was: '%s'.\n",
				classname, PQerrorMessage(g_conn), query);
		exit_nicely(g_conn);
	}
	else
	{
		if (PQresultStatus(res) != PGRES_COPY_OUT)
		{
385
			fprintf(stderr, "SQL query to dump the contents of Table '%s' "
386 387 388 389 390 391 392 393 394
					"executed abnormally.\n"
					"PQexec() returned status %d when %d was expected.\n"
					"The query was: '%s'.\n",
				  classname, PQresultStatus(res), PGRES_COPY_OUT, query);
			exit_nicely(g_conn);
		}
		else
		{
			copydone = false;
395

396 397
			while (!copydone)
			{
398
				ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
399 400 401 402 403 404 405 406 407

				if (copybuf[0] == '\\' &&
					copybuf[1] == '.' &&
					copybuf[2] == '\0')
				{
					copydone = true;	/* don't print this... */
				}
				else
				{
B
Bruce Momjian 已提交
408
					archputs(copybuf, fout);
409 410
					switch (ret)
					{
411 412 413 414
						case EOF:
							copydone = true;
							/* FALLTHROUGH */
						case 0:
B
Bruce Momjian 已提交
415
							archputc('\n', fout);
416 417 418
							break;
						case 1:
							break;
419 420
					}
				}
421

B
Bruce Momjian 已提交
422
				/*
423 424
				 * THROTTLE:
				 *
B
Bruce Momjian 已提交
425 426 427 428 429
				 * 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.
430
				 *
B
Bruce Momjian 已提交
431 432 433 434 435
				 * 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:
436
				 *
B
Bruce Momjian 已提交
437 438 439
				 * 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
440 441
				 * EndIf
				 *
B
Bruce Momjian 已提交
442 443
				 * where the throttle value was the number of ms to sleep per
				 * ms of work. The calculation was done in each loop.
444
				 *
B
Bruce Momjian 已提交
445 446 447 448 449
				 * 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.
450 451 452
				 *
				 * Further discussion ensued, and the proposal was dropped.
				 *
B
Bruce Momjian 已提交
453 454 455 456 457 458
				 * 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.
459
				 *
B
Bruce Momjian 已提交
460
				 * select(0, NULL, NULL, NULL, &tvi);
461
				 *
B
Bruce Momjian 已提交
462 463 464 465
				 * This will return after the interval specified in the
				 * structure tvi. Fianally, call gettimeofday again to
				 * save the 'last sleep time'.
				 */
466
			}
B
Bruce Momjian 已提交
467
			archprintf(fout, "\\.\n");
468
		}
469
		ret = PQendcopy(g_conn);
470 471
		if (ret != 0)
		{
472
			fprintf(stderr, "SQL query to dump the contents of Table '%s' "
473 474 475 476 477
					"did not execute correctly.  After we read all the "
				 "table contents from the backend, PQendcopy() failed.  "
					"Explanation from backend: '%s'.\n"
					"The query was: '%s'.\n",
					classname, PQerrorMessage(g_conn), query);
B
Bruce Momjian 已提交
478
			PQclear(res);
479 480 481
			exit_nicely(g_conn);
		}
	}
482

B
Bruce Momjian 已提交
483
	return 1;
484 485
}

B
Bruce Momjian 已提交
486
static int
B
Bruce Momjian 已提交
487
dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
488
{
B
Bruce Momjian 已提交
489 490
	const DumpContext *dctx = (DumpContext *) dctxv;
	const char *classname = dctx->tblinfo[dctx->tblidx].relname;
B
Bruce Momjian 已提交
491

492 493
	PGresult   *res;
	PQExpBuffer q = createPQExpBuffer();
494 495
	int			tuple;
	int			field;
496

497 498
	appendPQExpBuffer(q, "SELECT * FROM ONLY %s",
					  fmtId(classname, force_quotes));
B
Hi, all  
Bruce Momjian 已提交
499
	res = PQexec(g_conn, q->data);
500 501 502
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
503 504
		fprintf(stderr, "dumpClasses(): command failed.  Explanation from backend: '%s'.\n",
				PQerrorMessage(g_conn));
505 506
		exit_nicely(g_conn);
	}
507
	for (tuple = 0; tuple < PQntuples(res); tuple++)
508
	{
B
Bruce Momjian 已提交
509
		archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
510
		if (attrNames == true)
511
		{
B
Hi, all  
Bruce Momjian 已提交
512 513
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "(");
514
			for (field = 0; field < PQnfields(res); field++)
515
			{
516
				if (field > 0)
B
Hi, all  
Bruce Momjian 已提交
517 518
					appendPQExpBuffer(q, ",");
				appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
519
			}
B
Hi, all  
Bruce Momjian 已提交
520
			appendPQExpBuffer(q, ") ");
B
Bruce Momjian 已提交
521
			archprintf(fout, "%s", q->data);
522
		}
B
Bruce Momjian 已提交
523
		archprintf(fout, "VALUES (");
524
		for (field = 0; field < PQnfields(res); field++)
525
		{
526
			if (field > 0)
B
Bruce Momjian 已提交
527
				archprintf(fout, ",");
528
			if (PQgetisnull(res, tuple, field))
529
			{
B
Bruce Momjian 已提交
530
				archprintf(fout, "NULL");
531 532 533
				continue;
			}
			switch (PQftype(res, field))
534
			{
535 536
				case INT2OID:
				case INT4OID:
537
				case OIDOID:	/* int types */
538
				case FLOAT4OID:
539
				case FLOAT8OID:/* float types */
540
					/* These types are printed without quotes */
B
Bruce Momjian 已提交
541
					archprintf(fout, "%s",
B
Bruce Momjian 已提交
542
							   PQgetvalue(res, tuple, field));
543
					break;
544 545 546 547 548
				case ZPBITOID:
				case VARBITOID:
					archprintf(fout, "B'%s'",
							   PQgetvalue(res, tuple, field));
					break;
549
				default:
550

551 552
					/*
					 * All other types are printed as string literals,
553
					 * with appropriate escaping of special characters.
554
					 */
555
					resetPQExpBuffer(q);
556
					formatStringLiteral(q, PQgetvalue(res, tuple, field), CONV_ALL);
557
					archprintf(fout, "%s", q->data);
558
					break;
559
			}
560
		}
B
Bruce Momjian 已提交
561
		archprintf(fout, ");\n");
562 563
	}
	PQclear(res);
B
Bruce Momjian 已提交
564
	return 1;
565 566
}

567 568 569 570 571 572 573 574
/*
 * 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
575
formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts)
576 577 578 579
{
	appendPQExpBufferChar(buf, '\'');
	while (*str)
	{
B
Bruce Momjian 已提交
580
		char		ch = *str++;
581 582 583

		if (ch == '\\' || ch == '\'')
		{
B
Bruce Momjian 已提交
584
			appendPQExpBufferChar(buf, ch);		/* double these */
585 586 587
			appendPQExpBufferChar(buf, ch);
		}
		else if ((unsigned char) ch < (unsigned char) ' ' &&
B
Bruce Momjian 已提交
588 589 590
				 (opts == CONV_ALL
				  || (ch != '\n' && ch != '\t')
				  ))
591
		{
B
Bruce Momjian 已提交
592 593 594 595 596

			/*
			 * generate octal escape for control chars other than
			 * whitespace
			 */
597 598 599 600 601 602 603 604 605 606 607
			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, '\'');
}

608 609
/*
 * DumpClasses -
610
 *	  dump the contents of all the classes.
611 612
 */
static void
B
Bruce Momjian 已提交
613
dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
B
Bruce Momjian 已提交
614
		 const char *onlytable, const bool oids, const bool force_quotes)
615 616
{

B
Bruce Momjian 已提交
617 618 619 620 621 622 623 624 625
	int			i;
	char	   *all_only;
	DataDumperPtr dumpFn;
	DumpContext *dumpCtx;
	char	   *oidsPart;
	char		copyBuf[512];
	char	   *copyStmt;

	if (onlytable == NULL || (strlen(onlytable) == 0))
626 627
		all_only = "all";
	else
628
		all_only = "only";
629

630 631 632 633 634 635
	if (oids == true)
		oidsPart = "WITH OIDS ";
	else
		oidsPart = "";


636
	if (g_verbose)
637
		fprintf(stderr, "%s preparing to dump out the contents of %s %d table%s/sequence%s %s\n",
638
				g_comment_start, all_only,
B
Bruce Momjian 已提交
639 640 641
		 (onlytable == NULL || (strlen(onlytable) == 0)) ? numTables : 1,
			  (onlytable == NULL || (strlen(onlytable) == 0)) ? "s" : "",
			  (onlytable == NULL || (strlen(onlytable) == 0)) ? "s" : "",
642
				g_comment_end);
643

644 645
	for (i = 0; i < numTables; i++)
	{
646
		const char *classname = tblinfo[i].relname;
647 648

		/* Skip VIEW relations */
649
		if (tblinfo[i].viewdef != NULL)
650
			continue;
651 652

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

655
		if (!onlytable || (strcmp(classname, onlytable) == 0) || (strlen(onlytable) == 0))
656 657
		{
			if (g_verbose)
658
				fprintf(stderr, "%s preparing to dump out the contents of Table '%s' %s\n",
659 660
						g_comment_start, classname, g_comment_end);

B
Bruce Momjian 已提交
661 662
			/* becomeUser(fout, tblinfo[i].usename); */

B
Bruce Momjian 已提交
663 664
			dumpCtx = (DumpContext *) malloc(sizeof(DumpContext));
			dumpCtx->tblinfo = (TableInfo *) tblinfo;
B
Bruce Momjian 已提交
665 666
			dumpCtx->tblidx = i;
			dumpCtx->oids = oids;
667

B
Bruce Momjian 已提交
668
			if (!dumpData)		/* Dump/restore using COPY */
669
			{
B
Bruce Momjian 已提交
670 671
				dumpFn = dumpClasses_nodumpData;
				/* dumpClasses_nodumpData(fout, classname, oids); */
672 673 674 675
				sprintf(copyBuf, "COPY %s %s FROM stdin;\n", fmtId(tblinfo[i].relname, force_quotes),
						oidsPart);
				copyStmt = copyBuf;
			}
B
Bruce Momjian 已提交
676 677
			else
/* Restore using INSERT */
678
			{
B
Bruce Momjian 已提交
679 680
				dumpFn = dumpClasses_dumpData;
				/* dumpClasses_dumpData(fout, classname); */
681 682
				copyStmt = NULL;
			}
B
Bruce Momjian 已提交
683

P
Philip Warner 已提交
684
			ArchiveEntry(fout, tblinfo[i].oid, tblinfo[i].relname,
B
Bruce Momjian 已提交
685 686
				"TABLE DATA", NULL, "", "", copyStmt, tblinfo[i].usename,
						 dumpFn, dumpCtx);
687
		}
688
	}
689 690
}

691
int
692
main(int argc, char **argv)
693
{
B
Bruce Momjian 已提交
694 695 696
	int			c;
	const char *progname;
	const char *filename = NULL;
B
Bruce Momjian 已提交
697
	const char *format = "p";
B
Bruce Momjian 已提交
698 699 700 701
	const char *dbname = NULL;
	const char *pghost = NULL;
	const char *pgport = NULL;
	char	   *tablename = NULL;
702
	bool		oids = false;
B
Bruce Momjian 已提交
703 704
	TableInfo  *tblinfo;
	int			numTables;
705
	bool		use_password = false;
B
Bruce Momjian 已提交
706
	int			compressLevel = -1;
707
	bool		ignore_version = false;
708 709
	int			plainText = 0;
	int			outputClean = 0;
710
	int			outputCreate = 0;
711
	int			outputBlobs = 0;
712 713
	int			outputNoOwner = 0;
	int			outputNoReconnect = 0;
B
Bruce Momjian 已提交
714
	char	   *outputSuperuser = NULL;
715

B
Bruce Momjian 已提交
716
	RestoreOptions *ropt;
717

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

B
Hi,  
Bruce Momjian 已提交
748 749
#endif

750
	g_verbose = false;
751
	force_quotes = true;
752 753 754 755 756

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

757
	dataOnly = schemaOnly = dumpData = attrNames = false;
758

759 760 761 762
	if (!strrchr(argv[0], SEP_CHAR))
		progname = argv[0];
	else
		progname = strrchr(argv[0], SEP_CHAR) + 1;
763

764 765 766 767
	/* Set defaulty options based on progname */
	if (strcmp(progname, "pg_backup") == 0)
	{
		format = "c";
P
Philip Warner 已提交
768
		outputBlobs = true;
769
	}
770

771 772
	if (argc > 1)
	{
B
Bruce Momjian 已提交
773
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
774 775 776 777
		{
			help(progname);
			exit(0);
		}
B
Bruce Momjian 已提交
778
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
779 780 781 782 783 784
		{
			version();
			exit(0);
		}
	}

B
Hi,  
Bruce Momjian 已提交
785
#ifdef HAVE_GETOPT_LONG
786
	while ((c = getopt_long(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uvxzZ:V?", long_options, &optindex)) != -1)
B
Hi,  
Bruce Momjian 已提交
787
#else
788
	while ((c = getopt(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uvxzZ:V?-")) != -1)
B
Hi,  
Bruce Momjian 已提交
789
#endif
790

791 792 793
	{
		switch (c)
		{
794
			case 'a':			/* Dump data only */
795
				dataOnly = true;
796
				break;
797

798 799 800 801
			case 'b':			/* Dump blobs */
				outputBlobs = true;
				break;

B
Bruce Momjian 已提交
802
			case 'c':			/* clean (i.e., drop) schema prior to
B
Bruce Momjian 已提交
803
								 * create */
B
Bruce Momjian 已提交
804
				outputClean = 1;
B
Bruce Momjian 已提交
805 806
				break;

807 808 809 810 811
			case 'C':			/* Create DB */

				outputCreate = 1;
				break;

812
			case 'd':			/* dump data as proper insert strings */
813
				dumpData = true;
814
				break;
815

816 817
			case 'D':			/* dump data as proper insert strings with
								 * attr names */
818 819
				dumpData = true;
				attrNames = true;
820
				break;
821

822
			case 'f':
823 824
				filename = optarg;
				break;
825

B
Bruce Momjian 已提交
826 827 828
			case 'F':
				format = optarg;
				break;
829

B
Bruce Momjian 已提交
830
			case 'h':			/* server host */
831 832
				pghost = optarg;
				break;
833

834 835 836
			case 'i':			/* ignore database version mismatch */
				ignore_version = true;
				break;
837

B
Bruce Momjian 已提交
838 839
			case 'n':			/* Do not force double-quotes on
								 * identifiers */
840
				force_quotes = false;
841
				break;
842

843
			case 'N':			/* Force double-quotes on identifiers */
844
				force_quotes = true;
845
				break;
846

847
			case 'o':			/* Dump oids */
848
				oids = true;
849
				break;
850 851


852 853 854
			case 'O':			/* Don't reconnect to match owner */
				outputNoOwner = 1;
				break;
855

856 857 858
			case 'p':			/* server port */
				pgport = optarg;
				break;
859

860 861 862
			case 'R':			/* No reconnect */
				outputNoReconnect = 1;
				break;
863

864
			case 's':			/* dump schema only */
865
				schemaOnly = true;
866
				break;
867

B
Bruce Momjian 已提交
868 869
			case 'S':			/* Username for superuser in plain text
								 * output */
870 871
				outputSuperuser = strdup(optarg);
				break;
872

873
			case 't':			/* Dump data for this table only */
874
				{
875
					int			i;
876 877

					tablename = strdup(optarg);
B
Bruce Momjian 已提交
878 879 880 881 882

					/*
					 * quoted string? Then strip quotes and preserve
					 * case...
					 */
883 884 885
					if (tablename[0] == '"')
					{
						strcpy(tablename, &tablename[1]);
B
Bruce Momjian 已提交
886 887
						if (*(tablename + strlen(tablename) - 1) == '"')
							*(tablename + strlen(tablename) - 1) = '\0';
888 889 890 891 892
					}
					/* otherwise, convert table name to lowercase... */
					else
					{
						for (i = 0; tablename[i]; i++)
893 894
							if (isupper((unsigned char) tablename[i]))
								tablename[i] = tolower((unsigned char) tablename[i]);
895

B
Bruce Momjian 已提交
896 897 898 899 900
						/*
						 * '*' is a special case meaning ALL tables, but
						 * only if unquoted
						 */
						if (strcmp(tablename, "*") == 0)
901 902
							tablename[0] = '\0';

903
					}
904
				}
905
				break;
906

907 908 909
			case 'u':
				use_password = true;
				break;
910

911 912
			case 'v':			/* verbose */
				g_verbose = true;
913
				break;
914

915 916
			case 'x':			/* skip ACL dump */
				aclsSkip = true;
917
				break;
918

B
Bruce Momjian 已提交
919 920 921
			case 'Z':			/* Compression Level */
				compressLevel = atoi(optarg);
				break;
922

923 924 925 926
			case 'V':
				version();
				exit(0);
				break;
927

928 929 930
#ifndef HAVE_GETOPT_LONG
			case '-':
				fprintf(stderr, "%s was compiled without support for long options.\n"
B
Bruce Momjian 已提交
931
				"Use --help for help on invocation options.\n", progname);
932 933 934
				exit(1);
				break;
#endif
935
			default:
936
				fprintf(stderr, "Try '%s --help' for more information.\n", progname);
937
				exit(1);
938 939 940
		}
	}

B
Bruce Momjian 已提交
941 942
	if (optind < (argc - 1))
	{
P
Philip Warner 已提交
943 944
		fprintf(stderr,
				"%s: extra parameters found on command line after '%s' (first is '%s').\n"
B
Bruce Momjian 已提交
945 946
				"Please respecify command.\nUse --help for help on invocation options.\n",
				progname, argv[optind], argv[optind + 1]);
P
Philip Warner 已提交
947 948 949
		exit(1);
	}

B
Bruce Momjian 已提交
950 951 952
	if (dataOnly && schemaOnly)
	{
		fprintf(stderr,
B
Bruce Momjian 已提交
953
		 "%s: 'Schema Only' and 'Data Only' are incompatible options.\n",
B
Bruce Momjian 已提交
954 955 956 957
				progname);
		exit(1);
	}

B
Bruce Momjian 已提交
958
	if (outputBlobs && tablename != NULL && strlen(tablename) > 0)
959 960
	{
		fprintf(stderr,
961
				"%s: BLOB output is not supported for a single table. Use all tables or a full dump instead.\n",
962 963 964 965
				progname);
		exit(1);
	}

966 967 968
	if (dumpData == true && oids == true)
	{
		fprintf(stderr,
969
				"%s: INSERT's can not set oids, so INSERT and OID options can not be used together.\n",
970
				progname);
971
		exit(1);
972
	}
973

B
Bruce Momjian 已提交
974
	if (outputBlobs == true && (format[0] == 'p' || format[0] == 'P'))
P
Philip Warner 已提交
975 976
	{
		fprintf(stderr,
B
Bruce Momjian 已提交
977 978
				"%s: BLOB output is not supported for plain text dump files. Use a different output format.\n",
				progname);
P
Philip Warner 已提交
979 980 981
		exit(1);
	}

982
	/* open the output file */
B
Bruce Momjian 已提交
983 984
	switch (format[0])
	{
B
Bruce Momjian 已提交
985 986 987 988 989 990 991 992 993 994 995 996 997 998

		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;
999 1000 1001 1002 1003 1004
			g_fout = CreateArchive(filename, archNull, 0);
			break;

		case 't':
		case 'T':
			g_fout = CreateArchive(filename, archTar, compressLevel);
B
Bruce Momjian 已提交
1005 1006 1007
			break;

		default:
1008
			fprintf(stderr,
B
Bruce Momjian 已提交
1009 1010
					"%s: invalid output format '%s' specified\n", progname, format);
			exit(1);
B
Bruce Momjian 已提交
1011 1012 1013 1014 1015
	}

	if (g_fout == NULL)
	{
		fprintf(stderr,
B
Bruce Momjian 已提交
1016
				"%s: could not open output file named %s for writing\n",
B
Bruce Momjian 已提交
1017 1018
				progname, filename);
		exit(1);
1019 1020
	}

1021 1022
	/* Let the archiver know how noisy to be */
	g_fout->verbose = g_verbose;
1023

1024
	dbname = argv[optind];
1025

B
Bruce Momjian 已提交
1026 1027 1028 1029
	/*
	 * Open the database using the Archiver, so it knows about it. Errors
	 * mean death
	 */
1030
	g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, use_password, ignore_version);
1031

1032 1033 1034 1035 1036 1037 1038 1039
	/*
	 * Start serializable transaction to dump consistent data
	 */
	{
		PGresult   *res;

		res = PQexec(g_conn, "begin");
		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
1040 1041
			exit_horribly(g_fout, "BEGIN command failed. Explanation from backend: '%s'.\n",
						  PQerrorMessage(g_conn));
1042

1043 1044 1045
		PQclear(res);
		res = PQexec(g_conn, "set transaction isolation level serializable");
		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
B
Bruce Momjian 已提交
1046 1047
			exit_horribly(g_fout, "SET TRANSACTION command failed. Explanation from backend: '%s'.\n",
						  PQerrorMessage(g_conn));
1048

1049 1050 1051
		PQclear(res);
	}

1052
	g_last_builtin_oid = findLastBuiltinOid(dbname);
1053

1054 1055 1056 1057
	/* Dump the database definition */
	if (!dataOnly)
		dumpDatabase(g_fout);

1058
	if (oids == true)
1059
		setMaxOid(g_fout);
B
Bruce Momjian 已提交
1060 1061

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

1066
	if (!schemaOnly)
B
Bruce Momjian 已提交
1067
		dumpClasses(tblinfo, numTables, g_fout, tablename, oids, force_quotes);
1068 1069

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

1072 1073
	if (!dataOnly)				/* dump indexes and triggers at the end
								 * for performance */
V
Vadim B. Mikheev 已提交
1074 1075
	{
		dumpTriggers(g_fout, tablename, tblinfo, numTables);
1076
		dumpRules(g_fout, tablename, tblinfo, numTables);
V
Vadim B. Mikheev 已提交
1077
	}
1078

1079 1080
	/* Now sort the output nicely */
	SortTocByOID(g_fout);
1081
	MoveToStart(g_fout, "DATABASE");
1082 1083 1084
	MoveToEnd(g_fout, "TABLE DATA");
	MoveToEnd(g_fout, "BLOBS");
	MoveToEnd(g_fout, "INDEX");
1085
	MoveToEnd(g_fout, "CONSTRAINT");
1086 1087
	MoveToEnd(g_fout, "TRIGGER");
	MoveToEnd(g_fout, "RULE");
1088
	MoveToEnd(g_fout, "SEQUENCE SET");
1089

B
Bruce Momjian 已提交
1090
	if (plainText)
B
Bruce Momjian 已提交
1091 1092
	{
		ropt = NewRestoreOptions();
B
Bruce Momjian 已提交
1093
		ropt->filename = (char *) filename;
B
Bruce Momjian 已提交
1094 1095
		ropt->dropSchema = outputClean;
		ropt->aclsSkip = aclsSkip;
1096 1097 1098 1099 1100 1101 1102 1103 1104
		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 已提交
1105 1106

		if (compressLevel == -1)
B
Bruce Momjian 已提交
1107
			ropt->compression = 0;
B
Bruce Momjian 已提交
1108
		else
B
Bruce Momjian 已提交
1109
			ropt->compression = compressLevel;
B
Bruce Momjian 已提交
1110 1111 1112 1113 1114

		RestoreArchive(g_fout, ropt);
	}

	CloseArchive(g_fout);
1115

1116 1117 1118
	clearTableInfo(tblinfo, numTables);
	PQfinish(g_conn);
	exit(0);
1119 1120
}

1121 1122 1123 1124 1125
/*
 * dumpDatabase:
 *	dump the database definition
 *
 */
B
Bruce Momjian 已提交
1126
static int
1127 1128
dumpDatabase(Archive *AH)
{
B
Bruce Momjian 已提交
1129 1130 1131 1132 1133 1134
	PQExpBuffer dbQry = createPQExpBuffer();
	PQExpBuffer delQry = createPQExpBuffer();
	PQExpBuffer creaQry = createPQExpBuffer();
	PGresult   *res;
	int			ntups;
	int			i_dba;
1135 1136 1137 1138 1139

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

	/* Get the dba */
1140
	appendPQExpBuffer(dbQry, "select (select usename from pg_user where datdba = usesysid) as dba from pg_database"
B
Bruce Momjian 已提交
1141
					  " where datname = ");
1142
	formatStringLiteral(dbQry, PQdb(g_conn), CONV_ALL);
1143 1144 1145 1146 1147

	res = PQexec(g_conn, dbQry->data);
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1148 1149
		fprintf(stderr, "getDatabase(): SELECT failed.  Explanation from backend: '%s'.\n",
				PQerrorMessage(g_conn));
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

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

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

B
Bruce Momjian 已提交
1165 1166 1167 1168
	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 */ );
1169 1170 1171 1172 1173 1174 1175

	PQclear(res);

	return 1;
}


1176 1177 1178 1179 1180 1181
/*
 * dumpBlobs:
 *	dump all blobs
 *
 */

B
Bruce Momjian 已提交
1182
#define loBufSize 16384
1183 1184
#define loFetchSize 1000

B
Bruce Momjian 已提交
1185 1186
static int
dumpBlobs(Archive *AH, char *junkOid, void *junkVal)
1187
{
B
Bruce Momjian 已提交
1188 1189 1190 1191 1192 1193 1194 1195
	PQExpBuffer oidQry = createPQExpBuffer();
	PQExpBuffer oidFetchQry = createPQExpBuffer();
	PGresult   *res;
	int			i;
	int			loFd;
	char		buf[loBufSize];
	int			cnt;
	int			blobOid;
1196 1197 1198 1199 1200

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

	/* Cursor to get all BLOB tables */
B
Bruce Momjian 已提交
1201
	appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject");
1202 1203 1204 1205

	res = PQexec(g_conn, oidQry->data);
	if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
	{
B
Bruce Momjian 已提交
1206 1207
		fprintf(stderr, "dumpBlobs(): Declare Cursor failed.  Explanation from backend: '%s'.\n",
				PQerrorMessage(g_conn));
1208 1209 1210 1211 1212 1213
		exit_nicely(g_conn);
	}

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

B
Bruce Momjian 已提交
1214 1215
	do
	{
1216 1217 1218 1219 1220 1221
		/* Do a fetch */
		PQclear(res);
		res = PQexec(g_conn, oidFetchQry->data);

		if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
		{
B
Bruce Momjian 已提交
1222 1223
			fprintf(stderr, "dumpBlobs(): Fetch Cursor failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
			exit_nicely(g_conn);
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234
		}

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

			StartBlob(AH, blobOid);

			/* Now read it in chunks, sending data to archive */
B
Bruce Momjian 已提交
1242 1243
			do
			{
1244
				cnt = lo_read(g_conn, loFd, buf, loBufSize);
B
Bruce Momjian 已提交
1245 1246
				if (cnt < 0)
				{
1247
					fprintf(stderr, "dumpBlobs(): Error reading large object. "
B
Bruce Momjian 已提交
1248
							" Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1249 1250 1251
					exit_nicely(g_conn);
				}

B
Bruce Momjian 已提交
1252
				WriteData(AH, buf, cnt);
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265

			} while (cnt > 0);

			lo_close(g_conn, loFd);

			EndBlob(AH, blobOid);

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

	return 1;
}

1266
/*
1267 1268
 * getTypes:
 *	  read all base types in the system catalogs and return them in the
1269 1270
 * TypeInfo* structure
 *
1271
 *	numTypes is set to the number of types read in
1272 1273
 *
 */
1274
TypeInfo   *
1275 1276
getTypes(int *numTypes)
{
B
Bruce Momjian 已提交
1277
	PGresult   *res;
1278 1279
	int			ntups;
	int			i;
1280
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1281
	TypeInfo   *tinfo;
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297

	int			i_oid;
	int			i_typowner;
	int			i_typname;
	int			i_typlen;
	int			i_typprtlen;
	int			i_typinput;
	int			i_typoutput;
	int			i_typreceive;
	int			i_typsend;
	int			i_typelem;
	int			i_typdelim;
	int			i_typdefault;
	int			i_typrelid;
	int			i_typbyval;
	int			i_usename;
1298
	int			i_typedefn;
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310

	/* find all base types */

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

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

B
Hi, all  
Bruce Momjian 已提交
1311
	appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
B
Bruce Momjian 已提交
1312 1313 1314 1315 1316
		  "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
					  "typdefault, typrelid, typbyval, "
	"(select usename from pg_user where typowner = usesysid) as usename, "
					  "format_type(pg_type.oid, NULL) as typedefn "
					  "from pg_type");
1317

B
Hi, all  
Bruce Momjian 已提交
1318
	res = PQexec(g_conn, query->data);
1319 1320 1321
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1322
		fprintf(stderr, "getTypes(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));

	i_oid = PQfnumber(res, "oid");
	i_typowner = PQfnumber(res, "typowner");
	i_typname = PQfnumber(res, "typname");
	i_typlen = PQfnumber(res, "typlen");
	i_typprtlen = PQfnumber(res, "typprtlen");
	i_typinput = PQfnumber(res, "typinput");
	i_typoutput = PQfnumber(res, "typoutput");
	i_typreceive = PQfnumber(res, "typreceive");
	i_typsend = PQfnumber(res, "typsend");
	i_typelem = PQfnumber(res, "typelem");
	i_typdelim = PQfnumber(res, "typdelim");
	i_typdefault = PQfnumber(res, "typdefault");
	i_typrelid = PQfnumber(res, "typrelid");
	i_typbyval = PQfnumber(res, "typbyval");
	i_usename = PQfnumber(res, "usename");
1345
	i_typedefn = PQfnumber(res, "typedefn");
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362

	for (i = 0; i < ntups; i++)
	{
		tinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
		tinfo[i].typowner = strdup(PQgetvalue(res, i, i_typowner));
		tinfo[i].typname = strdup(PQgetvalue(res, i, i_typname));
		tinfo[i].typlen = strdup(PQgetvalue(res, i, i_typlen));
		tinfo[i].typprtlen = strdup(PQgetvalue(res, i, i_typprtlen));
		tinfo[i].typinput = strdup(PQgetvalue(res, i, i_typinput));
		tinfo[i].typoutput = strdup(PQgetvalue(res, i, i_typoutput));
		tinfo[i].typreceive = strdup(PQgetvalue(res, i, i_typreceive));
		tinfo[i].typsend = strdup(PQgetvalue(res, i, i_typsend));
		tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
		tinfo[i].typdelim = strdup(PQgetvalue(res, i, i_typdelim));
		tinfo[i].typdefault = strdup(PQgetvalue(res, i, i_typdefault));
		tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
		tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1363
		tinfo[i].typedefn = strdup(PQgetvalue(res, i, i_typedefn));
1364

1365
		if (strlen(tinfo[i].usename) == 0)
B
Bruce Momjian 已提交
1366
			fprintf(stderr, "WARNING: owner of type '%s' appears to be invalid\n", tinfo[i].typname);
1367

1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
		if (strcmp(PQgetvalue(res, i, i_typbyval), "f") == 0)
			tinfo[i].passedbyvalue = 0;
		else
			tinfo[i].passedbyvalue = 1;

		/*
		 * check for user-defined array types, omit system generated ones
		 */
		if ((strcmp(tinfo[i].typelem, "0") != 0) &&
			tinfo[i].typname[0] != '_')
			tinfo[i].isArray = 1;
		else
			tinfo[i].isArray = 0;
	}

	*numTypes = ntups;

	PQclear(res);

	return tinfo;
1388 1389 1390 1391
}

/*
 * getOperators:
1392
 *	  read all operators in the system catalogs and return them in the
1393 1394
 * OprInfo* structure
 *
1395 1396
 *	numOprs is set to the number of operators read in
 *
1397 1398
 *
 */
1399
OprInfo    *
1400 1401
getOperators(int *numOprs)
{
1402
	PGresult   *res;
1403 1404
	int			ntups;
	int			i;
1405
	PQExpBuffer query = createPQExpBuffer();
1406

B
Bruce Momjian 已提交
1407
	OprInfo    *oprinfo;
1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422

	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;
1423 1424 1425 1426 1427 1428

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

B
Hi, all  
Bruce Momjian 已提交
1429
	appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
1430
			   "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
B
Bruce Momjian 已提交
1431 1432 1433
					  "oprcanhash, oprlsortop, oprrsortop, "
	"(select usename from pg_user where oprowner = usesysid) as usename "
					  "from pg_operator");
1434

B
Hi, all  
Bruce Momjian 已提交
1435
	res = PQexec(g_conn, query->data);
1436 1437 1438
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1439
		fprintf(stderr, "getOperators(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
		exit_nicely(g_conn);
	}

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

	oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));

	i_oid = PQfnumber(res, "oid");
	i_oprname = PQfnumber(res, "oprname");
	i_oprkind = PQfnumber(res, "oprkind");
	i_oprcode = PQfnumber(res, "oprcode");
	i_oprleft = PQfnumber(res, "oprleft");
	i_oprright = PQfnumber(res, "oprright");
	i_oprcom = PQfnumber(res, "oprcom");
	i_oprnegate = PQfnumber(res, "oprnegate");
	i_oprrest = PQfnumber(res, "oprrest");
	i_oprjoin = PQfnumber(res, "oprjoin");
	i_oprcanhash = PQfnumber(res, "oprcanhash");
	i_oprlsortop = PQfnumber(res, "oprlsortop");
	i_oprrsortop = PQfnumber(res, "oprrsortop");
	i_usename = PQfnumber(res, "usename");

	for (i = 0; i < ntups; i++)
	{
		oprinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
		oprinfo[i].oprname = strdup(PQgetvalue(res, i, i_oprname));
		oprinfo[i].oprkind = strdup(PQgetvalue(res, i, i_oprkind));
		oprinfo[i].oprcode = strdup(PQgetvalue(res, i, i_oprcode));
		oprinfo[i].oprleft = strdup(PQgetvalue(res, i, i_oprleft));
		oprinfo[i].oprright = strdup(PQgetvalue(res, i, i_oprright));
		oprinfo[i].oprcom = strdup(PQgetvalue(res, i, i_oprcom));
		oprinfo[i].oprnegate = strdup(PQgetvalue(res, i, i_oprnegate));
		oprinfo[i].oprrest = strdup(PQgetvalue(res, i, i_oprrest));
		oprinfo[i].oprjoin = strdup(PQgetvalue(res, i, i_oprjoin));
		oprinfo[i].oprcanhash = strdup(PQgetvalue(res, i, i_oprcanhash));
		oprinfo[i].oprlsortop = strdup(PQgetvalue(res, i, i_oprlsortop));
		oprinfo[i].oprrsortop = strdup(PQgetvalue(res, i, i_oprrsortop));
		oprinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1479 1480 1481

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

1484 1485 1486 1487 1488
	}

	PQclear(res);

	return oprinfo;
1489 1490
}

1491
void
1492
clearTypeInfo(TypeInfo *tp, int numTypes)
1493
{
1494
	int			i;
1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527

	for (i = 0; i < numTypes; ++i)
	{
		if (tp[i].oid)
			free(tp[i].oid);
		if (tp[i].typowner)
			free(tp[i].typowner);
		if (tp[i].typname)
			free(tp[i].typname);
		if (tp[i].typlen)
			free(tp[i].typlen);
		if (tp[i].typprtlen)
			free(tp[i].typprtlen);
		if (tp[i].typinput)
			free(tp[i].typinput);
		if (tp[i].typoutput)
			free(tp[i].typoutput);
		if (tp[i].typreceive)
			free(tp[i].typreceive);
		if (tp[i].typsend)
			free(tp[i].typsend);
		if (tp[i].typelem)
			free(tp[i].typelem);
		if (tp[i].typdelim)
			free(tp[i].typdelim);
		if (tp[i].typdefault)
			free(tp[i].typdefault);
		if (tp[i].typrelid)
			free(tp[i].typrelid);
		if (tp[i].usename)
			free(tp[i].usename);
	}
	free(tp);
1528 1529 1530
}

void
1531
clearFuncInfo(FuncInfo *fun, int numFuncs)
1532
{
1533 1534
	int			i,
				a;
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545

	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);
1546
		for (a = 0; a < FUNC_MAX_ARGS; ++a)
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556
			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);
1557 1558
}

1559
static void
1560
clearTableInfo(TableInfo *tblinfo, int numTables)
1561
{
1562 1563
	int			i,
				j;
1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583

	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 已提交
1584 1585
			if (tblinfo[i].attoids[j])
				free(tblinfo[i].attoids[j]);
1586 1587 1588 1589 1590
			if (tblinfo[i].attnames[j])
				free(tblinfo[i].attnames[j]);
			if (tblinfo[i].typnames[j])
				free(tblinfo[i].typnames[j]);
		}
B
Bruce Momjian 已提交
1591

B
Bruce Momjian 已提交
1592 1593 1594
		if (tblinfo[i].triggers)
		{
			for (j = 0; j < tblinfo[i].ntrig; j++)
B
Bruce Momjian 已提交
1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607
			{
				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);
		}

1608 1609
		if (tblinfo[i].atttypmod)
			free((int *) tblinfo[i].atttypmod);
1610 1611
		if (tblinfo[i].inhAttrs)
			free((int *) tblinfo[i].inhAttrs);
1612 1613 1614 1615
		if (tblinfo[i].inhAttrDef)
			free((int *) tblinfo[i].inhAttrDef);
		if (tblinfo[i].inhNotNull)
			free((int *) tblinfo[i].inhNotNull);
1616 1617
		if (tblinfo[i].attnames)
			free(tblinfo[i].attnames);
1618 1619
		if (tblinfo[i].atttypedefns)
			free(tblinfo[i].atttypedefns);
1620 1621 1622 1623
		if (tblinfo[i].typnames)
			free(tblinfo[i].typnames);
		if (tblinfo[i].notnull)
			free(tblinfo[i].notnull);
1624 1625
		if (tblinfo[i].primary_key_name)
			free(tblinfo[i].primary_key_name);
1626 1627
	}
	free(tblinfo);
1628 1629
}

1630
void
1631
clearInhInfo(InhInfo *inh, int numInherits)
1632
{
1633
	int			i;
1634 1635 1636 1637 1638

	if (!inh)
		return;
	for (i = 0; i < numInherits; ++i)
	{
1639 1640
		if (inh[i].inhrelid)
			free(inh[i].inhrelid);
1641 1642 1643 1644
		if (inh[i].inhparent)
			free(inh[i].inhparent);
	}
	free(inh);
1645 1646 1647
}

void
1648
clearOprInfo(OprInfo *opr, int numOprs)
1649
{
1650
	int			i;
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685

	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);
1686 1687 1688
}

void
1689
clearIndInfo(IndInfo *ind, int numIndices)
1690
{
1691 1692
	int			i,
				a;
1693 1694 1695 1696 1697

	if (!ind)
		return;
	for (i = 0; i < numIndices; ++i)
	{
B
Bruce,  
Bruce Momjian 已提交
1698 1699
		if (ind[i].indoid)
			free(ind[i].indoid);
1700 1701 1702 1703 1704 1705 1706 1707 1708 1709
		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);
1710 1711
		if (ind[i].indisprimary)
			free(ind[i].indisprimary);
1712 1713 1714 1715 1716 1717 1718 1719 1720
		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);
1721 1722 1723
}

void
B
Bruce Momjian 已提交
1724
clearAggInfo(AggInfo *agginfo, int numArgs)
1725
{
1726
	int			i;
1727 1728 1729 1730 1731 1732 1733 1734 1735

	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);
1736 1737
		if (agginfo[i].aggtransfn)
			free(agginfo[i].aggtransfn);
1738 1739
		if (agginfo[i].aggfinalfn)
			free(agginfo[i].aggfinalfn);
1740 1741
		if (agginfo[i].aggtranstype)
			free(agginfo[i].aggtranstype);
1742 1743
		if (agginfo[i].aggbasetype)
			free(agginfo[i].aggbasetype);
1744 1745
		if (agginfo[i].agginitval)
			free(agginfo[i].agginitval);
1746 1747 1748 1749
		if (agginfo[i].usename)
			free(agginfo[i].usename);
	}
	free(agginfo);
1750
}
1751 1752 1753

/*
 * getAggregates:
1754
 *	  read all the user-defined aggregates in the system catalogs and
1755 1756
 * return them in the AggInfo* structure
 *
1757 1758
 * numAggs is set to the number of aggregates read in
 *
1759 1760
 *
 */
1761
AggInfo    *
1762 1763
getAggregates(int *numAggs)
{
B
Bruce Momjian 已提交
1764
	PGresult   *res;
1765 1766
	int			ntups;
	int			i;
1767
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1768
	AggInfo    *agginfo;
1769 1770 1771

	int			i_oid;
	int			i_aggname;
1772
	int			i_aggtransfn;
1773
	int			i_aggfinalfn;
1774
	int			i_aggtranstype;
1775
	int			i_aggbasetype;
1776
	int			i_agginitval;
1777
	int			i_usename;
1778 1779 1780

	/* find all user-defined aggregates */

B
Hi, all  
Bruce Momjian 已提交
1781
	appendPQExpBuffer(query,
B
Bruce Momjian 已提交
1782 1783 1784 1785 1786
					  "SELECT pg_aggregate.oid, aggname, aggtransfn, "
					  "aggfinalfn, aggtranstype, aggbasetype, "
					  "agginitval, "
	"(select usename from pg_user where aggowner = usesysid) as usename "
					  "from pg_aggregate");
1787

B
Hi, all  
Bruce Momjian 已提交
1788
	res = PQexec(g_conn, query->data);
1789 1790 1791
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1792
		fprintf(stderr, "getAggregates(): SELECT failed.  Explanation from backend: '%s'.\n",
B
Bruce Momjian 已提交
1793
				PQerrorMessage(g_conn));
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
		exit_nicely(g_conn);
	}

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

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

	i_oid = PQfnumber(res, "oid");
	i_aggname = PQfnumber(res, "aggname");
1804
	i_aggtransfn = PQfnumber(res, "aggtransfn");
1805
	i_aggfinalfn = PQfnumber(res, "aggfinalfn");
1806
	i_aggtranstype = PQfnumber(res, "aggtranstype");
1807
	i_aggbasetype = PQfnumber(res, "aggbasetype");
1808
	i_agginitval = PQfnumber(res, "agginitval");
1809 1810 1811 1812 1813 1814
	i_usename = PQfnumber(res, "usename");

	for (i = 0; i < ntups; i++)
	{
		agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
		agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
1815
		agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
1816
		agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
1817
		agginfo[i].aggtranstype = strdup(PQgetvalue(res, i, i_aggtranstype));
1818
		agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
1819
		agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
1820
		agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1821 1822
		if (strlen(agginfo[i].usename) == 0)
			fprintf(stderr, "WARNING: owner of aggregate '%s' appears to be invalid\n",
B
Bruce Momjian 已提交
1823
					agginfo[i].aggname);
1824

1825 1826 1827 1828 1829
	}

	PQclear(res);

	return agginfo;
1830 1831 1832 1833
}

/*
 * getFuncs:
1834
 *	  read all the user-defined functions in the system catalogs and
1835 1836
 * return them in the FuncInfo* structure
 *
1837 1838
 * numFuncs is set to the number of functions read in
 *
1839 1840
 *
 */
1841
FuncInfo   *
1842 1843
getFuncs(int *numFuncs)
{
1844
	PGresult   *res;
1845 1846
	int			ntups;
	int			i;
1847 1848
	PQExpBuffer query = createPQExpBuffer();
	FuncInfo   *finfo;
1849 1850 1851 1852 1853 1854 1855 1856 1857 1858

	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;
1859
	int			i_iscachable;
1860
	int			i_isstrict;
1861
	int			i_usename;
1862 1863 1864

	/* find all user-defined funcs */

B
Hi, all  
Bruce Momjian 已提交
1865
	appendPQExpBuffer(query,
1866
		   "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
1867
					  "proretset, proargtypes, prosrc, probin, "
B
Bruce Momjian 已提交
1868
	"(select usename from pg_user where proowner = usesysid) as usename, "
1869
					  "proiscachable, proisstrict "
1870
					  "from pg_proc "
B
Bruce Momjian 已提交
1871
					  "where pg_proc.oid > '%u'::oid",
1872
					  g_last_builtin_oid);
1873

B
Hi, all  
Bruce Momjian 已提交
1874
	res = PQexec(g_conn, query->data);
1875 1876 1877
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1878 1879
		fprintf(stderr, "getFuncs(): SELECT failed.  Explanation from backend: '%s'.\n",
				PQerrorMessage(g_conn));
1880 1881 1882 1883 1884 1885 1886 1887 1888
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numFuncs = ntups;

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

1889 1890
	memset((char *) finfo, 0, ntups * sizeof(FuncInfo));

1891 1892 1893 1894 1895 1896 1897 1898 1899
	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");
1900
	i_iscachable = PQfnumber(res, "proiscachable");
1901
	i_isstrict = PQfnumber(res, "proisstrict");
1902 1903 1904 1905 1906 1907 1908
	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));

1909
		finfo[i].prosrc = strdup(PQgetvalue(res, i, i_prosrc));
1910 1911 1912 1913 1914
		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));
1915
		finfo[i].lang = atoi(PQgetvalue(res, i, i_prolang));
1916
		finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
B
Bruce Momjian 已提交
1917 1918
		finfo[i].iscachable = (strcmp(PQgetvalue(res, i, i_iscachable), "t") == 0);
		finfo[i].isstrict = (strcmp(PQgetvalue(res, i, i_isstrict), "t") == 0);
1919 1920 1921

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

1924 1925 1926 1927
		if (finfo[i].nargs < 0 || finfo[i].nargs > FUNC_MAX_ARGS)
		{
			fprintf(stderr, "failed sanity check: %s has %d args\n",
					finfo[i].proname, finfo[i].nargs);
1928
			exit(1);
1929 1930 1931 1932
		}
		parseNumericArray(PQgetvalue(res, i, i_proargtypes),
						  finfo[i].argtypes,
						  finfo[i].nargs);
1933 1934 1935 1936 1937 1938
		finfo[i].dumped = 0;
	}

	PQclear(res);

	return finfo;
1939 1940 1941 1942 1943

}

/*
 * getTables
1944
 *	  read all the user-defined tables (no indices, no catalogs)
1945 1946
 * in the system catalogs return them in the TableInfo* structure
 *
1947 1948
 * numTables is set to the number of tables read in
 *
1949 1950
 *
 */
1951
TableInfo  *
V
Vadim B. Mikheev 已提交
1952
getTables(int *numTables, FuncInfo *finfo, int numFuncs)
1953
{
1954
	PGresult   *res;
1955 1956
	int			ntups;
	int			i;
1957
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
1958
	PQExpBuffer delqry = createPQExpBuffer();
1959
	TableInfo  *tblinfo;
1960

B
Bruce Momjian 已提交
1961
	int			i_reloid;
1962 1963 1964 1965
	int			i_relname;
	int			i_relkind;
	int			i_relacl;
	int			i_usename;
V
Vadim B. Mikheev 已提交
1966 1967
	int			i_relchecks;
	int			i_reltriggers;
1968
	int			i_relhasindex;
1969 1970 1971 1972 1973

	char		relkindview[2];

	relkindview[0] = RELKIND_VIEW;
	relkindview[1] = '\0';
1974 1975 1976 1977 1978 1979

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

B
Hi, all  
Bruce Momjian 已提交
1984
	appendPQExpBuffer(query,
B
Bruce Momjian 已提交
1985 1986
					  "SELECT pg_class.oid, relname, relkind, relacl, "
	"(select usename from pg_user where relowner = usesysid) as usename, "
1987
					  "relchecks, reltriggers, relhasindex "
1988 1989
					  "from pg_class "
					  "where relname !~ '^pg_' "
1990 1991
					  "and relkind in ('%c', '%c', '%c') "
					  "order by oid",
B
Bruce Momjian 已提交
1992
					  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
1993

B
Hi, all  
Bruce Momjian 已提交
1994
	res = PQexec(g_conn, query->data);
1995 1996 1997
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1998 1999
		fprintf(stderr, "getTables(): SELECT failed.  Explanation from backend: '%s'.\n",
				PQerrorMessage(g_conn));
2000 2001 2002 2003 2004 2005 2006 2007 2008
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numTables = ntups;

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

B
Bruce Momjian 已提交
2009
	i_reloid = PQfnumber(res, "oid");
2010 2011 2012 2013
	i_relname = PQfnumber(res, "relname");
	i_relkind = PQfnumber(res, "relkind");
	i_relacl = PQfnumber(res, "relacl");
	i_usename = PQfnumber(res, "usename");
V
Vadim B. Mikheev 已提交
2014 2015
	i_relchecks = PQfnumber(res, "relchecks");
	i_reltriggers = PQfnumber(res, "reltriggers");
B
Hi, all  
Bruce Momjian 已提交
2016
	i_relhasindex = PQfnumber(res, "relhasindex");
2017 2018 2019

	for (i = 0; i < ntups; i++)
	{
B
Bruce Momjian 已提交
2020
		tblinfo[i].oid = strdup(PQgetvalue(res, i, i_reloid));
2021 2022 2023 2024
		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 已提交
2025 2026
		tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
		tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
2027

2028 2029
		if (strlen(tblinfo[i].usename) == 0)
			fprintf(stderr, "WARNING: owner of table '%s' appears to be invalid\n",
B
Bruce Momjian 已提交
2030
					tblinfo[i].relname);
2031

2032 2033 2034 2035 2036 2037
		/* Get view definition */
		if (strcmp(PQgetvalue(res, i, i_relkind), relkindview) == 0)
		{
			PGresult   *res2;

			resetPQExpBuffer(query);
2038
			appendPQExpBuffer(query, "SELECT pg_get_viewdef(");
2039
			formatStringLiteral(query, tblinfo[i].relname, CONV_ALL);
2040
			appendPQExpBuffer(query, ") as viewdef");
2041 2042 2043 2044
			res2 = PQexec(g_conn, query->data);
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
				fprintf(stderr, "getTables(): SELECT (for VIEW DEFINITION) failed.  "
B
Bruce Momjian 已提交
2045 2046
						"Explanation from backend: %s",
						PQerrorMessage(g_conn));
2047 2048 2049
				exit_nicely(g_conn);
			}

B
Bruce Momjian 已提交
2050
			if (PQntuples(res2) != 1)
2051 2052 2053 2054
			{
				if (PQntuples(res2) < 1)
				{
					fprintf(stderr, "getTables(): SELECT (for VIEW %s) returned no definitions",
B
Bruce Momjian 已提交
2055 2056 2057 2058
							tblinfo[i].relname);
				}
				else
				{
2059
					fprintf(stderr, "getTables(): SELECT (for VIEW %s) returned more than 1 definition",
B
Bruce Momjian 已提交
2060
							tblinfo[i].relname);
2061 2062 2063 2064 2065 2066
				}
				exit_nicely(g_conn);
			}

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

B
Bruce Momjian 已提交
2067
			if (strlen(tblinfo[i].viewdef) == 0)
2068 2069
			{
				fprintf(stderr, "getTables(): SELECT (for VIEW %s) returned empty definition",
B
Bruce Momjian 已提交
2070
						tblinfo[i].relname);
2071 2072 2073 2074 2075 2076
				exit_nicely(g_conn);
			}
		}
		else
			tblinfo[i].viewdef = NULL;

2077 2078 2079
		/* 
		 * Get non-inherited CHECK constraints, if any.
		 *
B
Bruce Momjian 已提交
2080 2081
		 * Exclude inherited CHECKs from CHECK constraints total. If a
		 * constraint matches by name and condition with a constraint
2082 2083
		 * belonging to a parent class (OR conditions match and both
	     * names start with '$', we assume it was inherited.
2084 2085
		 */
		if (tblinfo[i].ncheck > 0)
V
Vadim B. Mikheev 已提交
2086 2087
		{
			PGresult   *res2;
2088 2089
			int			i_rcname,
						i_rcsrc;
V
Vadim B. Mikheev 已提交
2090 2091
			int			ntups2;
			int			i2;
2092

V
Vadim B. Mikheev 已提交
2093
			if (g_verbose)
2094
				fprintf(stderr, "%s finding CHECK constraints for relation: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2095 2096 2097
						g_comment_start,
						tblinfo[i].relname,
						g_comment_end);
2098

B
Hi, all  
Bruce Momjian 已提交
2099 2100
			resetPQExpBuffer(query);
			appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
2101
							  " where rcrelid = '%s'::oid "
2102
							  "   and not exists "
2103 2104 2105 2106 2107 2108 2109 2110
							  "  (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) "
2111
							  " Order By oid ",
2112
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2113
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2114
			if (!res2 ||
2115
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2116
			{
B
Bruce Momjian 已提交
2117 2118
				fprintf(stderr, "getTables(): SELECT (for CHECK) failed.  "
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2119 2120 2121
				exit_nicely(g_conn);
			}
			ntups2 = PQntuples(res2);
2122
			if (ntups2 > tblinfo[i].ncheck)
V
Vadim B. Mikheev 已提交
2123
			{
2124 2125
				fprintf(stderr, "getTables(): relation '%s': a maximum of %d CHECKs "
									"were expected, but got %d\n",
2126
						tblinfo[i].relname, tblinfo[i].ncheck, ntups2);
V
Vadim B. Mikheev 已提交
2127 2128
				exit_nicely(g_conn);
			}
2129 2130 2131 2132

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

V
Vadim B. Mikheev 已提交
2133 2134
			i_rcname = PQfnumber(res2, "rcname");
			i_rcsrc = PQfnumber(res2, "rcsrc");
2135
			tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
V
Vadim B. Mikheev 已提交
2136 2137
			for (i2 = 0; i2 < ntups2; i2++)
			{
B
Bruce Momjian 已提交
2138 2139
				const char *name = PQgetvalue(res2, i2, i_rcname);
				const char *expr = PQgetvalue(res2, i2, i_rcsrc);
2140

B
Hi, all  
Bruce Momjian 已提交
2141
				resetPQExpBuffer(query);
2142 2143
				if (name[0] != '$')
				{
2144 2145
					appendPQExpBuffer(query, "CONSTRAINT %s ",
									  fmtId(name, force_quotes));
B
Bruce Momjian 已提交
2146
				}
2147
				appendPQExpBuffer(query, "CHECK (%s)", expr);
B
Hi, all  
Bruce Momjian 已提交
2148
				tblinfo[i].check_expr[i2] = strdup(query->data);
V
Vadim B. Mikheev 已提交
2149 2150 2151 2152 2153
			}
			PQclear(res2);
		}
		else
			tblinfo[i].check_expr = NULL;
2154

2155 2156
		/* Get primary key */
		if (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0)
2157
		{
2158
			PGresult   *res2;
B
Bruce Momjian 已提交
2159

B
Hi, all  
Bruce Momjian 已提交
2160
			resetPQExpBuffer(query);
B
Bruce Momjian 已提交
2161
			appendPQExpBuffer(query,
2162
							  "SELECT Oid FROM pg_index i WHERE i.indisprimary AND i.indrelid = %s ",
2163
							  tblinfo[i].oid);
2164
			res2 = PQexec(g_conn, query->data);
B
Bruce Momjian 已提交
2165 2166
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
2167 2168
				fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY) failed on table %s.  Explanation from backend: %s\n",
						tblinfo[i].relname, PQerrorMessage(g_conn));
B
Bruce Momjian 已提交
2169 2170
				exit_nicely(g_conn);
			}
2171

B
Bruce Momjian 已提交
2172 2173
			if (PQntuples(res2) > 1)
			{
2174 2175
				fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY) produced more than one row on table %s.\n",
						tblinfo[i].relname);
2176
				exit_nicely(g_conn);
2177 2178
			}

B
Bruce Momjian 已提交
2179
			if (PQntuples(res2) == 1)
2180
				tblinfo[i].pkIndexOid = strdup(PQgetvalue(res2, 0, 0));
B
Bruce Momjian 已提交
2181
			else
2182 2183
				tblinfo[i].pkIndexOid = NULL;

2184
		}
2185
		else
2186
			tblinfo[i].pkIndexOid = NULL;
B
Bruce Momjian 已提交
2187

2188
		/* Get primary key name (if primary key exist) */
2189
		if (tblinfo[i].pkIndexOid != NULL)
2190 2191
		{
			PGresult   *res2;
B
Bruce Momjian 已提交
2192
			int			n;
2193 2194 2195 2196

			resetPQExpBuffer(query);
			appendPQExpBuffer(query,
							  "SELECT c.relname "
2197
							  "FROM pg_index i LEFT OUTER JOIN pg_class c ON c.oid = i.indexrelid "
2198
							  "WHERE i.indrelid = %s"
2199
							  "AND   i.indisprimary ",
2200 2201 2202 2203
							  tblinfo[i].oid);
			res2 = PQexec(g_conn, query->data);
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
2204 2205
				fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY NAME) failed for table %s.  Explanation from backend: %s",
						tblinfo[i].relname, PQerrorMessage(g_conn));
2206 2207 2208 2209 2210 2211 2212
				exit_nicely(g_conn);
			}

			n = PQntuples(res2);
			if (n != 1)
			{
				fprintf(stderr,
2213
						"getTables(): SELECT (for PRIMARY KEY NAME) failed for table %s. "
B
Bruce Momjian 已提交
2214
						"This is impossible but object with OID == %s have %d primary keys.\n",
2215
						tblinfo[i].relname,
2216 2217 2218 2219 2220
						tblinfo[i].oid,
						n);
				exit_nicely(g_conn);
			}

2221 2222 2223
			/* Sanity check on LOJ */
			if (PQgetisnull(res2, 0, 0))
			{
B
Bruce Momjian 已提交
2224
				fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY NAME) on table %s returned NULL value.\n",
2225 2226 2227 2228
						tblinfo[i].relname);
				exit_nicely(g_conn);
			}

2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239
			tblinfo[i].primary_key_name =
				strdup(fmtId(PQgetvalue(res2, 0, 0), force_quotes));
			if (tblinfo[i].primary_key_name == NULL)
			{
				perror("strdup");
				exit(1);
			}
		}
		else
			tblinfo[i].primary_key_name = NULL;

V
Vadim B. Mikheev 已提交
2240 2241 2242 2243
		/* Get Triggers */
		if (tblinfo[i].ntrig > 0)
		{
			PGresult   *res2;
B
Bruce,  
Bruce Momjian 已提交
2244
			int			i_tgoid,
2245
						i_tgname,
2246 2247 2248
						i_tgfoid,
						i_tgtype,
						i_tgnargs,
2249 2250 2251 2252 2253
						i_tgargs,
						i_tgisconstraint,
						i_tgconstrname,
						i_tgdeferrable,
						i_tginitdeferred;
V
Vadim B. Mikheev 已提交
2254 2255
			int			ntups2;
			int			i2;
2256

V
Vadim B. Mikheev 已提交
2257
			if (g_verbose)
2258
				fprintf(stderr, "%s finding Triggers for relation: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2259 2260 2261
						g_comment_start,
						tblinfo[i].relname,
						g_comment_end);
2262

B
Hi, all  
Bruce Momjian 已提交
2263
			resetPQExpBuffer(query);
2264
			appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, tgisconstraint, tgconstrname, tgdeferrable, tginitdeferred, oid "
2265 2266 2267
							  "from pg_trigger "
							  "where tgrelid = '%s'::oid ",
							  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2268
			res2 = PQexec(g_conn, query->data);
V
Vadim B. Mikheev 已提交
2269
			if (!res2 ||
2270
				PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2271
			{
B
Bruce Momjian 已提交
2272
				fprintf(stderr, "getTables(): SELECT (for TRIGGER) failed.  "
B
Bruce Momjian 已提交
2273
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2274 2275 2276 2277 2278
				exit_nicely(g_conn);
			}
			ntups2 = PQntuples(res2);
			if (ntups2 != tblinfo[i].ntrig)
			{
2279
				fprintf(stderr, "getTables(): relation '%s': %d Triggers were expected, but got %d\n",
2280
						tblinfo[i].relname, tblinfo[i].ntrig, ntups2);
V
Vadim B. Mikheev 已提交
2281 2282 2283 2284 2285 2286 2287
				exit_nicely(g_conn);
			}
			i_tgname = PQfnumber(res2, "tgname");
			i_tgfoid = PQfnumber(res2, "tgfoid");
			i_tgtype = PQfnumber(res2, "tgtype");
			i_tgnargs = PQfnumber(res2, "tgnargs");
			i_tgargs = PQfnumber(res2, "tgargs");
B
Bruce,  
Bruce Momjian 已提交
2288
			i_tgoid = PQfnumber(res2, "oid");
2289 2290 2291 2292 2293
			i_tgisconstraint = PQfnumber(res2, "tgisconstraint");
			i_tgconstrname = PQfnumber(res2, "tgconstrname");
			i_tgdeferrable = PQfnumber(res2, "tgdeferrable");
			i_tginitdeferred = PQfnumber(res2, "tginitdeferred");

B
Bruce Momjian 已提交
2294
			tblinfo[i].triggers = (TrigInfo *) malloc(ntups2 * sizeof(TrigInfo));
B
Hi, all  
Bruce Momjian 已提交
2295 2296
			resetPQExpBuffer(query);
			for (i2 = 0; i2 < ntups2; i2++)
V
Vadim B. Mikheev 已提交
2297
			{
2298
				const char *tgfuncoid = PQgetvalue(res2, i2, i_tgfoid);
2299
				char	   *tgfunc = NULL;
2300 2301
				int2		tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
				int			tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
B
Bruce Momjian 已提交
2302
				const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
2303 2304 2305
				int			tgisconstraint;
				int			tgdeferrable;
				int			tginitdeferred;
B
Bruce Momjian 已提交
2306
				const char *p;
2307 2308
				int			findx;

2309
				if (strcmp(PQgetvalue(res2, i2, i_tgisconstraint), "f") == 0)
2310
					tgisconstraint = 0;
2311
				else
2312
					tgisconstraint = 1;
2313 2314

				if (strcmp(PQgetvalue(res2, i2, i_tgdeferrable), "f") == 0)
2315
					tgdeferrable = 0;
2316
				else
2317
					tgdeferrable = 1;
2318 2319

				if (strcmp(PQgetvalue(res2, i2, i_tginitdeferred), "f") == 0)
2320
					tginitdeferred = 0;
2321
				else
2322
					tginitdeferred = 1;
2323

V
Vadim B. Mikheev 已提交
2324 2325
				for (findx = 0; findx < numFuncs; findx++)
				{
2326
					if (strcmp(finfo[findx].oid, tgfuncoid) == 0 &&
2327
						finfo[findx].nargs == 0 &&
V
Vadim B. Mikheev 已提交
2328 2329 2330
						strcmp(finfo[findx].prorettype, "0") == 0)
						break;
				}
2331

V
Vadim B. Mikheev 已提交
2332 2333
				if (findx == numFuncs)
				{
2334
					PGresult   *r;
2335
					int			numFuncs;
2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352

					/*
					 * 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)
					{
B
Bruce Momjian 已提交
2353 2354
						fprintf(stderr, "getTables(): SELECT (funcname) failed for trigger %s.  Explanation from backend: '%s'.\n",
								PQgetvalue(res2, i2, i_tgname), PQerrorMessage(g_conn));
2355 2356 2357 2358 2359
						exit_nicely(g_conn);
					}

					/* Sanity: Check we got only one tuple */
					numFuncs = PQntuples(r);
B
Bruce Momjian 已提交
2360 2361 2362 2363
					if (numFuncs != 1)
					{
						fprintf(stderr, "getTables(): SELECT (funcname) for trigger %s returned %d tuples. Expected 1.\n",
								PQgetvalue(res2, i2, i_tgname), numFuncs);
2364 2365
						exit_nicely(g_conn);
					}
2366

2367
					tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
2368
					PQclear(r);
2369
				}
2370
				else
2371
					tgfunc = strdup(finfo[findx].proname);
B
Bruce Momjian 已提交
2372 2373

				appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
B
Bruce Momjian 已提交
2374 2375
								  fmtId(PQgetvalue(res2, i2, i_tgname),
										force_quotes));
B
Bruce Momjian 已提交
2376
				appendPQExpBuffer(delqry, "ON %s;\n",
B
Bruce Momjian 已提交
2377
								fmtId(tblinfo[i].relname, force_quotes));
2378

B
Hi, all  
Bruce Momjian 已提交
2379
				resetPQExpBuffer(query);
2380 2381 2382 2383 2384
				if (tgisconstraint)
				{
					appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgconstrname), force_quotes));
				}
2385 2386
				else
				{
2387 2388 2389
					appendPQExpBuffer(query, "CREATE TRIGGER ");
					appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
				}
B
Bruce Momjian 已提交
2390
				appendPQExpBufferChar(query, ' ');
V
Vadim B. Mikheev 已提交
2391 2392 2393
				/* Trigger type */
				findx = 0;
				if (TRIGGER_FOR_BEFORE(tgtype))
B
Hi, all  
Bruce Momjian 已提交
2394
					appendPQExpBuffer(query, "BEFORE");
V
Vadim B. Mikheev 已提交
2395
				else
B
Hi, all  
Bruce Momjian 已提交
2396
					appendPQExpBuffer(query, "AFTER");
V
Vadim B. Mikheev 已提交
2397 2398
				if (TRIGGER_FOR_INSERT(tgtype))
				{
B
Hi, all  
Bruce Momjian 已提交
2399
					appendPQExpBuffer(query, " INSERT");
V
Vadim B. Mikheev 已提交
2400 2401 2402 2403 2404
					findx++;
				}
				if (TRIGGER_FOR_DELETE(tgtype))
				{
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2405
						appendPQExpBuffer(query, " OR DELETE");
V
Vadim B. Mikheev 已提交
2406
					else
B
Hi, all  
Bruce Momjian 已提交
2407
						appendPQExpBuffer(query, " DELETE");
V
Vadim B. Mikheev 已提交
2408 2409 2410
					findx++;
				}
				if (TRIGGER_FOR_UPDATE(tgtype))
2411
				{
V
Vadim B. Mikheev 已提交
2412
					if (findx > 0)
B
Hi, all  
Bruce Momjian 已提交
2413
						appendPQExpBuffer(query, " OR UPDATE");
V
Vadim B. Mikheev 已提交
2414
					else
B
Hi, all  
Bruce Momjian 已提交
2415
						appendPQExpBuffer(query, " UPDATE");
2416
				}
2417 2418
				appendPQExpBuffer(query, " ON %s ", fmtId(tblinfo[i].relname, force_quotes));

2419
				if (tgisconstraint)
2420
				{
2421
					if (!tgdeferrable)
2422 2423 2424 2425
						appendPQExpBuffer(query, " NOT");
					appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
					if (tginitdeferred)
						appendPQExpBuffer(query, "DEFERRED");
2426
					else
2427
						appendPQExpBuffer(query, "IMMEDIATE");
2428

2429 2430 2431
				}

				appendPQExpBuffer(query, " FOR EACH ROW");
2432 2433
				appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
								  fmtId(tgfunc, force_quotes));
V
Vadim B. Mikheev 已提交
2434 2435
				for (findx = 0; findx < tgnargs; findx++)
				{
2436
					const char *s;
2437 2438

					for (p = tgargs;;)
V
Vadim B. Mikheev 已提交
2439
					{
2440
						p = strchr(p, '\\');
V
Vadim B. Mikheev 已提交
2441 2442
						if (p == NULL)
						{
B
Bruce Momjian 已提交
2443 2444
							fprintf(stderr, "getTables(): relation '%s': bad argument "
									"string (%s) for trigger '%s'\n",
2445 2446 2447
									tblinfo[i].relname,
									PQgetvalue(res2, i2, i_tgargs),
									PQgetvalue(res2, i2, i_tgname));
V
Vadim B. Mikheev 已提交
2448 2449 2450 2451 2452 2453 2454 2455
							exit_nicely(g_conn);
						}
						p++;
						if (*p == '\\')
						{
							p++;
							continue;
						}
2456
						if (p[0] == '0' && p[1] == '0' && p[2] == '0')
V
Vadim B. Mikheev 已提交
2457 2458 2459
							break;
					}
					p--;
2460
					appendPQExpBufferChar(query, '\'');
B
Bruce Momjian 已提交
2461
					for (s = tgargs; s < p;)
V
Vadim B. Mikheev 已提交
2462 2463
					{
						if (*s == '\'')
2464 2465
							appendPQExpBufferChar(query, '\\');
						appendPQExpBufferChar(query, *s++);
V
Vadim B. Mikheev 已提交
2466
					}
B
Bruce Momjian 已提交
2467 2468
					appendPQExpBufferChar(query, '\'');
					appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
V
Vadim B. Mikheev 已提交
2469 2470
					tgargs = p + 4;
				}
B
Hi, all  
Bruce Momjian 已提交
2471
				appendPQExpBuffer(query, ");\n");
2472

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

				/*** Initialize trcomments and troids ***/
2476

B
Bruce,  
Bruce Momjian 已提交
2477
				resetPQExpBuffer(query);
2478 2479
				appendPQExpBuffer(query, "TRIGGER %s ",
					fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
B
Bruce,  
Bruce Momjian 已提交
2480
				appendPQExpBuffer(query, "ON %s",
2481
								fmtId(tblinfo[i].relname, force_quotes));
B
Bruce Momjian 已提交
2482 2483
				tblinfo[i].triggers[i2].tgcomment = strdup(query->data);
				tblinfo[i].triggers[i2].oid = strdup(PQgetvalue(res2, i2, i_tgoid));
B
Bruce Momjian 已提交
2484
				tblinfo[i].triggers[i2].tgname = strdup(fmtId(PQgetvalue(res2, i2, i_tgname), false));
B
Bruce Momjian 已提交
2485
				tblinfo[i].triggers[i2].tgdel = strdup(delqry->data);
B
Bruce,  
Bruce Momjian 已提交
2486

2487 2488
				if (tgfunc)
					free(tgfunc);
V
Vadim B. Mikheev 已提交
2489 2490 2491 2492 2493
			}
			PQclear(res2);
		}
		else
			tblinfo[i].triggers = NULL;
2494

2495 2496 2497 2498 2499
	}

	PQclear(res);

	return tblinfo;
2500 2501 2502 2503 2504

}

/*
 * getInherits
2505
 *	  read all the inheritance information
2506 2507
 * from the system catalogs return them in the InhInfo* structure
 *
2508 2509
 * numInherits is set to the number of tables read in
 *
2510 2511
 *
 */
2512
InhInfo    *
2513 2514
getInherits(int *numInherits)
{
2515
	PGresult   *res;
2516 2517
	int			ntups;
	int			i;
2518 2519
	PQExpBuffer query = createPQExpBuffer();
	InhInfo    *inhinfo;
2520

2521
	int			i_inhrelid;
2522
	int			i_inhparent;
2523 2524 2525

	/* find all the inheritance information */

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

B
Hi, all  
Bruce Momjian 已提交
2528
	res = PQexec(g_conn, query->data);
2529 2530 2531
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2532
		fprintf(stderr, "getInherits(): SELECT failed.  Explanation from backend: '%s'.\n",
B
Bruce Momjian 已提交
2533
				PQerrorMessage(g_conn));
2534 2535 2536 2537 2538 2539 2540 2541 2542
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numInherits = ntups;

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

2543
	i_inhrelid = PQfnumber(res, "inhrelid");
2544 2545 2546 2547
	i_inhparent = PQfnumber(res, "inhparent");

	for (i = 0; i < ntups; i++)
	{
2548
		inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
2549 2550 2551 2552 2553
		inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
	}

	PQclear(res);
	return inhinfo;
2554 2555 2556 2557
}

/*
 * getTableAttrs -
2558 2559
 *	  for each table in tblinfo, read its attributes types and names
 *
2560
 * this is implemented in a very inefficient way right now, looping
2561
 * through the tblinfo and doing a join per table to find the attrs and their
2562 2563
 * types
 *
2564
 *	modifies tblinfo
2565 2566
 */
void
2567
getTableAttrs(TableInfo *tblinfo, int numTables)
2568
{
2569 2570
	int			i,
				j;
2571
	PQExpBuffer q = createPQExpBuffer();
2572 2573
	int			i_attname;
	int			i_typname;
2574
	int			i_atttypmod;
2575
	int			i_attnotnull;
V
Vadim B. Mikheev 已提交
2576
	int			i_atthasdef;
2577
	int			i_attoid;
2578
	int			i_atttypedefn;
2579
	PGresult   *res;
2580
	int			ntups;
2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595

	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)
2596
			fprintf(stderr, "%s finding the attrs and types for table: '%s' %s\n",
2597 2598 2599 2600
					g_comment_start,
					tblinfo[i].relname,
					g_comment_end);

B
Hi, all  
Bruce Momjian 已提交
2601
		resetPQExpBuffer(q);
B
Bruce,  
Bruce Momjian 已提交
2602
		appendPQExpBuffer(q, "SELECT a.oid as attoid, a.attnum, a.attname, t.typname, a.atttypmod, "
2603
						  "a.attnotnull, a.atthasdef, format_type(a.atttypid, a.atttypmod) as atttypedefn "
2604
						  "from pg_attribute a LEFT OUTER JOIN pg_type t ON a.atttypid = t.oid "
B
Bruce Momjian 已提交
2605
						  "where a.attrelid = '%s'::oid "
2606 2607
						  "and a.attnum > 0 order by attnum",
						  tblinfo[i].oid);
B
Hi, all  
Bruce Momjian 已提交
2608
		res = PQexec(g_conn, q->data);
2609 2610 2611
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
B
Bruce Momjian 已提交
2612
			fprintf(stderr, "getTableAttrs(): SELECT failed.  "
B
Bruce Momjian 已提交
2613
			"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2614 2615 2616 2617 2618
			exit_nicely(g_conn);
		}

		ntups = PQntuples(res);

B
Bruce,  
Bruce Momjian 已提交
2619
		i_attoid = PQfnumber(res, "attoid");
2620 2621
		i_attname = PQfnumber(res, "attname");
		i_typname = PQfnumber(res, "typname");
2622
		i_atttypmod = PQfnumber(res, "atttypmod");
2623
		i_attnotnull = PQfnumber(res, "attnotnull");
V
Vadim B. Mikheev 已提交
2624
		i_atthasdef = PQfnumber(res, "atthasdef");
2625
		i_atttypedefn = PQfnumber(res, "atttypedefn");
2626 2627

		tblinfo[i].numatts = ntups;
B
Bruce,  
Bruce Momjian 已提交
2628
		tblinfo[i].attoids = (char **) malloc(ntups * sizeof(char *));
2629
		tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
2630
		tblinfo[i].atttypedefns = (char **) malloc(ntups * sizeof(char *));
2631
		tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
2632
		tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
2633
		tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
2634 2635
		tblinfo[i].inhAttrDef = (int *) malloc(ntups * sizeof(int));
		tblinfo[i].inhNotNull = (int *) malloc(ntups * sizeof(int));
2636
		tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
V
Vadim B. Mikheev 已提交
2637
		tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
2638 2639 2640 2641
		tblinfo[i].parentRels = NULL;
		tblinfo[i].numParents = 0;
		for (j = 0; j < ntups; j++)
		{
2642 2643 2644 2645 2646 2647 2648 2649 2650

			/* Sanity check on LOJ */
			if (PQgetisnull(res, j, i_typname))
			{
				fprintf(stderr, "getTableAttrs(): SELECT produced NULL attribute type name for attr %d on table %s.\n",
						j, tblinfo[i].relname);
				exit_nicely(g_conn);
			}

B
Bruce,  
Bruce Momjian 已提交
2651
			tblinfo[i].attoids[j] = strdup(PQgetvalue(res, j, i_attoid));
2652
			tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
2653
			tblinfo[i].atttypedefns[j] = strdup(PQgetvalue(res, j, i_atttypedefn));
2654
			tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
2655
			tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
2656 2657
			tblinfo[i].inhAttrs[j] = 0; /* this flag is set in
										 * flagInhAttrs() */
2658 2659 2660
			tblinfo[i].inhAttrDef[j] = 0;
			tblinfo[i].inhNotNull[j] = 0;

2661
			tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't') ? true : false;
V
Vadim B. Mikheev 已提交
2662 2663 2664
			if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
			{
				PGresult   *res2;
2665
				int			numAttr;
2666

V
Vadim B. Mikheev 已提交
2667
				if (g_verbose)
2668
					fprintf(stderr, "%s finding DEFAULT expression for attr: '%s' %s\n",
V
Vadim B. Mikheev 已提交
2669 2670 2671
							g_comment_start,
							tblinfo[i].attnames[j],
							g_comment_end);
2672

B
Hi, all  
Bruce Momjian 已提交
2673 2674
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
2675 2676
							 "where adrelid = '%s'::oid and adnum = %d ",
								  tblinfo[i].oid, j + 1);
B
Hi, all  
Bruce Momjian 已提交
2677
				res2 = PQexec(g_conn, q->data);
V
Vadim B. Mikheev 已提交
2678
				if (!res2 ||
2679
					PQresultStatus(res2) != PGRES_TUPLES_OK)
V
Vadim B. Mikheev 已提交
2680
				{
B
Bruce Momjian 已提交
2681 2682
					fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) failed.  "
							"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
V
Vadim B. Mikheev 已提交
2683 2684
					exit_nicely(g_conn);
				}
2685 2686 2687

				/* Sanity: Check we got only one tuple */
				numAttr = PQntuples(res2);
B
Bruce Momjian 已提交
2688 2689 2690 2691
				if (numAttr != 1)
				{
					fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) for attr %s returned %d tuples. Expected 1.\n",
							tblinfo[i].attnames[j], numAttr);
2692 2693 2694
					exit_nicely(g_conn);
				}

V
Vadim B. Mikheev 已提交
2695 2696 2697 2698 2699
				tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
				PQclear(res2);
			}
			else
				tblinfo[i].adef_expr[j] = NULL;
2700 2701 2702
		}
		PQclear(res);
	}
2703 2704 2705 2706 2707
}


/*
 * getIndices
2708
 *	  read all the user-defined indices information
2709 2710
 * from the system catalogs return them in the InhInfo* structure
 *
2711 2712
 * numIndices is set to the number of indices read in
 *
2713 2714
 *
 */
2715
IndInfo    *
2716 2717
getIndices(int *numIndices)
{
2718
	int			i;
2719
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
2720
	PGresult   *res;
2721
	int			ntups;
B
Bruce Momjian 已提交
2722
	IndInfo    *indinfo;
2723 2724 2725 2726 2727 2728 2729 2730

	int			i_indexrelname;
	int			i_indrelname;
	int			i_indamname;
	int			i_indproc;
	int			i_indkey;
	int			i_indclass;
	int			i_indisunique;
2731
	int			i_indoid;
2732 2733
	int			i_oid;
	int			i_indisprimary;
2734 2735 2736 2737 2738

	/*
	 * find all the user-defined indices. We do not handle partial
	 * indices.
	 *
2739
	 * Notice we skip indices on system classes
2740 2741
	 *
	 * this is a 4-way join !!
2742 2743
	 *
	 * XXXX: Use LOJ
2744 2745
	 */

B
Hi, all  
Bruce Momjian 已提交
2746
	appendPQExpBuffer(query,
2747
					  "SELECT i.oid, t1.oid as indoid, t1.relname as indexrelname, t2.relname as indrelname, "
2748
					  "i.indproc, i.indkey, i.indclass, "
B
Bruce Momjian 已提交
2749
				  "a.amname as indamname, i.indisunique, i.indisprimary "
2750 2751 2752
					"from pg_index i, pg_class t1, pg_class t2, pg_am a "
				   "WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid "
					  "and t1.relam = a.oid and i.indexrelid > '%u'::oid "
2753
					  "and t2.relname !~ '^pg_' ",
2754
					  g_last_builtin_oid);
2755

B
Hi, all  
Bruce Momjian 已提交
2756
	res = PQexec(g_conn, query->data);
2757 2758 2759
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
2760
		fprintf(stderr, "getIndices(): SELECT failed.  "
B
Bruce Momjian 已提交
2761
			"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2762 2763 2764 2765 2766 2767 2768 2769 2770
		exit_nicely(g_conn);
	}

	ntups = PQntuples(res);

	*numIndices = ntups;

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

2771 2772
	memset((char *) indinfo, 0, ntups * sizeof(IndInfo));

2773
	i_oid = PQfnumber(res, "oid");
B
Bruce,  
Bruce Momjian 已提交
2774
	i_indoid = PQfnumber(res, "indoid");
2775 2776 2777 2778 2779 2780 2781
	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");
2782
	i_indisprimary = PQfnumber(res, "indisprimary");
2783 2784 2785

	for (i = 0; i < ntups; i++)
	{
2786
		indinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
B
Bruce,  
Bruce Momjian 已提交
2787
		indinfo[i].indoid = strdup(PQgetvalue(res, i, i_indoid));
2788 2789 2790 2791
		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));
2792 2793 2794 2795 2796 2797
		parseNumericArray(PQgetvalue(res, i, i_indkey),
						  indinfo[i].indkey,
						  INDEX_MAX_KEYS);
		parseNumericArray(PQgetvalue(res, i, i_indclass),
						  indinfo[i].indclass,
						  INDEX_MAX_KEYS);
2798
		indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
2799
		indinfo[i].indisprimary = strdup(PQgetvalue(res, i, i_indisprimary));
2800 2801 2802
	}
	PQclear(res);
	return indinfo;
2803 2804
}

B
Bruce,  
Bruce Momjian 已提交
2805
/*------------------------------------------------------------------
2806
 * dumpComments --
B
Bruce,  
Bruce Momjian 已提交
2807
 *
2808
 * This routine is used to dump any comments associated with the
B
Bruce,  
Bruce Momjian 已提交
2809 2810 2811 2812
 * oid handed to this routine. The routine takes a constant character
 * string for the target part of the object and the oid of the object
 * whose comments are to be dumped. It is perfectly acceptable
 * to hand an oid to this routine which has not been commented. In
2813
 * addition, the routine takes the stdio FILE handle to which the
B
Bruce,  
Bruce Momjian 已提交
2814 2815 2816 2817
 * output should be written.
 *------------------------------------------------------------------
*/

T
Tom Lane 已提交
2818
static void
B
Bruce Momjian 已提交
2819
dumpComment(Archive *fout, const char *target, const char *oid)
2820
{
B
Bruce,  
Bruce Momjian 已提交
2821

2822
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
2823
	PQExpBuffer query;
2824
	int			i_description;
B
Bruce,  
Bruce Momjian 已提交
2825 2826 2827 2828 2829 2830 2831 2832 2833 2834

	/*** 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);
2835 2836
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce,  
Bruce Momjian 已提交
2837 2838 2839 2840 2841 2842 2843
		fprintf(stderr, "DumpComment: SELECT failed: '%s'.\n",
				PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

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

2844 2845
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2846
		i_description = PQfnumber(res, "description");
B
Bruce Momjian 已提交
2847
		resetPQExpBuffer(query);
2848
		appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
2849
		formatStringLiteral(query, PQgetvalue(res, 0, i_description), PASS_LFTAB);
2850
		appendPQExpBuffer(query, ";\n");
B
Bruce Momjian 已提交
2851

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

B
Bruce,  
Bruce Momjian 已提交
2855 2856 2857 2858 2859
	}

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

	PQclear(res);
2860

B
Bruce,  
Bruce Momjian 已提交
2861 2862 2863
}

/*------------------------------------------------------------------
2864
 * dumpDBComment --
B
Bruce,  
Bruce Momjian 已提交
2865
 *
2866 2867
 * 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 已提交
2868 2869 2870 2871 2872
 * to dump the schema of the database, then this is the first
 * statement issued.
 *------------------------------------------------------------------
*/

2873
void
B
Bruce Momjian 已提交
2874
dumpDBComment(Archive *fout)
2875
{
B
Bruce,  
Bruce Momjian 已提交
2876

2877
	PGresult   *res;
B
Bruce,  
Bruce Momjian 已提交
2878
	PQExpBuffer query;
2879
	int			i_oid;
B
Bruce,  
Bruce Momjian 已提交
2880 2881 2882 2883

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

	query = createPQExpBuffer();
2884
	appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = ");
2885
	formatStringLiteral(query, PQdb(g_conn), CONV_ALL);
B
Bruce,  
Bruce Momjian 已提交
2886 2887 2888 2889

	/*** Execute query ***/

	res = PQexec(g_conn, query->data);
2890 2891
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce,  
Bruce Momjian 已提交
2892 2893 2894 2895 2896 2897 2898
		fprintf(stderr, "dumpDBComment: SELECT failed: '%s'.\n",
				PQerrorMessage(g_conn));
		exit_nicely(g_conn);
	}

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

2899 2900
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2901 2902 2903 2904 2905 2906 2907 2908 2909
		i_oid = PQfnumber(res, "oid");
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "DATABASE %s", fmtId(PQdb(g_conn), force_quotes));
		dumpComment(fout, query->data, PQgetvalue(res, 0, i_oid));
	}

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

	PQclear(res);
2910

B
Bruce,  
Bruce Momjian 已提交
2911 2912
}

2913 2914
/*
 * dumpTypes
2915
 *	  writes out to fout the queries to recreate all the user-defined types
2916 2917 2918
 *
 */
void
B
Bruce Momjian 已提交
2919
dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
2920
		  TypeInfo *tinfo, int numTypes)
2921
{
2922
	int			i;
2923
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
2924
	PQExpBuffer delq = createPQExpBuffer();
2925
	int			funcInd;
2926 2927 2928 2929
	const char *((*deps)[]);
	int			depIdx = 0;

	deps = malloc(sizeof(char*) * 10);
2930 2931 2932 2933 2934

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

		/* skip all the builtin types */
2935
		if (atooid(tinfo[i].oid) <= g_last_builtin_oid)
2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952
			continue;

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

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

		/*
		 * before we create a type, we need to create the input and output
		 * functions for it, if they haven't been created already
		 */
		funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typinput);
		if (funcInd != -1)
2953 2954
		{
			(*deps)[depIdx++] = strdup(finfo[funcInd].oid);
2955
			dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
2956
		}
2957 2958 2959

		funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
		if (funcInd != -1)
2960 2961
		{
			(*deps)[depIdx++] = strdup(finfo[funcInd].oid);
2962
			dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
2963
		}
2964

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

B
Hi, all  
Bruce Momjian 已提交
2967 2968
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
2969
						  "CREATE TYPE %s "
2970
						  "( internallength = %s, externallength = %s,",
2971 2972
						  fmtId(tinfo[i].typname, force_quotes),
						  tinfo[i].typlen,
2973 2974 2975 2976 2977 2978 2979 2980 2981 2982
						  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));
2983
		formatStringLiteral(q, tinfo[i].typdefault, CONV_ALL);
2984 2985 2986

		if (tinfo[i].isArray)
		{
2987
			char	   *elemType;
2988

2989
			elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
2990 2991 2992 2993 2994 2995 2996 2997 2998
			if (elemType == NULL)
			{
				fprintf(stderr, "Notice: array type %s - type for elements (oid %s) is not dumped.\n",
						tinfo[i].typname, tinfo[i].typelem);
				resetPQExpBuffer(q);
				resetPQExpBuffer(delq);
				continue;
			}

2999
			appendPQExpBuffer(q, ", element = %s, delimiter = ", elemType);
3000
			formatStringLiteral(q, tinfo[i].typdelim, CONV_ALL);
3001 3002

			(*deps)[depIdx++] = strdup(tinfo[i].typelem);
3003 3004
		}
		if (tinfo[i].passedbyvalue)
B
Hi, all  
Bruce Momjian 已提交
3005
			appendPQExpBuffer(q, ",passedbyvalue);\n");
3006
		else
B
Hi, all  
Bruce Momjian 已提交
3007
			appendPQExpBuffer(q, ");\n");
3008

3009 3010 3011
		(*deps)[depIdx++] = NULL; /* End of List */

		ArchiveEntry(fout, tinfo[i].oid, tinfo[i].typname, "TYPE", deps,
B
Bruce Momjian 已提交
3012
				  q->data, delq->data, "", tinfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
3013 3014 3015 3016

		/*** Dump Type Comments ***/

		resetPQExpBuffer(q);
B
Bruce Momjian 已提交
3017 3018
		resetPQExpBuffer(delq);

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

B
Bruce Momjian 已提交
3022
		resetPQExpBuffer(q);
3023
	}
3024 3025
}

3026 3027
/*
 * dumpProcLangs
B
Bruce Momjian 已提交
3028
 *		  writes out to fout the queries to recreate user-defined procedural languages
3029 3030 3031
 *
 */
void
B
Bruce Momjian 已提交
3032
dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
B
Bruce Momjian 已提交
3033
			  TypeInfo *tinfo, int numTypes)
3034
{
3035 3036
	PGresult   *res;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
3037 3038
	PQExpBuffer defqry = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
3039
	int			ntups;
B
Bruce Momjian 已提交
3040
	int			i_oid;
3041 3042 3043 3044
	int			i_lanname;
	int			i_lanpltrusted;
	int			i_lanplcallfoid;
	int			i_lancompiler;
3045
	Oid			lanoid;
3046 3047 3048
	char	   *lanname;
	char	   *lancompiler;
	const char *lanplcallfoid;
3049 3050 3051
	int			i,
				fidx;

B
Bruce Momjian 已提交
3052
	appendPQExpBuffer(query, "SELECT oid, * FROM pg_language "
3053 3054
					  "WHERE lanispl "
					  "ORDER BY oid");
B
Hi, all  
Bruce Momjian 已提交
3055
	res = PQexec(g_conn, query->data);
3056 3057 3058
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
3059
		fprintf(stderr, "dumpProcLangs(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3060 3061 3062 3063
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);

B
Bruce Momjian 已提交
3064 3065 3066 3067
	i_lanname = PQfnumber(res, "lanname");
	i_lanpltrusted = PQfnumber(res, "lanpltrusted");
	i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
	i_lancompiler = PQfnumber(res, "lancompiler");
B
Bruce Momjian 已提交
3068
	i_oid = PQfnumber(res, "oid");
3069

B
Bruce Momjian 已提交
3070 3071
	for (i = 0; i < ntups; i++)
	{
3072
		lanoid = atooid(PQgetvalue(res, i, i_oid));
3073 3074 3075
		if (lanoid <= g_last_builtin_oid)
			continue;

3076
		lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
3077 3078


3079 3080 3081 3082 3083 3084 3085
		for (fidx = 0; fidx < numFuncs; fidx++)
		{
			if (!strcmp(finfo[fidx].oid, lanplcallfoid))
				break;
		}
		if (fidx >= numFuncs)
		{
B
Bruce Momjian 已提交
3086
			fprintf(stderr, "dumpProcLangs(): handler procedure for "
B
Bruce Momjian 已提交
3087
			   "language %s not found\n", PQgetvalue(res, i, i_lanname));
3088 3089 3090 3091 3092
			exit_nicely(g_conn);
		}

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

3093 3094
		lanname = PQgetvalue(res, i, i_lanname);
		lancompiler = PQgetvalue(res, i, i_lancompiler);
3095

3096
		appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE ");
3097
		formatStringLiteral(delqry, lanname, CONV_ALL);
3098
		appendPQExpBuffer(delqry, ";\n");
3099

3100 3101 3102
		appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE ",
						  (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
						  "TRUSTED " : "");
3103
		formatStringLiteral(defqry, lanname, CONV_ALL);
3104 3105
		appendPQExpBuffer(defqry, " HANDLER %s LANCOMPILER ",
						  fmtId(finfo[fidx].proname, force_quotes));
3106
		formatStringLiteral(defqry, lancompiler, CONV_ALL);
3107
		appendPQExpBuffer(defqry, ";\n");
3108

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

3112 3113
		resetPQExpBuffer(defqry);
		resetPQExpBuffer(delqry);
3114 3115 3116 3117 3118 3119
	}

	PQclear(res);

}

3120 3121
/*
 * dumpFuncs
3122
 *	  writes out to fout the queries to recreate all the user-defined functions
3123 3124 3125
 *
 */
void
B
Bruce Momjian 已提交
3126
dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs,
3127
		  TypeInfo *tinfo, int numTypes)
3128
{
3129
	int			i;
3130 3131 3132

	for (i = 0; i < numFuncs; i++)
		dumpOneFunc(fout, finfo, i, tinfo, numTypes);
3133 3134 3135 3136
}

/*
 * dumpOneFunc:
3137 3138
 *	  dump out only one function,  the index of which is given in the third
 *	argument
3139 3140 3141
 *
 */

3142
static void
B
Bruce Momjian 已提交
3143
dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
3144
			TypeInfo *tinfo, int numTypes)
3145
{
3146
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3147 3148
	PQExpBuffer fn = createPQExpBuffer();
	PQExpBuffer delqry = createPQExpBuffer();
B
Bruce,  
Bruce Momjian 已提交
3149
	PQExpBuffer fnlist = createPQExpBuffer();
B
Bruce Momjian 已提交
3150
	int			j;
3151
	PQExpBuffer asPart = createPQExpBuffer();
3152
	char		func_lang[NAMEDATALEN + 1];
3153 3154 3155 3156
	PGresult   *res;
	int			nlangs;
	int			i_lanname;
	char		query[256];
3157

B
Bruce Momjian 已提交
3158 3159 3160 3161
	char	   *listSep;
	char	   *listSepComma = ",";
	char	   *listSepNone = "";
	char	   *rettypename;
3162

3163 3164 3165 3166 3167
	if (finfo[i].dumped)
		return;
	else
		finfo[i].dumped = 1;

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

3170 3171 3172 3173 3174
	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 已提交
3175
	{
3176 3177
		fprintf(stderr, "dumpOneFunc(): SELECT for procedural language failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
		exit_nicely(g_conn);
B
Bruce Momjian 已提交
3178
	}
3179 3180 3181
	nlangs = PQntuples(res);

	if (nlangs != 1)
B
Bruce Momjian 已提交
3182
	{
3183 3184
		fprintf(stderr, "dumpOneFunc(): procedural language for function %s not found\n", finfo[i].proname);
		exit_nicely(g_conn);
B
Bruce Momjian 已提交
3185 3186
	}

3187
	i_lanname = PQfnumber(res, "lanname");
3188

3189
	/*
B
Bruce Momjian 已提交
3190 3191
	 * See backend/commands/define.c for details of how the 'AS' clause is
	 * used.
3192 3193 3194
	 */
	if (strcmp(finfo[i].probin, "-") != 0)
	{
3195
		appendPQExpBuffer(asPart, "AS ");
3196
		formatStringLiteral(asPart, finfo[i].probin, CONV_ALL);
3197
		if (strcmp(finfo[i].prosrc, "-") != 0)
3198 3199
		{
			appendPQExpBuffer(asPart, ", ");
3200
			formatStringLiteral(asPart, finfo[i].prosrc, PASS_LFTAB);
3201
		}
3202 3203 3204 3205
	}
	else
	{
		if (strcmp(finfo[i].prosrc, "-") != 0)
3206 3207
		{
			appendPQExpBuffer(asPart, "AS ");
3208
			formatStringLiteral(asPart, finfo[i].prosrc, PASS_LFTAB);
3209
		}
3210 3211
	}

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

3214
	PQclear(res);
B
Bruce Momjian 已提交
3215

B
Bruce Momjian 已提交
3216 3217
	resetPQExpBuffer(fn);
	appendPQExpBuffer(fn, "%s (", fmtId(finfo[i].proname, force_quotes));
3218 3219
	for (j = 0; j < finfo[i].nargs; j++)
	{
B
Bruce Momjian 已提交
3220
		char	   *typname;
3221

3222
		typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j], zeroAsOpaque);
3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237
		if (typname == NULL)
		{
			fprintf(stderr, "Notice: function \"%s\" is not dumped.\n",
					finfo[i].proname);

			fprintf(stderr, "Reason: the %d th argument type name (oid %s) not found.\n",
					j, finfo[i].argtypes[j]);
			resetPQExpBuffer(q);
			resetPQExpBuffer(fn);
			resetPQExpBuffer(delqry);
			resetPQExpBuffer(fnlist);
			resetPQExpBuffer(asPart);
			return;
		}

B
Bruce Momjian 已提交
3238 3239 3240
		appendPQExpBuffer(fn, "%s%s",
						  (j > 0) ? "," : "",
						  typname);
B
Bruce,  
Bruce Momjian 已提交
3241
		appendPQExpBuffer(fnlist, "%s%s",
B
Bruce Momjian 已提交
3242 3243
						  (j > 0) ? "," : "",
						  typname);
3244
	}
B
Bruce Momjian 已提交
3245 3246 3247
	appendPQExpBuffer(fn, ")");

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

3250 3251 3252 3253 3254 3255 3256 3257 3258
	rettypename = findTypeByOid(tinfo, numTypes, finfo[i].prorettype, zeroAsOpaque);

	if (rettypename == NULL)
	{
		fprintf(stderr, "Notice: function \"%s\" is not dumped.\n",
				finfo[i].proname);

		fprintf(stderr, "Reason: return type name (oid %s) not found.\n",
				finfo[i].prorettype);
B
Bruce Momjian 已提交
3259 3260 3261 3262 3263 3264
		resetPQExpBuffer(q);
		resetPQExpBuffer(fn);
		resetPQExpBuffer(delqry);
		resetPQExpBuffer(fnlist);
		resetPQExpBuffer(asPart);
		return;
3265 3266
	}

B
Bruce Momjian 已提交
3267
	resetPQExpBuffer(q);
B
Bruce Momjian 已提交
3268
	appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data);
3269 3270
	appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ",
					  (finfo[i].retset) ? "SETOF " : "",
3271
					  rettypename,
3272
					  asPart->data);
3273
	formatStringLiteral(q, func_lang, CONV_ALL);
3274

B
Bruce Momjian 已提交
3275
	if (finfo[i].iscachable || finfo[i].isstrict)		/* OR in new attrs here */
3276
	{
3277 3278 3279
		appendPQExpBuffer(q, " WITH (");
		listSep = listSepNone;

B
Bruce Momjian 已提交
3280 3281
		if (finfo[i].iscachable)
		{
3282 3283 3284 3285
			appendPQExpBuffer(q, "%s iscachable", listSep);
			listSep = listSepComma;
		}

B
Bruce Momjian 已提交
3286 3287
		if (finfo[i].isstrict)
		{
3288 3289 3290 3291
			appendPQExpBuffer(q, "%s isstrict", listSep);
			listSep = listSepComma;
		}
		appendPQExpBuffer(q, " )");
3292 3293 3294 3295
	}

	appendPQExpBuffer(q, ";\n");

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

B
Bruce,  
Bruce Momjian 已提交
3299 3300 3301 3302 3303 3304 3305 3306
	/*** Dump Function Comments ***/

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

3307 3308 3309 3310
}

/*
 * dumpOprs
3311
 *	  writes out to fout the queries to recreate all the user-defined operators
3312 3313
 *
 */
3314
void
B
Bruce Momjian 已提交
3315
dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
3316
		 TypeInfo *tinfo, int numTypes)
3317
{
3318 3319 3320 3321 3322 3323
#define OPR_NOTICE(arg) {\
		fprintf(stderr, "Notice: operator \"%s\"(oid %s) is not dumped.\n",oprinfo[i].oprname, oprinfo[i].oid);\
	fprintf(stderr, "Reason: " CppAsString(arg));\
	fprintf (stderr, " (oid %s) not found.\n",oprinfo[i].arg);\
	}

B
Bruce Momjian 已提交
3324
	int			i;
3325
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3326
	PQExpBuffer delq = createPQExpBuffer();
3327 3328 3329 3330 3331 3332 3333 3334
	PQExpBuffer leftarg = createPQExpBuffer();
	PQExpBuffer rightarg = createPQExpBuffer();
	PQExpBuffer commutator = createPQExpBuffer();
	PQExpBuffer negator = createPQExpBuffer();
	PQExpBuffer restrictor = createPQExpBuffer();
	PQExpBuffer join = createPQExpBuffer();
	PQExpBuffer sort1 = createPQExpBuffer();
	PQExpBuffer sort2 = createPQExpBuffer();
3335 3336 3337

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

B
Hi, all  
Bruce Momjian 已提交
3340 3341 3342 3343 3344 3345 3346 3347 3348
		resetPQExpBuffer(leftarg);
		resetPQExpBuffer(rightarg);
		resetPQExpBuffer(commutator);
		resetPQExpBuffer(negator);
		resetPQExpBuffer(restrictor);
		resetPQExpBuffer(join);
		resetPQExpBuffer(sort1);
		resetPQExpBuffer(sort2);

3349
		/* skip all the builtin oids */
3350
		if (atooid(oprinfo[i].oid) <= g_last_builtin_oid)
3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366
			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 已提交
3367 3368
			name = findTypeByOid(tinfo, numTypes,
								 oprinfo[i].oprleft, zeroAsOpaque);
3369 3370 3371 3372 3373
			if (name == NULL)
			{
				OPR_NOTICE(oprleft);
				continue;
			}
B
Bruce Momjian 已提交
3374
			appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ", name);
3375
		}
3376

3377 3378 3379
		if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
			strcmp(oprinfo[i].oprkind, "b") == 0)
		{
B
Bruce Momjian 已提交
3380 3381
			name = findTypeByOid(tinfo, numTypes,
								 oprinfo[i].oprright, zeroAsOpaque);
3382 3383 3384 3385 3386 3387
			if (name == NULL)
			{
				OPR_NOTICE(oprright);
				continue;
			}
			appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ", name);
3388
		}
3389

B
Hi, all  
Bruce Momjian 已提交
3390
		if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
3391 3392 3393 3394 3395 3396 3397 3398 3399
		{
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom);
			if (name == NULL)
			{
				OPR_NOTICE(oprcom);
				continue;
			}
			appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ", name);
		}
3400

B
Hi, all  
Bruce Momjian 已提交
3401
		if (!(strcmp(oprinfo[i].oprnegate, "0") == 0))
3402 3403 3404 3405 3406 3407 3408 3409 3410
		{
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate);
			if (name == NULL)
			{
				OPR_NOTICE(oprnegate);
				continue;
			}
			appendPQExpBuffer(negator, ",\n\tNEGATOR = %s ", name);
		}
3411

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

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

B
Hi, all  
Bruce Momjian 已提交
3418
		if (!(strcmp(oprinfo[i].oprlsortop, "0") == 0))
3419
		{
B
Bruce Momjian 已提交
3420
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprlsortop);
3421 3422 3423 3424 3425 3426 3427
			if (name == NULL)
			{
				OPR_NOTICE(oprlsortop);
				continue;
			}
			appendPQExpBuffer(sort1, ",\n\tSORT1 = %s ", name);
		}
3428

B
Hi, all  
Bruce Momjian 已提交
3429
		if (!(strcmp(oprinfo[i].oprrsortop, "0") == 0))
3430
		{
B
Bruce Momjian 已提交
3431
			name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprrsortop);
3432 3433 3434 3435 3436 3437 3438
			if (name == NULL)
			{
				OPR_NOTICE(oprrsortop);
				continue;
			}
			appendPQExpBuffer(sort2, ",\n\tSORT2 = %s ", name);
		}
3439

B
Bruce Momjian 已提交
3440 3441
		resetPQExpBuffer(delq);
		appendPQExpBuffer(delq, "DROP OPERATOR %s (%s", oprinfo[i].oprname,
B
Bruce Momjian 已提交
3442
		findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft, zeroAsOpaque));
B
Bruce Momjian 已提交
3443
		appendPQExpBuffer(delq, ", %s);\n",
B
Bruce Momjian 已提交
3444
						  findTypeByOid(tinfo, numTypes, oprinfo[i].oprright, zeroAsOpaque));
3445

B
Hi, all  
Bruce Momjian 已提交
3446 3447
		resetPQExpBuffer(q);
		appendPQExpBuffer(q,
3448 3449 3450 3451 3452 3453 3454 3455 3456
						  "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 已提交
3457
		  (strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
3458 3459 3460
						  join->data,
						  sort1->data,
						  sort2->data);
3461

B
Bruce Momjian 已提交
3462
		ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
B
Bruce Momjian 已提交
3463
				q->data, delq->data, "", oprinfo[i].usename, NULL, NULL);
3464
	}
3465 3466 3467 3468
}

/*
 * dumpAggs
3469
 *	  writes out to fout the queries to create all the user-defined aggregates
3470 3471 3472
 *
 */
void
B
Bruce Momjian 已提交
3473
dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
3474
		 TypeInfo *tinfo, int numTypes)
3475
{
3476 3477 3478 3479 3480 3481
#define AGG_NOTICE(arg) {\
		fprintf(stderr, "Notice: aggregate \"%s\"(oid %s) is not dumped.\n",agginfo[i].aggname, agginfo[i].oid);\
	fprintf(stderr, "Reason: " CppAsString(arg) );\
	fprintf (stderr, " (oid %s) not found.\n",agginfo[i].arg);\
	}

B
Bruce Momjian 已提交
3482
	int			i;
3483
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3484 3485
	PQExpBuffer delq = createPQExpBuffer();
	PQExpBuffer aggSig = createPQExpBuffer();
3486
	PQExpBuffer details = createPQExpBuffer();
3487 3488 3489

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

3492
		resetPQExpBuffer(details);
B
Hi, all  
Bruce Momjian 已提交
3493

3494
		/* skip all the builtin oids */
3495
		if (atooid(agginfo[i].oid) <= g_last_builtin_oid)
3496
			continue;
3497

3498 3499 3500 3501 3502 3503 3504
		name = findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsAny + useBaseTypeName);
		if (name == NULL)
		{
			AGG_NOTICE(aggbasetype);
			continue;
		}
		appendPQExpBuffer(details, "BASETYPE = %s, ", name);
3505

3506 3507 3508 3509 3510 3511
		name = findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype, zeroAsOpaque + useBaseTypeName);
		if (name == NULL)
		{
			AGG_NOTICE(aggtranstype);
			continue;
		}
3512 3513
		appendPQExpBuffer(details,
						  "SFUNC = %s, STYPE = %s",
3514
						  agginfo[i].aggtransfn, name);
3515

3516
		if (agginfo[i].agginitval)
3517 3518
		{
			appendPQExpBuffer(details, ", INITCOND = ");
3519
			formatStringLiteral(details, agginfo[i].agginitval, CONV_ALL);
3520
		}
3521

B
Hi, all  
Bruce Momjian 已提交
3522
		if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
3523 3524
			appendPQExpBuffer(details, ", FINALFUNC = %s",
							  agginfo[i].aggfinalfn);
3525

B
Bruce Momjian 已提交
3526 3527
		resetPQExpBuffer(aggSig);
		appendPQExpBuffer(aggSig, "%s %s", agginfo[i].aggname,
B
Bruce Momjian 已提交
3528
						  findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype, zeroAsOpaque + useBaseTypeName));
3529

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

B
Hi, all  
Bruce Momjian 已提交
3533
		resetPQExpBuffer(q);
3534
		appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
3535
						  agginfo[i].aggname,
3536
						  details->data);
3537

B
Bruce Momjian 已提交
3538
		ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
B
Bruce Momjian 已提交
3539
				q->data, delq->data, "", agginfo[i].usename, NULL, NULL);
B
Bruce,  
Bruce Momjian 已提交
3540 3541 3542 3543

		/*** Dump Aggregate Comments ***/

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

3548
	}
3549 3550
}

3551 3552 3553 3554 3555
/*
 * These are some support functions to fix the acl problem of pg_dump
 *
 * Matthew C. Aycock 12/02/97
 */
3556 3557 3558

/* Append a keyword to a keyword list, inserting comma if needed.
 * Caller must make aclbuf big enough for all possible keywords.
3559
 */
3560
static void
B
Bruce Momjian 已提交
3561
AddAcl(char *aclbuf, const char *keyword)
3562
{
3563 3564 3565
	if (*aclbuf)
		strcat(aclbuf, ",");
	strcat(aclbuf, keyword);
3566
}
3567

3568
/*
3569
 * This will take a string of 'arwR' and return a malloced,
3570 3571
 * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
 */
V
Vadim B. Mikheev 已提交
3572
static char *
3573
GetPrivileges(const char *s)
3574
{
3575
	char		aclbuf[100];
3576

3577
	aclbuf[0] = '\0';
3578

B
Bruce Momjian 已提交
3579
	if (strchr(s, 'a'))
3580
		AddAcl(aclbuf, "INSERT");
3581

B
Bruce Momjian 已提交
3582
	if (strchr(s, 'w'))
3583
		AddAcl(aclbuf, "UPDATE,DELETE");
B
Bruce Momjian 已提交
3584 3585

	if (strchr(s, 'r'))
3586
		AddAcl(aclbuf, "SELECT");
3587

3588
	if (strchr(s, 'R'))
3589
		AddAcl(aclbuf, "RULE");
3590

3591 3592 3593
	/* Special-case when they're all there */
	if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
		return strdup("ALL");
3594

3595
	return strdup(aclbuf);
3596
}
3597

B
Bruce Momjian 已提交
3598
/*
B
Bruce Momjian 已提交
3599
 * The name says it all; a function to append a string is the dest
B
Bruce Momjian 已提交
3600 3601
 * is big enough. If not, it does a realloc.
 */
B
Bruce Momjian 已提交
3602 3603
static void
strcatalloc(char **dest, int *dSize, char *src)
B
Bruce Momjian 已提交
3604
{
B
Bruce Momjian 已提交
3605 3606 3607 3608 3609 3610 3611 3612 3613 3614
	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 已提交
3615 3616


B
Bruce Momjian 已提交
3617 3618
/*
 * dumpACL:
3619 3620
 *	  Write out grant/revoke information
 *	  Called for sequences and tables
B
Bruce Momjian 已提交
3621 3622
 */

3623
static void
B
Bruce Momjian 已提交
3624
dumpACL(Archive *fout, TableInfo tbinfo)
B
Bruce Momjian 已提交
3625
{
B
Bruce Momjian 已提交
3626 3627
	const char *acls = tbinfo.relacl;
	char	   *aclbuf,
B
Bruce Momjian 已提交
3628 3629 3630
			   *tok,
			   *eqpos,
			   *priv;
B
Bruce Momjian 已提交
3631
	char	   *sql;
B
Bruce Momjian 已提交
3632
	char		tmp[1024];
B
Bruce Momjian 已提交
3633
	int			sSize = 4096;
3634 3635 3636 3637

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

B
Bruce Momjian 已提交
3638 3639 3640
	/*
	 * Allocate a larginsh buffer for the output SQL.
	 */
B
Bruce Momjian 已提交
3641
	sql = (char *) malloc(sSize);
B
Bruce Momjian 已提交
3642

B
Bruce Momjian 已提交
3643 3644 3645
	/*
	 * Revoke Default permissions for PUBLIC. Is this actually necessary,
	 * or is it just a waste of time?
3646
	 */
B
Bruce Momjian 已提交
3647
	sprintf(sql, "REVOKE ALL on %s from PUBLIC;\n",
3648
			fmtId(tbinfo.relname, force_quotes));
3649 3650 3651

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

3653 3654
	/* Scan comma-separated ACL items */
	for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
3655
	{
3656

B
Bruce Momjian 已提交
3657 3658 3659
		/*
		 * Token may start with '{' and/or '"'.  Actually only the start
		 * of the string should have '{', but we don't verify that.
3660 3661 3662 3663 3664 3665 3666 3667
		 */
		if (*tok == '{')
			tok++;
		if (*tok == '"')
			tok++;

		/* User name is string up to = in tok */
		eqpos = strchr(tok, '=');
B
Bruce Momjian 已提交
3668
		if (!eqpos)
B
Bruce Momjian 已提交
3669
		{
3670 3671
			fprintf(stderr, "Could not parse ACL list ('%s') for '%s'...Exiting!\n",
					acls, tbinfo.relname);
B
Bruce Momjian 已提交
3672 3673 3674
			exit_nicely(g_conn);
		}

B
Bruce Momjian 已提交
3675 3676 3677 3678
		/*
		 * Parse the privileges (right-hand side).	Skip if there are
		 * none.
		 */
3679 3680
		priv = GetPrivileges(eqpos + 1);
		if (*priv)
3681
		{
B
Bruce Momjian 已提交
3682
			sprintf(tmp, "GRANT %s on %s to ",
3683
					priv, fmtId(tbinfo.relname, force_quotes));
B
Bruce Momjian 已提交
3684
			strcatalloc(&sql, &sSize, tmp);
B
Bruce Momjian 已提交
3685 3686 3687

			/*
			 * Note: fmtId() can only be called once per printf, so don't
3688 3689 3690 3691 3692
			 * try to merge printing of username into the above printf.
			 */
			if (eqpos == tok)
			{
				/* Empty left-hand side means "PUBLIC" */
B
Bruce Momjian 已提交
3693
				strcatalloc(&sql, &sSize, "PUBLIC;\n");
3694
			}
3695
			else
3696 3697
			{
				*eqpos = '\0';	/* it's ok to clobber aclbuf */
3698
				if (strncmp(tok, "group ", strlen("group ")) == 0)
B
Bruce Momjian 已提交
3699
					sprintf(tmp, "GROUP %s;\n",
3700 3701
							fmtId(tok + strlen("group "), force_quotes));
				else
B
Bruce Momjian 已提交
3702 3703
					sprintf(tmp, "%s;\n", fmtId(tok, force_quotes));
				strcatalloc(&sql, &sSize, tmp);
3704
			}
3705
		}
3706
		free(priv);
B
Bruce Momjian 已提交
3707
	}
3708 3709

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

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

B
Bruce Momjian 已提交
3713 3714
}

3715

3716 3717
/*
 * dumpTables:
3718
 *	  write out to fout all the user-define tables
3719
 */
3720

3721
void
B
Bruce Momjian 已提交
3722
dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
3723
		   IndInfo *indinfo, int numIndices,
3724 3725
		   InhInfo *inhinfo, int numInherits,
		   TypeInfo *tinfo, int numTypes, const char *tablename,
B
Bruce Momjian 已提交
3726 3727
		   const bool aclsSkip, const bool oids,
		   const bool schemaOnly, const bool dataOnly)
3728
{
3729 3730
	int			i,
				j,
B
Bruce Momjian 已提交
3731
				k;
3732
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3733
	PQExpBuffer delq = createPQExpBuffer();
3734
	char	   *serialSeq = NULL;		/* implicit sequence name created
B
Bruce Momjian 已提交
3735 3736 3737 3738
										 * by SERIAL datatype */
	const char *serialSeqSuffix = "_id_seq";	/* suffix for implicit
												 * SERIAL sequences */
	char	  **parentRels;		/* list of names of parent relations */
3739
	int			numParents;
B
Bruce Momjian 已提交
3740
	int			actual_atts;	/* number of attrs in this CREATE statment */
3741
	char	   *reltypename;
3742

V
Vadim B. Mikheev 已提交
3743
	/* First - dump SEQUENCEs */
3744
	if (tablename && strlen(tablename) > 0)
B
Bruce Momjian 已提交
3745 3746 3747 3748 3749
	{
		serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
		strcpy(serialSeq, tablename);
		strcat(serialSeq, serialSeqSuffix);
	}
V
Vadim B. Mikheev 已提交
3750 3751 3752 3753
	for (i = 0; i < numTables; i++)
	{
		if (!(tblinfo[i].sequence))
			continue;
B
Bruce Momjian 已提交
3754
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
B
Bruce Momjian 已提交
3755
			|| (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
V
Vadim B. Mikheev 已提交
3756
		{
B
Bruce Momjian 已提交
3757
			/* becomeUser(fout, tblinfo[i].usename); */
3758
			dumpSequence(fout, tblinfo[i], schemaOnly, dataOnly);
3759
			if (!aclsSkip)
B
Bruce Momjian 已提交
3760
				dumpACL(fout, tblinfo[i]);
V
Vadim B. Mikheev 已提交
3761 3762
		}
	}
B
Bruce Momjian 已提交
3763
	if (tablename)
B
Bruce Momjian 已提交
3764
		free(serialSeq);
3765

3766 3767
	for (i = 0; i < numTables; i++)
	{
3768
		if (tblinfo[i].sequence)/* already dumped */
V
Vadim B. Mikheev 已提交
3769
			continue;
3770

3771
		if (!tablename || (!strcmp(tblinfo[i].relname, tablename)) || (strlen(tablename) == 0))
3772 3773
		{

3774 3775
			resetPQExpBuffer(delq);
			resetPQExpBuffer(q);
3776

3777 3778 3779 3780
			/* Use the view definition if there is one */
			if (tblinfo[i].viewdef != NULL)
			{
				reltypename = "VIEW";
3781

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

3785 3786
			}
			else
3787
			{
3788
				reltypename = "TABLE";
3789

3790 3791
				parentRels = tblinfo[i].parentRels;
				numParents = tblinfo[i].numParents;
B
Bruce Momjian 已提交
3792

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

3795 3796 3797 3798 3799 3800
				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)
3801
					{
3802 3803 3804 3805 3806 3807
						/* Format properly if not first attr */
						if (actual_atts > 0)
							appendPQExpBuffer(q, ",\n\t");

						/* Attr name & type */
						appendPQExpBuffer(q, "%s %s",
B
Bruce Momjian 已提交
3808 3809
							 fmtId(tblinfo[i].attnames[j], force_quotes),
										  tblinfo[i].atttypedefns[j]);
3810 3811

						/* Default value */
3812
						if (tblinfo[i].adef_expr[j] != NULL && tblinfo[i].inhAttrDef[j] == 0)
3813
							appendPQExpBuffer(q, " DEFAULT %s",
B
Bruce Momjian 已提交
3814
											  tblinfo[i].adef_expr[j]);
3815 3816

						/* Not Null constraint */
3817
						if (tblinfo[i].notnull[j] && tblinfo[i].inhNotNull[j] == 0)
3818 3819 3820 3821
							appendPQExpBuffer(q, " NOT NULL");

						actual_atts++;
					}
3822
				}
B
Hi all  
Bruce Momjian 已提交
3823

3824 3825


3826 3827 3828 3829 3830 3831 3832
				/* 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 已提交
3833
									  tblinfo[i].check_expr[k]);
3834
				}
3835

3836 3837
				/* Primary Key */
				if (tblinfo[i].pkIndexOid != NULL)
3838
				{
B
Bruce Momjian 已提交
3839
					PQExpBuffer consDef;
3840 3841 3842 3843

					/* Find the corresponding index */
					for (k = 0; k < numIndices; k++)
					{
B
Bruce Momjian 已提交
3844
						if (strcmp(indinfo[k].oid, tblinfo[i].pkIndexOid) == 0)
3845 3846 3847 3848 3849 3850
							break;
					}

					if (k >= numIndices)
					{
						fprintf(stderr, "dumpTables(): failed sanity check, could not find index (%s) for PK constraint\n",
B
Bruce Momjian 已提交
3851
								tblinfo[i].pkIndexOid);
3852 3853 3854 3855 3856
						exit_nicely(g_conn);
					}

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

B
Bruce Momjian 已提交
3857
					if ((actual_atts + tblinfo[i].ncheck) > 0)
3858
						appendPQExpBuffer(q, ",\n\t");
3859 3860 3861 3862

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

					destroyPQExpBuffer(consDef);
3863
				}
B
Bruce Momjian 已提交
3864

3865

3866
				appendPQExpBuffer(q, "\n)");
3867

3868
				if (numParents > 0)
B
Hi all  
Bruce Momjian 已提交
3869
				{
3870
					appendPQExpBuffer(q, "\nINHERITS (");
3871 3872 3873
					for (k = 0; k < numParents; k++)
					{
						appendPQExpBuffer(q, "%s%s",
B
Bruce Momjian 已提交
3874 3875
										  (k > 0) ? ", " : "",
									 fmtId(parentRels[k], force_quotes));
3876 3877
					}
					appendPQExpBuffer(q, ")");
B
Hi all  
Bruce Momjian 已提交
3878 3879
				}

3880 3881
				appendPQExpBuffer(q, ";\n");
			}
B
Bruce Momjian 已提交
3882

B
Bruce Momjian 已提交
3883 3884
			if (!dataOnly)
			{
3885

P
Philip Warner 已提交
3886
				ArchiveEntry(fout, tblinfo[i].oid, tblinfo[i].relname,
B
Bruce Momjian 已提交
3887 3888
							 reltypename, NULL, q->data, delq->data, "", tblinfo[i].usename,
							 NULL, NULL);
B
Bruce Momjian 已提交
3889

3890 3891 3892 3893
				if (!aclsSkip)
					dumpACL(fout, tblinfo[i]);

			}
3894

3895
			/* Dump Field Comments */
B
Bruce,  
Bruce Momjian 已提交
3896

3897 3898
			for (j = 0; j < tblinfo[i].numatts; j++)
			{
B
Bruce,  
Bruce Momjian 已提交
3899 3900 3901 3902 3903 3904
				resetPQExpBuffer(q);
				appendPQExpBuffer(q, "COLUMN %s", fmtId(tblinfo[i].relname, force_quotes));
				appendPQExpBuffer(q, ".");
				appendPQExpBuffer(q, "%s", fmtId(tblinfo[i].attnames[j], force_quotes));
				dumpComment(fout, q->data, tblinfo[i].attoids[j]);
			}
3905

B
Bruce,  
Bruce Momjian 已提交
3906
			/* Dump Table Comments */
3907

B
Bruce,  
Bruce Momjian 已提交
3908
			resetPQExpBuffer(q);
3909
			appendPQExpBuffer(q, "%s %s", reltypename, fmtId(tblinfo[i].relname, force_quotes));
B
Bruce,  
Bruce Momjian 已提交
3910
			dumpComment(fout, q->data, tblinfo[i].oid);
3911

3912 3913
		}
	}
3914 3915
}

B
Bruce Momjian 已提交
3916 3917
static PQExpBuffer
getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo)
3918
{
B
Bruce Momjian 已提交
3919 3920 3921
	PQExpBuffer pkBuf = createPQExpBuffer();
	int			k;
	int			indkey;
3922

B
Bruce Momjian 已提交
3923
	resetPQExpBuffer(pkBuf);
3924 3925

	appendPQExpBuffer(pkBuf, "Constraint %s Primary Key (",
B
Bruce Momjian 已提交
3926
					  tblInfo->primary_key_name);
3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942


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

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

		appendPQExpBuffer(pkBuf, "%s%s",
B
Bruce Momjian 已提交
3943 3944
						  (k == 0) ? "" : ", ",
						  fmtId(attname, force_quotes));
3945 3946 3947 3948 3949 3950 3951
	}

	appendPQExpBuffer(pkBuf, ")");

	return pkBuf;
}

3952 3953
/*
 * dumpIndices:
3954
 *	  write out to fout all the user-define indices
3955
 */
3956
void
B
Bruce Momjian 已提交
3957
dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
3958
			TableInfo *tblinfo, int numTables, const char *tablename)
3959
{
3960 3961 3962
	int			i,
				k;
	int			tableInd;
3963
	PQExpBuffer attlist = createPQExpBuffer();
B
Bruce Momjian 已提交
3964 3965 3966
	char	   *classname[INDEX_MAX_KEYS];
	char	   *funcname;		/* the name of the function to comput the
								 * index key from */
3967 3968 3969
	int			indkey,
				indclass;
	int			nclass;
3970

3971
	PQExpBuffer q = createPQExpBuffer(),
B
Bruce Momjian 已提交
3972
				delq = createPQExpBuffer(),
B
Hi, all  
Bruce Momjian 已提交
3973 3974
				id1 = createPQExpBuffer(),
				id2 = createPQExpBuffer();
3975
	PGresult   *res;
3976 3977 3978 3979

	for (i = 0; i < numIndices; i++)
	{
		tableInd = findTableByName(tblinfo, numTables,
3980 3981 3982 3983 3984
								   indinfo[i].indrelname);
		if (tableInd < 0)
		{
			fprintf(stderr, "failed sanity check, table %s was not found\n",
					indinfo[i].indrelname);
3985
			exit(1);
3986
		}
3987

3988 3989 3990 3991 3992 3993
		/* Handle PK indexes */
		if (strcmp(indinfo[i].indisprimary, "t") == 0)
		{
/*
 *			***PK: Enable this code when ALTER TABLE supports PK constraints. ***
 *
B
Bruce Momjian 已提交
3994
 *			PQExpBuffer consDef = getPKconstraint(&tblinfo[tableInd], &indinfo[i]);
3995 3996 3997
 *
 *			resetPQExpBuffer(attlist);
 *
B
Bruce Momjian 已提交
3998
 *			appendPQExpBuffer(attlist, "Alter Table %s Add %s;",
3999 4000 4001
 *								fmtId(tblinfo[tableInd].relname, force_quotes),
 *								consDef->data);
 *
B
Bruce Momjian 已提交
4002
 *			ArchiveEntry(fout, indinfo[i].oid, tblinfo[tableInd].primary_key_name, "CONSTRAINT", NULL,
4003 4004 4005 4006 4007
 *							attlist->data, "",
 *							"", tblinfo[tableInd].usename, NULL, NULL);
 *
 *			destroyPQExpBuffer(consDef);
 */
B
Bruce Momjian 已提交
4008 4009 4010 4011 4012

			/*
			 * Don't need to do anything else for this system-generated
			 * index
			 */
4013 4014 4015 4016
			continue;
		}


4017 4018 4019 4020
		if (strcmp(indinfo[i].indproc, "0") == 0)
			funcname = NULL;
		else
		{
B
Bruce Momjian 已提交
4021
			int			numFuncs;
4022 4023 4024 4025 4026 4027 4028

			/*
			 * 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 已提交
4029 4030
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
4031 4032 4033
							  "SELECT proname from pg_proc "
							  "where pg_proc.oid = '%s'::oid",
							  indinfo[i].indproc);
B
Hi, all  
Bruce Momjian 已提交
4034
			res = PQexec(g_conn, q->data);
4035 4036
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
4037 4038
				fprintf(stderr, "dumpIndices(): SELECT (funcname) failed.  "
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4039 4040
				exit_nicely(g_conn);
			}
4041 4042 4043

			/* Sanity: Check we got only one tuple */
			numFuncs = PQntuples(res);
B
Bruce Momjian 已提交
4044 4045 4046 4047
			if (numFuncs != 1)
			{
				fprintf(stderr, "dumpIndices(): SELECT (funcname) for index %s returned %d tuples. Expected 1.\n",
						indinfo[i].indrelname, numFuncs);
4048 4049 4050
				exit_nicely(g_conn);
			}

B
Bruce Momjian 已提交
4051
			funcname = strdup(PQgetvalue(res, 0, PQfnumber(res, "proname")));
4052 4053 4054 4055 4056 4057
			PQclear(res);
		}

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

4060 4061 4062
			indclass = atoi(indinfo[i].indclass[nclass]);
			if (indclass == 0)
				break;
B
Hi, all  
Bruce Momjian 已提交
4063 4064
			resetPQExpBuffer(q);
			appendPQExpBuffer(q,
4065 4066 4067
							  "SELECT opcname from pg_opclass "
							  "where pg_opclass.oid = '%u'::oid",
							  indclass);
B
Hi, all  
Bruce Momjian 已提交
4068
			res = PQexec(g_conn, q->data);
4069 4070
			if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
			{
B
Bruce Momjian 已提交
4071
				fprintf(stderr, "dumpIndices(): SELECT (classname) failed.  "
B
Bruce Momjian 已提交
4072
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4073 4074
				exit_nicely(g_conn);
			}
4075 4076 4077

			/* Sanity: Check we got only one tuple */
			numRows = PQntuples(res);
B
Bruce Momjian 已提交
4078 4079 4080 4081
			if (numRows != 1)
			{
				fprintf(stderr, "dumpIndices(): SELECT (classname) for index %s returned %d tuples. Expected 1.\n",
						indinfo[i].indrelname, numRows);
4082 4083 4084
				exit_nicely(g_conn);
			}

B
Bruce Momjian 已提交
4085
			classname[nclass] = strdup(PQgetvalue(res, 0, PQfnumber(res, "opcname")));
4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096
			PQclear(res);
		}

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

		/* convert attribute numbers into attribute list */
B
Hi, all  
Bruce Momjian 已提交
4097 4098
		resetPQExpBuffer(attlist);
		for (k = 0; k < INDEX_MAX_KEYS; k++)
4099
		{
4100
			char	   *attname;
4101 4102

			indkey = atoi(indinfo[i].indkey[k]);
B
Bruce Momjian 已提交
4103
			if (indkey == InvalidAttrNumber)
4104 4105 4106 4107 4108 4109 4110
				break;
			indkey--;
			if (indkey == ObjectIdAttributeNumber - 1)
				attname = "oid";
			else
				attname = tblinfo[tableInd].attnames[indkey];
			if (funcname)
B
Hi, all  
Bruce Momjian 已提交
4111
				appendPQExpBuffer(attlist, "%s%s",
B
Bruce Momjian 已提交
4112
					 (k == 0) ? "" : ", ", fmtId(attname, force_quotes));
4113 4114 4115 4116 4117
			else
			{
				if (k >= nclass)
				{
					fprintf(stderr, "dumpIndices(): OpClass not found for "
4118
							"attribute '%s' of index '%s'\n",
4119 4120 4121
							attname, indinfo[i].indexrelname);
					exit_nicely(g_conn);
				}
B
Hi, all  
Bruce Momjian 已提交
4122 4123 4124 4125 4126
				resetPQExpBuffer(id1);
				resetPQExpBuffer(id2);
				appendPQExpBuffer(id1, fmtId(attname, force_quotes));
				appendPQExpBuffer(id2, fmtId(classname[k], force_quotes));
				appendPQExpBuffer(attlist, "%s%s %s",
4127
							 (k == 0) ? "" : ", ", id1->data, id2->data);
4128 4129 4130 4131
				free(classname[k]);
			}
		}

B
Bruce Momjian 已提交
4132
		if (!tablename || (strcmp(indinfo[i].indrelname, tablename) == 0) || (strlen(tablename) == 0))
4133
		{
B
Bruce Momjian 已提交
4134 4135 4136 4137 4138

			/*
			 * 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.
4139
			 */
4140

B
Hi, all  
Bruce Momjian 已提交
4141 4142 4143 4144
			resetPQExpBuffer(id1);
			resetPQExpBuffer(id2);
			appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
			appendPQExpBuffer(id2, fmtId(indinfo[i].indrelname, force_quotes));
4145

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

B
Bruce Momjian 已提交
4149 4150
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "CREATE %s INDEX %s on %s using %s (",
B
Bruce Momjian 已提交
4151 4152 4153 4154
			  (strcmp(indinfo[i].indisunique, "t") == 0) ? "UNIQUE" : "",
							  id1->data,
							  id2->data,
							  indinfo[i].indamname);
4155 4156
			if (funcname)
			{
4157
				/* need 2 printf's here cuz fmtId has static return area */
B
Bruce Momjian 已提交
4158
				appendPQExpBuffer(q, " %s", fmtId(funcname, false));
B
Bruce Momjian 已提交
4159 4160
				appendPQExpBuffer(q, " (%s) %s );\n", attlist->data,
								  fmtId(classname[0], force_quotes));
4161 4162 4163 4164
				free(funcname);
				free(classname[0]);
			}
			else
B
Bruce Momjian 已提交
4165
				appendPQExpBuffer(q, " %s );\n", attlist->data);
B
Bruce,  
Bruce Momjian 已提交
4166 4167 4168

			/* Dump Index Comments */

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

B
Bruce,  
Bruce Momjian 已提交
4172 4173 4174
			resetPQExpBuffer(q);
			appendPQExpBuffer(q, "INDEX %s", id1->data);
			dumpComment(fout, q->data, indinfo[i].indoid);
4175

4176 4177
		}
	}
4178 4179

}
4180

4181
/*
B
Bruce Momjian 已提交
4182
 * dumpTuples
4183 4184 4185 4186 4187
 *	  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
4188
 *	  in PostgreSQL.
4189 4190 4191 4192
 *
 * the attrmap passed in tells how to map the attributes copied in to the
 * attributes copied out
 */
4193
#ifdef NOT_USED
4194
void
4195
dumpTuples(PGresult *res, FILE *fout, int *attrmap)
4196
{
4197 4198 4199 4200
	int			j,
				k;
	int			m,
				n;
B
Bruce Momjian 已提交
4201
	char	  **outVals = NULL; /* values to copy out */
4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220

	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++)
			{
4221
				char	   *pval = outVals[k];
4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241

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

4244
#endif
4245

4246 4247 4248 4249
/*
 * setMaxOid -
 * find the maximum oid and generate a COPY statement to set it
*/
4250

4251
static void
B
Bruce Momjian 已提交
4252
setMaxOid(Archive *fout)
4253
{
B
Bruce Momjian 已提交
4254 4255
	PGresult   *res;
	Oid			max_oid;
B
Bruce Momjian 已提交
4256
	char		sql[1024];
B
Bruce Momjian 已提交
4257
	int			pos;
4258

4259
	res = PQexec(g_conn, "CREATE TEMPORARY TABLE pgdump_oid (dummy int4)");
4260 4261 4262
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4263
		fprintf(stderr, "Can not create pgdump_oid table.  "
B
Bruce Momjian 已提交
4264
			"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4265 4266 4267
		exit_nicely(g_conn);
	}
	PQclear(res);
4268
	res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
4269 4270 4271
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4272
		fprintf(stderr, "Can not insert into pgdump_oid table.  "
B
Bruce Momjian 已提交
4273
			"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4274 4275 4276 4277 4278 4279 4280 4281 4282
		exit_nicely(g_conn);
	}
	max_oid = atol(PQoidStatus(res));
	if (max_oid == 0)
	{
		fprintf(stderr, "Invalid max id in setMaxOid\n");
		exit_nicely(g_conn);
	}
	PQclear(res);
4283
	res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
4284 4285 4286
	if (!res ||
		PQresultStatus(res) != PGRES_COMMAND_OK)
	{
4287
		fprintf(stderr, "Can not drop pgdump_oid table.  "
B
Bruce Momjian 已提交
4288
			"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4289 4290 4291 4292
		exit_nicely(g_conn);
	}
	PQclear(res);
	if (g_verbose)
4293
		fprintf(stderr, "%s maximum system oid is %u %s\n",
4294
				g_comment_start, max_oid, g_comment_end);
4295
	pos = snprintf(sql, 1024, "CREATE TEMPORARY TABLE pgdump_oid (dummy int4);\n");
B
Bruce Momjian 已提交
4296 4297 4298 4299
	pos = pos + snprintf(sql + pos, 1024 - pos, "COPY pgdump_oid WITH OIDS FROM stdin;\n");
	pos = pos + snprintf(sql + pos, 1024 - pos, "%-d\t0\n", max_oid);
	pos = pos + snprintf(sql + pos, 1024 - pos, "\\.\n");
	pos = pos + snprintf(sql + pos, 1024 - pos, "DROP TABLE pgdump_oid;\n");
B
Bruce Momjian 已提交
4300

4301
	ArchiveEntry(fout, "0", "Max OID", "<Init>", NULL, sql, "", "", "", NULL, NULL);
4302
}
4303 4304 4305

/*
 * findLastBuiltInOid -
4306
 * find the last built in oid
4307 4308
 * we do this by retrieving datlastsysoid from the pg_database entry for this database,
 */
4309

4310
static Oid
B
Bruce Momjian 已提交
4311
findLastBuiltinOid(const char *dbname)
4312
{
B
Bruce Momjian 已提交
4313
	PGresult   *res;
4314
	int			ntups;
4315
	Oid			last_oid;
4316 4317 4318
	PQExpBuffer query = createPQExpBuffer();

	resetPQExpBuffer(query);
4319
	appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
4320
	formatStringLiteral(query, dbname, CONV_ALL);
4321

4322
	res = PQexec(g_conn, query->data);
4323 4324 4325
	if (res == NULL ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
4326
		fprintf(stderr, "pg_dump: error in finding the last system OID");
4327
		fprintf(stderr, "Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4328 4329 4330
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);
4331
	if (ntups < 1)
4332
	{
4333 4334
		fprintf(stderr, "pg_dump: couldn't find the pg_database entry.\n");
		fprintf(stderr, "There is no entry in the 'pg_database' table for this database.\n");
4335 4336 4337 4338
		exit_nicely(g_conn);
	}
	if (ntups > 1)
	{
4339 4340
		fprintf(stderr, "pg_dump: found more than one matching database.\n");
		fprintf(stderr, "There is more than one entry for this database in the 'pg_database' table\n");
4341 4342
		exit_nicely(g_conn);
	}
4343
	last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
4344 4345
	PQclear(res);
	return last_oid;
4346 4347 4348
}


4349
static void
4350
dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool dataOnly)
4351
{
4352
	PGresult   *res;
B
Bruce Momjian 已提交
4353
	int4		last,
4354 4355 4356 4357
				incby,
				maxv,
				minv,
				cache;
B
Bruce Momjian 已提交
4358
	char		cycled,
B
Bruce Momjian 已提交
4359
				called;
4360 4361
	const char *t;
	PQExpBuffer query = createPQExpBuffer();
B
Bruce Momjian 已提交
4362
	PQExpBuffer delqry = createPQExpBuffer();
4363

B
Hi, all  
Bruce Momjian 已提交
4364
	appendPQExpBuffer(query,
4365
			"SELECT sequence_name, last_value, increment_by, max_value, "
4366 4367
				  "min_value, cache_value, is_cycled, is_called from %s",
					  fmtId(tbinfo.relname, force_quotes));
4368

B
Hi, all  
Bruce Momjian 已提交
4369
	res = PQexec(g_conn, query->data);
4370 4371
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
4372
		fprintf(stderr, "dumpSequence(%s): SELECT failed.  "
B
Bruce Momjian 已提交
4373
				"Explanation from backend: '%s'.\n", tbinfo.relname, PQerrorMessage(g_conn));
4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402
		exit_nicely(g_conn);
	}

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

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


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

4403
	/*
B
Bruce Momjian 已提交
4404 4405
	 * The logic we use for restoring sequences is as follows: -   Add a
	 * basic CREATE SEQUENCE statement (use last_val for start if called
4406 4407 4408 4409
	 * with 'f', else use min_val for start_val).
	 *
	 *	Add a 'SETVAL(seq, last_val, iscalled)' at restore-time iff
	 *  we load data
4410
	 */
4411

4412 4413 4414
	if (!dataOnly)
	{
		PQclear(res);
4415

4416 4417
		resetPQExpBuffer(delqry);
		appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n", fmtId(tbinfo.relname, force_quotes));
4418

4419 4420
		resetPQExpBuffer(query);
		appendPQExpBuffer(query,
B
Bruce Momjian 已提交
4421
				  "CREATE SEQUENCE %s start %d increment %d maxvalue %d "
4422
						  "minvalue %d  cache %d %s;\n",
B
Bruce Momjian 已提交
4423
						  fmtId(tbinfo.relname, force_quotes),
4424 4425 4426 4427
						  (called == 't') ? minv : last,
						  incby, maxv, minv, cache,
						  (cycled == 't') ? "cycle" : "");

P
Philip Warner 已提交
4428
		ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "SEQUENCE", NULL,
B
Bruce Momjian 已提交
4429
			  query->data, delqry->data, "", tbinfo.usename, NULL, NULL);
4430
	}
4431

4432 4433 4434 4435 4436 4437
	if (!schemaOnly)
	{
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "SELECT setval (");
		formatStringLiteral(query, fmtId(tbinfo.relname, force_quotes), CONV_ALL);
		appendPQExpBuffer(query, ", %d, '%c');\n", last, called);
4438

P
Philip Warner 已提交
4439
		ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "SEQUENCE SET", NULL,
B
Bruce Momjian 已提交
4440
					 query->data, "" /* Del */ , "", "", NULL, NULL);
4441
	}
B
Bruce,  
Bruce Momjian 已提交
4442

4443 4444 4445
	if (!dataOnly)
	{
		/* Dump Sequence Comments */
B
Bruce,  
Bruce Momjian 已提交
4446

4447 4448 4449 4450
		resetPQExpBuffer(query);
		appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo.relname, force_quotes));
		dumpComment(fout, query->data, tbinfo.oid);
	}
4451
}
V
Vadim B. Mikheev 已提交
4452 4453


4454
static void
B
Bruce Momjian 已提交
4455
dumpTriggers(Archive *fout, const char *tablename,
4456
			 TableInfo *tblinfo, int numTables)
V
Vadim B. Mikheev 已提交
4457
{
4458 4459 4460
	int			i,
				j;

V
Vadim B. Mikheev 已提交
4461 4462 4463
	if (g_verbose)
		fprintf(stderr, "%s dumping out triggers %s\n",
				g_comment_start, g_comment_end);
4464

V
Vadim B. Mikheev 已提交
4465 4466
	for (i = 0; i < numTables; i++)
	{
B
Bruce Momjian 已提交
4467
		if (tablename && (strcmp(tblinfo[i].relname, tablename) != 0) && (strlen(tablename) > 0))
V
Vadim B. Mikheev 已提交
4468
			continue;
4469

V
Vadim B. Mikheev 已提交
4470 4471
		for (j = 0; j < tblinfo[i].ntrig; j++)
		{
B
Bruce Momjian 已提交
4472
			ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
B
Bruce Momjian 已提交
4473 4474
				   "TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "", "",
						 tblinfo[i].usename, NULL, NULL);
B
Bruce Momjian 已提交
4475
			dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid);
V
Vadim B. Mikheev 已提交
4476 4477 4478
		}
	}
}
4479 4480


4481
static void
B
Bruce Momjian 已提交
4482
dumpRules(Archive *fout, const char *tablename,
B
Bruce Momjian 已提交
4483
		  TableInfo *tblinfo, int numTables)
4484
{
B
Bruce Momjian 已提交
4485 4486 4487 4488
	PGresult   *res;
	int			nrules;
	int			i,
				t;
4489
	PQExpBuffer query = createPQExpBuffer();
4490

B
Bruce Momjian 已提交
4491
	int			i_definition;
4492
	int			i_oid;
4493
	int			i_owner;
4494
	int			i_rulename;
4495 4496 4497 4498 4499 4500 4501 4502 4503 4504

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

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

		/*
B
Bruce Momjian 已提交
4509 4510
		 * 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).
4511 4512
		 *
		 * XXXX: Use LOJ here
4513
		 */
B
Hi, all  
Bruce Momjian 已提交
4514
		resetPQExpBuffer(query);
4515
		appendPQExpBuffer(query, "SELECT definition,"
4516
						  "   (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
4517 4518
						  "   pg_rewrite.oid, pg_rewrite.rulename "
						  "FROM pg_rewrite, pg_class, pg_rules "
4519
						  "WHERE pg_class.relname = ");
4520
		formatStringLiteral(query, tblinfo[t].relname, CONV_ALL);
4521
		appendPQExpBuffer(query,
4522 4523
						  "    AND pg_rewrite.ev_class = pg_class.oid "
						  "    AND pg_rules.tablename = pg_class.relname "
B
Bruce Momjian 已提交
4524
					   "    AND pg_rules.rulename = pg_rewrite.rulename "
4525
						  "ORDER BY pg_rewrite.oid");
B
Hi, all  
Bruce Momjian 已提交
4526
		res = PQexec(g_conn, query->data);
4527 4528 4529
		if (!res ||
			PQresultStatus(res) != PGRES_TUPLES_OK)
		{
4530
			fprintf(stderr, "dumpRules(): SELECT failed for rules associated with table \"%s\".\n\tExplanation from backend: '%s'.\n",
B
Bruce Momjian 已提交
4531
					tblinfo[t].relname, PQerrorMessage(g_conn));
4532 4533 4534 4535 4536
			exit_nicely(g_conn);
		}

		nrules = PQntuples(res);
		i_definition = PQfnumber(res, "definition");
4537
		i_owner = PQfnumber(res, "viewowner");
B
Bruce,  
Bruce Momjian 已提交
4538 4539
		i_oid = PQfnumber(res, "oid");
		i_rulename = PQfnumber(res, "rulename");
4540 4541 4542 4543

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

4545 4546
		for (i = 0; i < nrules; i++)
		{
B
Bruce Momjian 已提交
4547
			ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
B
Bruce Momjian 已提交
4548 4549
						 "RULE", NULL, PQgetvalue(res, i, i_definition),
						 "", "", PQgetvalue(res, i, i_owner), NULL, NULL);
4550

B
Bruce,  
Bruce Momjian 已提交
4551 4552 4553 4554 4555
			/* Dump rule comments */

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

B
Bruce,  
Bruce Momjian 已提交
4557 4558
		}

4559 4560 4561
		PQclear(res);
	}
}