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.200 2001/04/04 06:47:30 pjw Exp $
26
 *
27
 * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
28
 *
29 30 31 32
 *	 Applied 'insert string' patch from "Marc G. Fournier" <scrappy@ki.net>
 *	 Added '-t table' option
 *	 Added '-a' option
 *	 Added '-da' option
33
 *
34 35
 * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
 *
36 37 38
 *	 - Fixed dumpTable output to output lengths for char and varchar types!
 *	 - Added single. quote to twin single quote expansion for 'insert' string
 *	   mode.
39
 *
40 41
 * Modifications - 7/26/96 - asussman@vidya.com
 *
42
 *	 - Fixed ouput lengths for char and varchar type where the length is variable (-1)
43
 *
44 45
 * Modifications - 6/1/97 - igor@sba.miami.edu
 * - Added functions to free allocated memory used for retrieving
46 47
 *	 indices,tables,inheritance,types,functions and aggregates.
 *	 No more leaks reported by Purify.
48 49 50
 *
 *
 * Modifications - 1/26/98 - pjlobo@euitt.upm.es
51
 *		 - Added support for password authentication
B
Bruce Momjian 已提交
52 53 54 55 56 57
 *
 * 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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

				outputCreate = 1;
				break;

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

902
					}
903
				}
904
				break;
905

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1023
	dbname = argv[optind];
1024

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

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

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

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

1048 1049 1050
		PQclear(res);
	}

1051
	g_last_builtin_oid = findLastBuiltinOid(dbname);
1052

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

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

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

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

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

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

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

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

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

		RestoreArchive(g_fout, ropt);
	}

	CloseArchive(g_fout);
1114

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

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

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

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

	res = PQexec(g_conn, dbQry->data);
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1147 1148
		fprintf(stderr, "getDatabase(): SELECT failed.  Explanation from backend: '%s'.\n",
				PQerrorMessage(g_conn));
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
		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 已提交
1164 1165 1166 1167
	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 */ );
1168 1169 1170 1171 1172 1173 1174

	PQclear(res);

	return 1;
}


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

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

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

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

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

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

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

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

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

		/* 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 已提交
1234
						"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1235 1236 1237 1238 1239 1240
				exit_nicely(g_conn);
			}

			StartBlob(AH, blobOid);

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

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

			} while (cnt > 0);

			lo_close(g_conn, loFd);

			EndBlob(AH, blobOid);

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

	return 1;
}

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

	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;
1297
	int			i_typedefn;
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309

	/* 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 已提交
1310
	appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
B
Bruce Momjian 已提交
1311 1312 1313 1314 1315
		  "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");
1316

B
Hi, all  
Bruce Momjian 已提交
1317
	res = PQexec(g_conn, query->data);
1318 1319 1320
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1321
		fprintf(stderr, "getTypes(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
		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");
1344
	i_typedefn = PQfnumber(res, "typedefn");
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361

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

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

1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
		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;
1387 1388 1389 1390
}

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

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

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

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

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

B
Hi, all  
Bruce Momjian 已提交
1434
	res = PQexec(g_conn, query->data);
1435 1436 1437
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1438
		fprintf(stderr, "getOperators(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1439 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
		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));
1478 1479 1480

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

1483 1484 1485 1486 1487
	}

	PQclear(res);

	return oprinfo;
1488 1489
}

1490
void
1491
clearTypeInfo(TypeInfo *tp, int numTypes)
1492
{
1493
	int			i;
1494 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

	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);
1527 1528 1529
}

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

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

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

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

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

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

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

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

void
1647
clearOprInfo(OprInfo *opr, int numOprs)
1648
{
1649
	int			i;
1650 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

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

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

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

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

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

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

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

	/* find all user-defined aggregates */

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

B
Hi, all  
Bruce Momjian 已提交
1787
	res = PQexec(g_conn, query->data);
1788 1789 1790
	if (!res ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
1791
		fprintf(stderr, "getAggregates(): SELECT failed.  Explanation from backend: '%s'.\n",
B
Bruce Momjian 已提交
1792
				PQerrorMessage(g_conn));
1793 1794 1795 1796 1797 1798 1799 1800 1801 1802
		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");
1803
	i_aggtransfn = PQfnumber(res, "aggtransfn");
1804
	i_aggfinalfn = PQfnumber(res, "aggfinalfn");
1805
	i_aggtranstype = PQfnumber(res, "aggtranstype");
1806
	i_aggbasetype = PQfnumber(res, "aggbasetype");
1807
	i_agginitval = PQfnumber(res, "agginitval");
1808 1809 1810 1811 1812 1813
	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));
1814
		agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
1815
		agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
1816
		agginfo[i].aggtranstype = strdup(PQgetvalue(res, i, i_aggtranstype));
1817
		agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
1818
		agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
1819
		agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1820 1821
		if (strlen(agginfo[i].usename) == 0)
			fprintf(stderr, "WARNING: owner of aggregate '%s' appears to be invalid\n",
B
Bruce Momjian 已提交
1822
					agginfo[i].aggname);
1823

1824 1825 1826 1827 1828
	}

	PQclear(res);

	return agginfo;
1829 1830 1831 1832
}

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

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

	/* find all user-defined funcs */

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

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

	ntups = PQntuples(res);

	*numFuncs = ntups;

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

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

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

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

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

1923 1924 1925 1926
		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);
1927
			exit(1);
1928 1929 1930 1931
		}
		parseNumericArray(PQgetvalue(res, i, i_proargtypes),
						  finfo[i].argtypes,
						  finfo[i].nargs);
1932 1933 1934 1935 1936 1937
		finfo[i].dumped = 0;
	}

	PQclear(res);

	return finfo;
1938 1939 1940 1941 1942

}

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

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

	char		relkindview[2];

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

	/*
	 * 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*
	 *
1979
	 * we ignore tables that are not type 'r' (ordinary relation) or 'S'
1980
	 * (sequence) or 'v' (view).
1981 1982
	 */

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

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

	ntups = PQntuples(res);

	*numTables = ntups;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

B
Hi, all  
Bruce Momjian 已提交
2159
			resetPQExpBuffer(query);
B
Bruce Momjian 已提交
2160
			appendPQExpBuffer(query,
2161
							  "SELECT Oid FROM pg_index i WHERE i.indisprimary AND i.indrelid = %s ",
2162
							  tblinfo[i].oid);
2163
			res2 = PQexec(g_conn, query->data);
B
Bruce Momjian 已提交
2164 2165
			if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
			{
2166 2167
				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 已提交
2168 2169
				exit_nicely(g_conn);
			}
2170

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

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

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

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

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

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

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

2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238
			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 已提交
2239 2240 2241 2242
		/* Get Triggers */
		if (tblinfo[i].ntrig > 0)
		{
			PGresult   *res2;
B
Bruce,  
Bruce Momjian 已提交
2243
			int			i_tgoid,
2244
						i_tgname,
2245 2246 2247
						i_tgfoid,
						i_tgtype,
						i_tgnargs,
2248 2249 2250 2251 2252
						i_tgargs,
						i_tgisconstraint,
						i_tgconstrname,
						i_tgdeferrable,
						i_tginitdeferred;
V
Vadim B. Mikheev 已提交
2253 2254
			int			ntups2;
			int			i2;
2255

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2428 2429 2430
				}

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

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

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

				/*** Initialize trcomments and troids ***/
2475

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

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

2494 2495 2496 2497 2498
	}

	PQclear(res);

	return tblinfo;
2499 2500 2501 2502 2503

}

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

2520
	int			i_inhrelid;
2521
	int			i_inhparent;
2522 2523 2524

	/* find all the inheritance information */

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

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

	ntups = PQntuples(res);

	*numInherits = ntups;

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

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

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

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

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

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

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

		ntups = PQntuples(res);

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

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

			/* 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 已提交
2650
			tblinfo[i].attoids[j] = strdup(PQgetvalue(res, j, i_attoid));
2651
			tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
2652
			tblinfo[i].atttypedefns[j] = strdup(PQgetvalue(res, j, i_atttypedefn));
2653
			tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
2654
			tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
2655 2656
			tblinfo[i].inhAttrs[j] = 0; /* this flag is set in
										 * flagInhAttrs() */
2657 2658 2659
			tblinfo[i].inhAttrDef[j] = 0;
			tblinfo[i].inhNotNull[j] = 0;

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

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

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

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

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


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

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

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

B
Hi, all  
Bruce Momjian 已提交
2745
	appendPQExpBuffer(query,
2746
					  "SELECT i.oid, t1.oid as indoid, t1.relname as indexrelname, t2.relname as indrelname, "
2747
					  "i.indproc, i.indkey, i.indclass, "
B
Bruce Momjian 已提交
2748
				  "a.amname as indamname, i.indisunique, i.indisprimary "
2749 2750 2751
					"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 "
2752
					  "and t2.relname !~ '^pg_' ",
2753
					  g_last_builtin_oid);
2754

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

	ntups = PQntuples(res);

	*numIndices = ntups;

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

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

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

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

B
Bruce,  
Bruce Momjian 已提交
2804
/*------------------------------------------------------------------
2805
 * dumpComments --
B
Bruce,  
Bruce Momjian 已提交
2806
 *
2807
 * This routine is used to dump any comments associated with the
B
Bruce,  
Bruce Momjian 已提交
2808 2809 2810 2811
 * 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
2812
 * addition, the routine takes the stdio FILE handle to which the
B
Bruce,  
Bruce Momjian 已提交
2813 2814 2815 2816
 * output should be written.
 *------------------------------------------------------------------
*/

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

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

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

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

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

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

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

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

	PQclear(res);
2859

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

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

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

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

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

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

	/*** Execute query ***/

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

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

2898 2899
	if (PQntuples(res) != 0)
	{
B
Bruce,  
Bruce Momjian 已提交
2900 2901 2902 2903 2904 2905 2906 2907 2908
		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);
2909

B
Bruce,  
Bruce Momjian 已提交
2910 2911
}

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

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

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

		/* skip all the builtin types */
2934
		if (atooid(tinfo[i].oid) <= g_last_builtin_oid)
2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951
			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)
2952 2953
		{
			(*deps)[depIdx++] = strdup(finfo[funcInd].oid);
2954
			dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
2955
		}
2956 2957 2958

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

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

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

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

2988
			elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
2989 2990 2991 2992 2993 2994 2995 2996 2997
			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;
			}

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

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

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

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

		/*** Dump Type Comments ***/

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

	PQclear(res);

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3221
		typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j], zeroAsOpaque);
3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236
		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 已提交
3237 3238 3239
		appendPQExpBuffer(fn, "%s%s",
						  (j > 0) ? "," : "",
						  typname);
B
Bruce,  
Bruce Momjian 已提交
3240
		appendPQExpBuffer(fnlist, "%s%s",
B
Bruce Momjian 已提交
3241 3242
						  (j > 0) ? "," : "",
						  typname);
3243
	}
B
Bruce Momjian 已提交
3244 3245 3246
	appendPQExpBuffer(fn, ")");

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

3249 3250 3251 3252 3253 3254 3255 3256 3257
	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 已提交
3258 3259 3260 3261 3262 3263
		resetPQExpBuffer(q);
		resetPQExpBuffer(fn);
		resetPQExpBuffer(delqry);
		resetPQExpBuffer(fnlist);
		resetPQExpBuffer(asPart);
		return;
3264 3265
	}

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

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

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

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

	appendPQExpBuffer(q, ";\n");

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

B
Bruce,  
Bruce Momjian 已提交
3298 3299 3300 3301 3302 3303 3304 3305
	/*** 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);

3306 3307 3308 3309
}

/*
 * dumpOprs
3310
 *	  writes out to fout the queries to recreate all the user-defined operators
3311 3312
 *
 */
3313
void
B
Bruce Momjian 已提交
3314
dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
3315
		 TypeInfo *tinfo, int numTypes)
3316
{
3317 3318 3319 3320 3321 3322
#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 已提交
3323
	int			i;
3324
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3325
	PQExpBuffer delq = createPQExpBuffer();
3326 3327 3328 3329 3330 3331 3332 3333
	PQExpBuffer leftarg = createPQExpBuffer();
	PQExpBuffer rightarg = createPQExpBuffer();
	PQExpBuffer commutator = createPQExpBuffer();
	PQExpBuffer negator = createPQExpBuffer();
	PQExpBuffer restrictor = createPQExpBuffer();
	PQExpBuffer join = createPQExpBuffer();
	PQExpBuffer sort1 = createPQExpBuffer();
	PQExpBuffer sort2 = createPQExpBuffer();
3334 3335 3336

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

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

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

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

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

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

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

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

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

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

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

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

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

/*
 * dumpAggs
3468
 *	  writes out to fout the queries to create all the user-defined aggregates
3469 3470 3471
 *
 */
void
B
Bruce Momjian 已提交
3472
dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
3473
		 TypeInfo *tinfo, int numTypes)
3474
{
3475 3476 3477 3478 3479 3480
#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 已提交
3481
	int			i;
3482
	PQExpBuffer q = createPQExpBuffer();
B
Bruce Momjian 已提交
3483 3484
	PQExpBuffer delq = createPQExpBuffer();
	PQExpBuffer aggSig = createPQExpBuffer();
3485
	PQExpBuffer details = createPQExpBuffer();
3486 3487 3488

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

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

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

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

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

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

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

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

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

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

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

		/*** Dump Aggregate Comments ***/

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

3547
	}
3548 3549
}

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

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

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

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

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

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

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

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

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

3594
	return strdup(aclbuf);
3595
}
3596

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


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

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

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

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

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

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

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

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

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

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

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

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

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

B
Bruce Momjian 已提交
3712 3713
}

3714

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

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

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

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

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

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

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

3781 3782
				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);
3783

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

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

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

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

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

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

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

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

3823 3824


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

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

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

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

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

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

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

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

3864

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

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

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

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

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

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

			}
3893

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

3896 3897
			for (j = 0; j < tblinfo[i].numatts; j++)
			{
B
Bruce,  
Bruce Momjian 已提交
3898 3899 3900 3901 3902 3903
				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]);
			}
3904

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

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

3911 3912
		}
	}
3913 3914
}

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

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

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


	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 已提交
3942 3943
						  (k == 0) ? "" : ", ",
						  fmtId(attname, force_quotes));
3944 3945 3946 3947 3948 3949 3950
	}

	appendPQExpBuffer(pkBuf, ")");

	return pkBuf;
}

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

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

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

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

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


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

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

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

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

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

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

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

B
Bruce Momjian 已提交
4084
			classname[nclass] = strdup(PQgetvalue(res, 0, PQfnumber(res, "opcname")));
4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095
			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 已提交
4096 4097
		resetPQExpBuffer(attlist);
		for (k = 0; k < INDEX_MAX_KEYS; k++)
4098
		{
4099
			char	   *attname;
4100 4101

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

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

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

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

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

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

			/* Dump Index Comments */

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

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

4175 4176
		}
	}
4177 4178

}
4179

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

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

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

4243
#endif
4244

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

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

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

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

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

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

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

4321
	res = PQexec(g_conn, query->data);
4322 4323 4324
	if (res == NULL ||
		PQresultStatus(res) != PGRES_TUPLES_OK)
	{
4325
		fprintf(stderr, "pg_dump: error in finding the last system OID");
4326
		fprintf(stderr, "Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
4327 4328 4329
		exit_nicely(g_conn);
	}
	ntups = PQntuples(res);
4330
	if (ntups < 1)
4331
	{
4332 4333
		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");
4334 4335 4336 4337
		exit_nicely(g_conn);
	}
	if (ntups > 1)
	{
4338 4339
		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");
4340 4341
		exit_nicely(g_conn);
	}
4342
	last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
4343 4344
	PQclear(res);
	return last_oid;
4345 4346 4347
}


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

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

B
Hi, all  
Bruce Momjian 已提交
4368
	res = PQexec(g_conn, query->data);
4369 4370
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
B
Bruce Momjian 已提交
4371
		fprintf(stderr, "dumpSequence(%s): SELECT failed.  "
B
Bruce Momjian 已提交
4372
				"Explanation from backend: '%s'.\n", tbinfo.relname, PQerrorMessage(g_conn));
4373 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
		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;

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

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

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

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

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

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

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

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

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


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

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

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

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


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

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

	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 已提交
4504
		if (tablename && (strcmp(tblinfo[t].relname, tablename) != 0) && (strlen(tablename) > 0))
4505 4506 4507
			continue;

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

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

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

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

B
Bruce,  
Bruce Momjian 已提交
4550 4551 4552 4553 4554
			/* 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));
4555

B
Bruce,  
Bruce Momjian 已提交
4556 4557
		}

4558 4559 4560
		PQclear(res);
	}
}