1 /*-------------------------------------------------------------------------
2  *
3  * pg_dump.c
4  *	  pg_dump is a utility for dumping out a postgres database
5  *	  into a script file.
6  *
7  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *	pg_dump will read the system catalogs in a database and dump out a
11  *	script that reproduces the schema in terms of SQL that is understood
12  *	by PostgreSQL
13  *
14  *	Note that pg_dump runs in a transaction-snapshot mode transaction,
15  *	so it sees a consistent snapshot of the database including system
16  *	catalogs. However, it relies in part on various specialized backend
17  *	functions like pg_get_indexdef(), and those things tend to look at
18  *	the currently committed state.  So it is possible to get 'cache
19  *	lookup failed' error if someone performs DDL changes while a dump is
20  *	happening. The window for this sort of thing is from the acquisition
21  *	of the transaction snapshot to getSchemaData() (when pg_dump acquires
22  *	AccessShareLock on every table it intends to dump). It isn't very large,
23  *	but it can happen.
24  *
25  *	http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26  *
27  * IDENTIFICATION
28  *	  src/bin/pg_dump/pg_dump.c
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres_fe.h"
33 
34 #include <unistd.h>
35 #include <ctype.h>
36 #ifdef ENABLE_NLS
37 #include <locale.h>
38 #endif
39 #ifdef HAVE_TERMIOS_H
40 #include <termios.h>
41 #endif
42 
43 #include "getopt_long.h"
44 
45 #include "access/attnum.h"
46 #include "access/sysattr.h"
47 #include "access/transam.h"
48 #include "catalog/pg_am.h"
49 #include "catalog/pg_cast.h"
50 #include "catalog/pg_class.h"
51 #include "catalog/pg_default_acl.h"
52 #include "catalog/pg_largeobject.h"
53 #include "catalog/pg_largeobject_metadata.h"
54 #include "catalog/pg_proc.h"
55 #include "catalog/pg_trigger.h"
56 #include "catalog/pg_type.h"
57 #include "libpq/libpq-fs.h"
58 
59 #include "dumputils.h"
60 #include "parallel.h"
61 #include "pg_backup_db.h"
62 #include "pg_backup_utils.h"
63 #include "pg_dump.h"
64 #include "fe_utils/connect.h"
65 #include "fe_utils/string_utils.h"
66 
67 
68 typedef struct
69 {
70 	const char *descr;			/* comment for an object */
71 	Oid			classoid;		/* object class (catalog OID) */
72 	Oid			objoid;			/* object OID */
73 	int			objsubid;		/* subobject (table column #) */
74 } CommentItem;
75 
76 typedef struct
77 {
78 	const char *provider;		/* label provider of this security label */
79 	const char *label;			/* security label for an object */
80 	Oid			classoid;		/* object class (catalog OID) */
81 	Oid			objoid;			/* object OID */
82 	int			objsubid;		/* subobject (table column #) */
83 } SecLabelItem;
84 
85 typedef enum OidOptions
86 {
87 	zeroAsOpaque = 1,
88 	zeroAsAny = 2,
89 	zeroAsStar = 4,
90 	zeroAsNone = 8
91 } OidOptions;
92 
93 /* global decls */
94 bool		g_verbose;			/* User wants verbose narration of our
95 								 * activities. */
96 
97 /* subquery used to convert user ID (eg, datdba) to user name */
98 static const char *username_subquery;
99 
100 /*
101  * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
102  * FirstNormalObjectId - 1.
103  */
104 static Oid	g_last_builtin_oid; /* value of the last builtin oid */
105 
106 /* The specified names/patterns should to match at least one entity */
107 static int	strict_names = 0;
108 
109 /*
110  * Object inclusion/exclusion lists
111  *
112  * The string lists record the patterns given by command-line switches,
113  * which we then convert to lists of OIDs of matching objects.
114  */
115 static SimpleStringList schema_include_patterns = {NULL, NULL};
116 static SimpleOidList schema_include_oids = {NULL, NULL};
117 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
118 static SimpleOidList schema_exclude_oids = {NULL, NULL};
119 
120 static SimpleStringList table_include_patterns = {NULL, NULL};
121 static SimpleOidList table_include_oids = {NULL, NULL};
122 static SimpleStringList table_exclude_patterns = {NULL, NULL};
123 static SimpleOidList table_exclude_oids = {NULL, NULL};
124 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
125 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
126 
127 
128 char		g_opaque_type[10];	/* name for the opaque type */
129 
130 /* placeholders for the delimiters for comments */
131 char		g_comment_start[10];
132 char		g_comment_end[10];
133 
134 static const CatalogId nilCatalogId = {0, 0};
135 
136 /*
137  * Macro for producing quoted, schema-qualified name of a dumpable object.
138  * Note implicit dependence on "fout"; we should get rid of that argument.
139  */
140 #define fmtQualifiedDumpable(obj) \
141 	fmtQualifiedId(fout->remoteVersion, \
142 				   (obj)->dobj.namespace->dobj.name, \
143 				   (obj)->dobj.name)
144 
145 static void help(const char *progname);
146 static void setup_connection(Archive *AH,
147 				 const char *dumpencoding, const char *dumpsnapshot,
148 				 char *use_role);
149 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
150 static void expand_schema_name_patterns(Archive *fout,
151 							SimpleStringList *patterns,
152 							SimpleOidList *oids,
153 							bool strict_names);
154 static void expand_table_name_patterns(Archive *fout,
155 						   SimpleStringList *patterns,
156 						   SimpleOidList *oids,
157 						   bool strict_names);
158 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
159 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
160 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
161 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
162 static void dumpComment(Archive *fout, const char *type, const char *name,
163 			const char *namespace, const char *owner,
164 			CatalogId catalogId, int subid, DumpId dumpId);
165 static int findComments(Archive *fout, Oid classoid, Oid objoid,
166 			 CommentItem **items);
167 static int	collectComments(Archive *fout, CommentItem **items);
168 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
169 			 const char *namespace, const char *owner,
170 			 CatalogId catalogId, int subid, DumpId dumpId);
171 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
172 			  SecLabelItem **items);
173 static int	collectSecLabels(Archive *fout, SecLabelItem **items);
174 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
175 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
176 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
177 static void dumpType(Archive *fout, TypeInfo *tyinfo);
178 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
179 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
180 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
181 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
182 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
183 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
184 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
185 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
186 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
187 static void dumpFunc(Archive *fout, FuncInfo *finfo);
188 static void dumpCast(Archive *fout, CastInfo *cast);
189 static void dumpTransform(Archive *fout, TransformInfo *transform);
190 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
191 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
192 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
193 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
194 static void dumpCollation(Archive *fout, CollInfo *convinfo);
195 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
196 static void dumpRule(Archive *fout, RuleInfo *rinfo);
197 static void dumpAgg(Archive *fout, AggInfo *agginfo);
198 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
199 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
200 static void dumpTable(Archive *fout, TableInfo *tbinfo);
201 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
202 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
203 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
204 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
205 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
206 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
207 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
208 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
209 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
210 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
211 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
212 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
213 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
214 static void dumpUserMappings(Archive *fout,
215 				 const char *servername, const char *namespace,
216 				 const char *owner, CatalogId catalogId, DumpId dumpId);
217 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
218 
219 static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
220 		const char *type, const char *name, const char *subname,
221 		const char *nspname, const char *owner,
222 		const char *acls, const char *racls,
223 		const char *initacls, const char *initracls);
224 
225 static void getDependencies(Archive *fout);
226 static void BuildArchiveDependencies(Archive *fout);
227 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
228 						 DumpId **dependencies, int *nDeps, int *allocDeps);
229 
230 static DumpableObject *createBoundaryObjects(void);
231 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
232 						DumpableObject *boundaryObjs);
233 
234 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
235 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids);
236 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids);
237 static void buildMatViewRefreshDependencies(Archive *fout);
238 static void getTableDataFKConstraints(void);
239 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
240 						  bool is_agg);
241 static char *format_function_arguments_old(Archive *fout,
242 							  FuncInfo *finfo, int nallargs,
243 							  char **allargtypes,
244 							  char **argmodes,
245 							  char **argnames);
246 static char *format_function_signature(Archive *fout,
247 						  FuncInfo *finfo, bool honor_quotes);
248 static char *convertRegProcReference(Archive *fout,
249 						const char *proc);
250 static char *getFormattedOperatorName(Archive *fout, const char *oproid);
251 static char *convertTSFunction(Archive *fout, Oid funcOid);
252 static Oid	findLastBuiltinOid_V71(Archive *fout, const char *);
253 static Oid	findLastBuiltinOid_V70(Archive *fout);
254 static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
255 static char *myFormatType(const char *typname, int32 typmod);
256 static void getBlobs(Archive *fout);
257 static void dumpBlob(Archive *fout, BlobInfo *binfo);
258 static int	dumpBlobs(Archive *fout, void *arg);
259 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
260 static void dumpDatabase(Archive *AH);
261 static void dumpEncoding(Archive *AH);
262 static void dumpStdStrings(Archive *AH);
263 static void dumpSearchPath(Archive *AH);
264 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
265 								PQExpBuffer upgrade_buffer, Oid pg_type_oid);
266 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
267 								 PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
268 static void binary_upgrade_set_pg_class_oids(Archive *fout,
269 								 PQExpBuffer upgrade_buffer,
270 								 Oid pg_class_oid, bool is_index);
271 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
272 								DumpableObject *dobj,
273 								const char *objtype,
274 								const char *objname,
275 								const char *objnamespace);
276 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
277 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
278 static bool nonemptyReloptions(const char *reloptions);
279 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
280 						const char *prefix, Archive *fout);
281 static char *get_synchronized_snapshot(Archive *fout);
282 static void setupDumpWorker(Archive *AHX);
283 
284 
285 int
main(int argc,char ** argv)286 main(int argc, char **argv)
287 {
288 	int			c;
289 	const char *filename = NULL;
290 	const char *format = "p";
291 	TableInfo  *tblinfo;
292 	int			numTables;
293 	DumpableObject **dobjs;
294 	int			numObjs;
295 	DumpableObject *boundaryObjs;
296 	int			i;
297 	int			optindex;
298 	RestoreOptions *ropt;
299 	Archive    *fout;			/* the script file */
300 	const char *dumpencoding = NULL;
301 	const char *dumpsnapshot = NULL;
302 	char	   *use_role = NULL;
303 	int			numWorkers = 1;
304 	int			compressLevel = -1;
305 	int			plainText = 0;
306 	ArchiveFormat archiveFormat = archUnknown;
307 	ArchiveMode archiveMode;
308 
309 	static DumpOptions dopt;
310 
311 	static struct option long_options[] = {
312 		{"data-only", no_argument, NULL, 'a'},
313 		{"blobs", no_argument, NULL, 'b'},
314 		{"clean", no_argument, NULL, 'c'},
315 		{"create", no_argument, NULL, 'C'},
316 		{"dbname", required_argument, NULL, 'd'},
317 		{"file", required_argument, NULL, 'f'},
318 		{"format", required_argument, NULL, 'F'},
319 		{"host", required_argument, NULL, 'h'},
320 		{"jobs", 1, NULL, 'j'},
321 		{"no-reconnect", no_argument, NULL, 'R'},
322 		{"oids", no_argument, NULL, 'o'},
323 		{"no-owner", no_argument, NULL, 'O'},
324 		{"port", required_argument, NULL, 'p'},
325 		{"schema", required_argument, NULL, 'n'},
326 		{"exclude-schema", required_argument, NULL, 'N'},
327 		{"schema-only", no_argument, NULL, 's'},
328 		{"superuser", required_argument, NULL, 'S'},
329 		{"table", required_argument, NULL, 't'},
330 		{"exclude-table", required_argument, NULL, 'T'},
331 		{"no-password", no_argument, NULL, 'w'},
332 		{"password", no_argument, NULL, 'W'},
333 		{"username", required_argument, NULL, 'U'},
334 		{"verbose", no_argument, NULL, 'v'},
335 		{"no-privileges", no_argument, NULL, 'x'},
336 		{"no-acl", no_argument, NULL, 'x'},
337 		{"compress", required_argument, NULL, 'Z'},
338 		{"encoding", required_argument, NULL, 'E'},
339 		{"help", no_argument, NULL, '?'},
340 		{"version", no_argument, NULL, 'V'},
341 
342 		/*
343 		 * the following options don't have an equivalent short option letter
344 		 */
345 		{"attribute-inserts", no_argument, &dopt.column_inserts, 1},
346 		{"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
347 		{"column-inserts", no_argument, &dopt.column_inserts, 1},
348 		{"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
349 		{"disable-triggers", no_argument, &dopt.disable_triggers, 1},
350 		{"enable-row-security", no_argument, &dopt.enable_row_security, 1},
351 		{"exclude-table-data", required_argument, NULL, 4},
352 		{"if-exists", no_argument, &dopt.if_exists, 1},
353 		{"inserts", no_argument, &dopt.dump_inserts, 1},
354 		{"lock-wait-timeout", required_argument, NULL, 2},
355 		{"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
356 		{"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
357 		{"role", required_argument, NULL, 3},
358 		{"section", required_argument, NULL, 5},
359 		{"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
360 		{"snapshot", required_argument, NULL, 6},
361 		{"strict-names", no_argument, &strict_names, 1},
362 		{"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
363 		{"no-security-labels", no_argument, &dopt.no_security_labels, 1},
364 		{"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
365 		{"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
366 
367 		{NULL, 0, NULL, 0}
368 	};
369 
370 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
371 
372 	/*
373 	 * Initialize what we need for parallel execution, especially for thread
374 	 * support on Windows.
375 	 */
376 	init_parallel_dump_utils();
377 
378 	g_verbose = false;
379 
380 	strcpy(g_comment_start, "-- ");
381 	g_comment_end[0] = '\0';
382 	strcpy(g_opaque_type, "opaque");
383 
384 	progname = get_progname(argv[0]);
385 
386 	/* Set default options based on progname */
387 	if (strcmp(progname, "pg_backup") == 0)
388 		format = "c";
389 
390 	if (argc > 1)
391 	{
392 		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
393 		{
394 			help(progname);
395 			exit_nicely(0);
396 		}
397 		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
398 		{
399 			puts("pg_dump (PostgreSQL) " PG_VERSION);
400 			exit_nicely(0);
401 		}
402 	}
403 
404 	InitDumpOptions(&dopt);
405 
406 	while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:",
407 							long_options, &optindex)) != -1)
408 	{
409 		switch (c)
410 		{
411 			case 'a':			/* Dump data only */
412 				dopt.dataOnly = true;
413 				break;
414 
415 			case 'b':			/* Dump blobs */
416 				dopt.outputBlobs = true;
417 				break;
418 
419 			case 'c':			/* clean (i.e., drop) schema prior to create */
420 				dopt.outputClean = 1;
421 				break;
422 
423 			case 'C':			/* Create DB */
424 				dopt.outputCreateDB = 1;
425 				break;
426 
427 			case 'd':			/* database name */
428 				dopt.cparams.dbname = pg_strdup(optarg);
429 				break;
430 
431 			case 'E':			/* Dump encoding */
432 				dumpencoding = pg_strdup(optarg);
433 				break;
434 
435 			case 'f':
436 				filename = pg_strdup(optarg);
437 				break;
438 
439 			case 'F':
440 				format = pg_strdup(optarg);
441 				break;
442 
443 			case 'h':			/* server host */
444 				dopt.cparams.pghost = pg_strdup(optarg);
445 				break;
446 
447 			case 'j':			/* number of dump jobs */
448 				numWorkers = atoi(optarg);
449 				break;
450 
451 			case 'n':			/* include schema(s) */
452 				simple_string_list_append(&schema_include_patterns, optarg);
453 				dopt.include_everything = false;
454 				break;
455 
456 			case 'N':			/* exclude schema(s) */
457 				simple_string_list_append(&schema_exclude_patterns, optarg);
458 				break;
459 
460 			case 'o':			/* Dump oids */
461 				dopt.oids = true;
462 				break;
463 
464 			case 'O':			/* Don't reconnect to match owner */
465 				dopt.outputNoOwner = 1;
466 				break;
467 
468 			case 'p':			/* server port */
469 				dopt.cparams.pgport = pg_strdup(optarg);
470 				break;
471 
472 			case 'R':
473 				/* no-op, still accepted for backwards compatibility */
474 				break;
475 
476 			case 's':			/* dump schema only */
477 				dopt.schemaOnly = true;
478 				break;
479 
480 			case 'S':			/* Username for superuser in plain text output */
481 				dopt.outputSuperuser = pg_strdup(optarg);
482 				break;
483 
484 			case 't':			/* include table(s) */
485 				simple_string_list_append(&table_include_patterns, optarg);
486 				dopt.include_everything = false;
487 				break;
488 
489 			case 'T':			/* exclude table(s) */
490 				simple_string_list_append(&table_exclude_patterns, optarg);
491 				break;
492 
493 			case 'U':
494 				dopt.cparams.username = pg_strdup(optarg);
495 				break;
496 
497 			case 'v':			/* verbose */
498 				g_verbose = true;
499 				break;
500 
501 			case 'w':
502 				dopt.cparams.promptPassword = TRI_NO;
503 				break;
504 
505 			case 'W':
506 				dopt.cparams.promptPassword = TRI_YES;
507 				break;
508 
509 			case 'x':			/* skip ACL dump */
510 				dopt.aclsSkip = true;
511 				break;
512 
513 			case 'Z':			/* Compression Level */
514 				compressLevel = atoi(optarg);
515 				if (compressLevel < 0 || compressLevel > 9)
516 				{
517 					write_msg(NULL, "compression level must be in range 0..9\n");
518 					exit_nicely(1);
519 				}
520 				break;
521 
522 			case 0:
523 				/* This covers the long options. */
524 				break;
525 
526 			case 2:				/* lock-wait-timeout */
527 				dopt.lockWaitTimeout = pg_strdup(optarg);
528 				break;
529 
530 			case 3:				/* SET ROLE */
531 				use_role = pg_strdup(optarg);
532 				break;
533 
534 			case 4:				/* exclude table(s) data */
535 				simple_string_list_append(&tabledata_exclude_patterns, optarg);
536 				break;
537 
538 			case 5:				/* section */
539 				set_dump_section(optarg, &dopt.dumpSections);
540 				break;
541 
542 			case 6:				/* snapshot */
543 				dumpsnapshot = pg_strdup(optarg);
544 				break;
545 
546 			default:
547 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
548 				exit_nicely(1);
549 		}
550 	}
551 
552 	/*
553 	 * Non-option argument specifies database name as long as it wasn't
554 	 * already specified with -d / --dbname
555 	 */
556 	if (optind < argc && dopt.cparams.dbname == NULL)
557 		dopt.cparams.dbname = argv[optind++];
558 
559 	/* Complain if any arguments remain */
560 	if (optind < argc)
561 	{
562 		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
563 				progname, argv[optind]);
564 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
565 				progname);
566 		exit_nicely(1);
567 	}
568 
569 	/* --column-inserts implies --inserts */
570 	if (dopt.column_inserts)
571 		dopt.dump_inserts = 1;
572 
573 	if (dopt.dataOnly && dopt.schemaOnly)
574 	{
575 		write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
576 		exit_nicely(1);
577 	}
578 
579 	if (dopt.dataOnly && dopt.outputClean)
580 	{
581 		write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
582 		exit_nicely(1);
583 	}
584 
585 	if (dopt.dump_inserts && dopt.oids)
586 	{
587 		write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
588 		write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
589 		exit_nicely(1);
590 	}
591 
592 	if (dopt.if_exists && !dopt.outputClean)
593 		exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
594 
595 	/* Identify archive format to emit */
596 	archiveFormat = parseArchiveFormat(format, &archiveMode);
597 
598 	/* archiveFormat specific setup */
599 	if (archiveFormat == archNull)
600 		plainText = 1;
601 
602 	/* Custom and directory formats are compressed by default, others not */
603 	if (compressLevel == -1)
604 	{
605 #ifdef HAVE_LIBZ
606 		if (archiveFormat == archCustom || archiveFormat == archDirectory)
607 			compressLevel = Z_DEFAULT_COMPRESSION;
608 		else
609 #endif
610 			compressLevel = 0;
611 	}
612 
613 #ifndef HAVE_LIBZ
614 	if (compressLevel != 0)
615 		write_msg(NULL, "WARNING: requested compression not available in this "
616 				  "installation -- archive will be uncompressed\n");
617 	compressLevel = 0;
618 #endif
619 
620 	/*
621 	 * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
622 	 * parallel jobs because that's the maximum limit for the
623 	 * WaitForMultipleObjects() call.
624 	 */
625 	if (numWorkers <= 0
626 #ifdef WIN32
627 		|| numWorkers > MAXIMUM_WAIT_OBJECTS
628 #endif
629 		)
630 		exit_horribly(NULL, "invalid number of parallel jobs\n");
631 
632 	/* Parallel backup only in the directory archive format so far */
633 	if (archiveFormat != archDirectory && numWorkers > 1)
634 		exit_horribly(NULL, "parallel backup only supported by the directory format\n");
635 
636 	/* Open the output file */
637 	fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
638 						 setupDumpWorker);
639 
640 	/* Make dump options accessible right away */
641 	SetArchiveOptions(fout, &dopt, NULL);
642 
643 	/* Register the cleanup hook */
644 	on_exit_close_archive(fout);
645 
646 	/* Let the archiver know how noisy to be */
647 	fout->verbose = g_verbose;
648 
649 	/*
650 	 * We allow the server to be back to 7.0, and up to any minor release of
651 	 * our own major version.  (See also version check in pg_dumpall.c.)
652 	 */
653 	fout->minRemoteVersion = 70000;
654 	fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
655 
656 	fout->numWorkers = numWorkers;
657 
658 	/*
659 	 * Open the database using the Archiver, so it knows about it. Errors mean
660 	 * death.
661 	 */
662 	ConnectDatabase(fout, &dopt.cparams, false);
663 	setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
664 
665 	/*
666 	 * Disable security label support if server version < v9.1.x (prevents
667 	 * access to nonexistent pg_seclabel catalog)
668 	 */
669 	if (fout->remoteVersion < 90100)
670 		dopt.no_security_labels = 1;
671 
672 	/*
673 	 * On hot standby slaves, never try to dump unlogged table data, since it
674 	 * will just throw an error.
675 	 */
676 	if (fout->isStandby)
677 		dopt.no_unlogged_table_data = true;
678 
679 	/* Select the appropriate subquery to convert user IDs to names */
680 	if (fout->remoteVersion >= 80100)
681 		username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
682 	else if (fout->remoteVersion >= 70300)
683 		username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
684 	else
685 		username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
686 
687 	/* check the version for the synchronized snapshots feature */
688 	if (numWorkers > 1 && fout->remoteVersion < 90200
689 		&& !dopt.no_synchronized_snapshots)
690 		exit_horribly(NULL,
691 		 "Synchronized snapshots are not supported by this server version.\n"
692 		  "Run with --no-synchronized-snapshots instead if you do not need\n"
693 					  "synchronized snapshots.\n");
694 
695 	/* check the version when a snapshot is explicitly specified by user */
696 	if (dumpsnapshot && fout->remoteVersion < 90200)
697 		exit_horribly(NULL,
698 		   "Exported snapshots are not supported by this server version.\n");
699 
700 	/*
701 	 * Find the last built-in OID, if needed (prior to 8.1)
702 	 *
703 	 * With 8.1 and above, we can just use FirstNormalObjectId - 1.
704 	 */
705 	if (fout->remoteVersion < 80100)
706 	{
707 		if (fout->remoteVersion >= 70100)
708 			g_last_builtin_oid = findLastBuiltinOid_V71(fout,
709 												  PQdb(GetConnection(fout)));
710 		else
711 			g_last_builtin_oid = findLastBuiltinOid_V70(fout);
712 	}
713 	else
714 		g_last_builtin_oid = FirstNormalObjectId - 1;
715 
716 	if (g_verbose)
717 		write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
718 
719 	/* Expand schema selection patterns into OID lists */
720 	if (schema_include_patterns.head != NULL)
721 	{
722 		expand_schema_name_patterns(fout, &schema_include_patterns,
723 									&schema_include_oids,
724 									strict_names);
725 		if (schema_include_oids.head == NULL)
726 			exit_horribly(NULL, "no matching schemas were found\n");
727 	}
728 	expand_schema_name_patterns(fout, &schema_exclude_patterns,
729 								&schema_exclude_oids,
730 								false);
731 	/* non-matching exclusion patterns aren't an error */
732 
733 	/* Expand table selection patterns into OID lists */
734 	if (table_include_patterns.head != NULL)
735 	{
736 		expand_table_name_patterns(fout, &table_include_patterns,
737 								   &table_include_oids,
738 								   strict_names);
739 		if (table_include_oids.head == NULL)
740 			exit_horribly(NULL, "no matching tables were found\n");
741 	}
742 	expand_table_name_patterns(fout, &table_exclude_patterns,
743 							   &table_exclude_oids,
744 							   false);
745 
746 	expand_table_name_patterns(fout, &tabledata_exclude_patterns,
747 							   &tabledata_exclude_oids,
748 							   false);
749 
750 	/* non-matching exclusion patterns aren't an error */
751 
752 	/*
753 	 * Dumping blobs is now default unless we saw an inclusion switch or -s
754 	 * ... but even if we did see one of these, -b turns it back on.
755 	 */
756 	if (dopt.include_everything && !dopt.schemaOnly)
757 		dopt.outputBlobs = true;
758 
759 	/*
760 	 * Now scan the database and create DumpableObject structs for all the
761 	 * objects we intend to dump.
762 	 */
763 	tblinfo = getSchemaData(fout, &numTables);
764 
765 	if (fout->remoteVersion < 80400)
766 		guessConstraintInheritance(tblinfo, numTables);
767 
768 	if (!dopt.schemaOnly)
769 	{
770 		getTableData(&dopt, tblinfo, numTables, dopt.oids);
771 		buildMatViewRefreshDependencies(fout);
772 		if (dopt.dataOnly)
773 			getTableDataFKConstraints();
774 	}
775 
776 	/*
777 	 * In binary-upgrade mode, we do not have to worry about the actual blob
778 	 * data or the associated metadata that resides in the pg_largeobject and
779 	 * pg_largeobject_metadata tables, respectivly.
780 	 *
781 	 * However, we do need to collect blob information as there may be
782 	 * comments or other information on blobs that we do need to dump out.
783 	 */
784 	if (dopt.outputBlobs || dopt.binary_upgrade)
785 		getBlobs(fout);
786 
787 	/*
788 	 * Collect dependency data to assist in ordering the objects.
789 	 */
790 	getDependencies(fout);
791 
792 	/* Lastly, create dummy objects to represent the section boundaries */
793 	boundaryObjs = createBoundaryObjects();
794 
795 	/* Get pointers to all the known DumpableObjects */
796 	getDumpableObjects(&dobjs, &numObjs);
797 
798 	/*
799 	 * Add dummy dependencies to enforce the dump section ordering.
800 	 */
801 	addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
802 
803 	/*
804 	 * Sort the objects into a safe dump order (no forward references).
805 	 *
806 	 * In 7.3 or later, we can rely on dependency information to help us
807 	 * determine a safe order, so the initial sort is mostly for cosmetic
808 	 * purposes: we sort by name to ensure that logically identical schemas
809 	 * will dump identically.  Before 7.3 we don't have dependencies and we
810 	 * use OID ordering as an (unreliable) guide to creation order.
811 	 */
812 	if (fout->remoteVersion >= 70300)
813 		sortDumpableObjectsByTypeName(dobjs, numObjs);
814 	else
815 		sortDumpableObjectsByTypeOid(dobjs, numObjs);
816 
817 	/* If we do a parallel dump, we want the largest tables to go first */
818 	if (archiveFormat == archDirectory && numWorkers > 1)
819 		sortDataAndIndexObjectsBySize(dobjs, numObjs);
820 
821 	sortDumpableObjects(dobjs, numObjs,
822 						boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
823 
824 	/*
825 	 * Create archive TOC entries for all the objects to be dumped, in a safe
826 	 * order.
827 	 */
828 
829 	/* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
830 	dumpEncoding(fout);
831 	dumpStdStrings(fout);
832 	dumpSearchPath(fout);
833 
834 	/* The database item is always next, unless we don't want it at all */
835 	if (dopt.include_everything && !dopt.dataOnly)
836 		dumpDatabase(fout);
837 
838 	/* Now the rearrangeable objects. */
839 	for (i = 0; i < numObjs; i++)
840 		dumpDumpableObject(fout, dobjs[i]);
841 
842 	/*
843 	 * Set up options info to ensure we dump what we want.
844 	 */
845 	ropt = NewRestoreOptions();
846 	ropt->filename = filename;
847 
848 	/* if you change this list, see dumpOptionsFromRestoreOptions */
849 	ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
850 	ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
851 	ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
852 	ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
853 	ropt->cparams.promptPassword = dopt.cparams.promptPassword;
854 	ropt->dropSchema = dopt.outputClean;
855 	ropt->dataOnly = dopt.dataOnly;
856 	ropt->schemaOnly = dopt.schemaOnly;
857 	ropt->if_exists = dopt.if_exists;
858 	ropt->column_inserts = dopt.column_inserts;
859 	ropt->dumpSections = dopt.dumpSections;
860 	ropt->aclsSkip = dopt.aclsSkip;
861 	ropt->superuser = dopt.outputSuperuser;
862 	ropt->createDB = dopt.outputCreateDB;
863 	ropt->noOwner = dopt.outputNoOwner;
864 	ropt->noTablespace = dopt.outputNoTablespaces;
865 	ropt->disable_triggers = dopt.disable_triggers;
866 	ropt->use_setsessauth = dopt.use_setsessauth;
867 	ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
868 	ropt->dump_inserts = dopt.dump_inserts;
869 	ropt->no_security_labels = dopt.no_security_labels;
870 	ropt->lockWaitTimeout = dopt.lockWaitTimeout;
871 	ropt->include_everything = dopt.include_everything;
872 	ropt->enable_row_security = dopt.enable_row_security;
873 	ropt->binary_upgrade = dopt.binary_upgrade;
874 
875 	if (compressLevel == -1)
876 		ropt->compression = 0;
877 	else
878 		ropt->compression = compressLevel;
879 
880 	ropt->suppressDumpWarnings = true;	/* We've already shown them */
881 
882 	SetArchiveOptions(fout, &dopt, ropt);
883 
884 	/* Mark which entries should be output */
885 	ProcessArchiveRestoreOptions(fout);
886 
887 	/*
888 	 * The archive's TOC entries are now marked as to which ones will actually
889 	 * be output, so we can set up their dependency lists properly. This isn't
890 	 * necessary for plain-text output, though.
891 	 */
892 	if (!plainText)
893 		BuildArchiveDependencies(fout);
894 
895 	/*
896 	 * And finally we can do the actual output.
897 	 *
898 	 * Note: for non-plain-text output formats, the output file is written
899 	 * inside CloseArchive().  This is, um, bizarre; but not worth changing
900 	 * right now.
901 	 */
902 	if (plainText)
903 		RestoreArchive(fout);
904 
905 	CloseArchive(fout);
906 
907 	exit_nicely(0);
908 }
909 
910 
911 static void
help(const char * progname)912 help(const char *progname)
913 {
914 	printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
915 	printf(_("Usage:\n"));
916 	printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
917 
918 	printf(_("\nGeneral options:\n"));
919 	printf(_("  -f, --file=FILENAME          output file or directory name\n"));
920 	printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
921 			 "                               plain text (default))\n"));
922 	printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
923 	printf(_("  -v, --verbose                verbose mode\n"));
924 	printf(_("  -V, --version                output version information, then exit\n"));
925 	printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
926 	printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
927 	printf(_("  -?, --help                   show this help, then exit\n"));
928 
929 	printf(_("\nOptions controlling the output content:\n"));
930 	printf(_("  -a, --data-only              dump only the data, not the schema\n"));
931 	printf(_("  -b, --blobs                  include large objects in dump\n"));
932 	printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
933 	printf(_("  -C, --create                 include commands to create database in dump\n"));
934 	printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
935 	printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
936 	printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
937 	printf(_("  -o, --oids                   include OIDs in dump\n"));
938 	printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
939 			 "                               plain-text format\n"));
940 	printf(_("  -s, --schema-only            dump only the schema, no data\n"));
941 	printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
942 	printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
943 	printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
944 	printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
945 	printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
946 	printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
947 	printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
948 	printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
949 	printf(_("  --enable-row-security        enable row security (dump only content user has\n"
950 			 "                               access to)\n"));
951 	printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
952 	printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
953 	printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
954 	printf(_("  --no-security-labels         do not dump security label assignments\n"));
955 	printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
956 	printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
957 	printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
958 	printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
959 	printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
960 	printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
961 	printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
962 	printf(_("  --strict-names               require table and/or schema include patterns to\n"
963 		 "                               match at least one entity each\n"));
964 	printf(_("  --use-set-session-authorization\n"
965 			 "                               use SET SESSION AUTHORIZATION commands instead of\n"
966 			 "                               ALTER OWNER commands to set ownership\n"));
967 
968 	printf(_("\nConnection options:\n"));
969 	printf(_("  -d, --dbname=DBNAME      database to dump\n"));
970 	printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
971 	printf(_("  -p, --port=PORT          database server port number\n"));
972 	printf(_("  -U, --username=NAME      connect as specified database user\n"));
973 	printf(_("  -w, --no-password        never prompt for password\n"));
974 	printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
975 	printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
976 
977 	printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
978 			 "variable value is used.\n\n"));
979 	printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
980 }
981 
982 static void
setup_connection(Archive * AH,const char * dumpencoding,const char * dumpsnapshot,char * use_role)983 setup_connection(Archive *AH, const char *dumpencoding,
984 				 const char *dumpsnapshot, char *use_role)
985 {
986 	DumpOptions *dopt = AH->dopt;
987 	PGconn	   *conn = GetConnection(AH);
988 	const char *std_strings;
989 
990 	if (AH->remoteVersion >= 70300)
991 		PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
992 
993 	/*
994 	 * Set the client encoding if requested.
995 	 */
996 	if (dumpencoding)
997 	{
998 		if (PQsetClientEncoding(conn, dumpencoding) < 0)
999 			exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
1000 						  dumpencoding);
1001 	}
1002 
1003 	/*
1004 	 * Get the active encoding and the standard_conforming_strings setting, so
1005 	 * we know how to escape strings.
1006 	 */
1007 	AH->encoding = PQclientEncoding(conn);
1008 
1009 	std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1010 	AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1011 
1012 	/*
1013 	 * Set the role if requested.  In a parallel dump worker, we'll be passed
1014 	 * use_role == NULL, but AH->use_role is already set (if user specified it
1015 	 * originally) and we should use that.
1016 	 */
1017 	if (!use_role && AH->use_role)
1018 		use_role = AH->use_role;
1019 
1020 	/* Set the role if requested */
1021 	if (use_role && AH->remoteVersion >= 80100)
1022 	{
1023 		PQExpBuffer query = createPQExpBuffer();
1024 
1025 		appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1026 		ExecuteSqlStatement(AH, query->data);
1027 		destroyPQExpBuffer(query);
1028 
1029 		/* save it for possible later use by parallel workers */
1030 		if (!AH->use_role)
1031 			AH->use_role = pg_strdup(use_role);
1032 	}
1033 
1034 	/* Set the datestyle to ISO to ensure the dump's portability */
1035 	ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1036 
1037 	/* Likewise, avoid using sql_standard intervalstyle */
1038 	if (AH->remoteVersion >= 80400)
1039 		ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1040 
1041 	/*
1042 	 * If supported, set extra_float_digits so that we can dump float data
1043 	 * exactly (given correctly implemented float I/O code, anyway)
1044 	 */
1045 	if (AH->remoteVersion >= 90000)
1046 		ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1047 	else if (AH->remoteVersion >= 70400)
1048 		ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1049 
1050 	/*
1051 	 * If synchronized scanning is supported, disable it, to prevent
1052 	 * unpredictable changes in row ordering across a dump and reload.
1053 	 */
1054 	if (AH->remoteVersion >= 80300)
1055 		ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1056 
1057 	/*
1058 	 * Disable timeouts if supported.
1059 	 */
1060 	if (AH->remoteVersion >= 70300)
1061 		ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1062 	if (AH->remoteVersion >= 90300)
1063 		ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1064 	if (AH->remoteVersion >= 90600)
1065 		ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1066 
1067 	/*
1068 	 * Quote all identifiers, if requested.
1069 	 */
1070 	if (quote_all_identifiers && AH->remoteVersion >= 90100)
1071 		ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1072 
1073 	/*
1074 	 * Adjust row-security mode, if supported.
1075 	 */
1076 	if (AH->remoteVersion >= 90500)
1077 	{
1078 		if (dopt->enable_row_security)
1079 			ExecuteSqlStatement(AH, "SET row_security = on");
1080 		else
1081 			ExecuteSqlStatement(AH, "SET row_security = off");
1082 	}
1083 
1084 	/*
1085 	 * Start transaction-snapshot mode transaction to dump consistent data.
1086 	 */
1087 	ExecuteSqlStatement(AH, "BEGIN");
1088 	if (AH->remoteVersion >= 90100)
1089 	{
1090 		/*
1091 		 * To support the combination of serializable_deferrable with the jobs
1092 		 * option we use REPEATABLE READ for the worker connections that are
1093 		 * passed a snapshot.  As long as the snapshot is acquired in a
1094 		 * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1095 		 * REPEATABLE READ transaction provides the appropriate integrity
1096 		 * guarantees.  This is a kluge, but safe for back-patching.
1097 		 */
1098 		if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1099 			ExecuteSqlStatement(AH,
1100 								"SET TRANSACTION ISOLATION LEVEL "
1101 								"SERIALIZABLE, READ ONLY, DEFERRABLE");
1102 		else
1103 			ExecuteSqlStatement(AH,
1104 								"SET TRANSACTION ISOLATION LEVEL "
1105 								"REPEATABLE READ, READ ONLY");
1106 	}
1107 	else if (AH->remoteVersion >= 70400)
1108 	{
1109 		/* note: comma was not accepted in SET TRANSACTION before 8.0 */
1110 		ExecuteSqlStatement(AH,
1111 							"SET TRANSACTION ISOLATION LEVEL "
1112 							"SERIALIZABLE READ ONLY");
1113 	}
1114 	else
1115 		ExecuteSqlStatement(AH,
1116 							"SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
1117 
1118 	/*
1119 	 * If user specified a snapshot to use, select that.  In a parallel dump
1120 	 * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1121 	 * is already set (if the server can handle it) and we should use that.
1122 	 */
1123 	if (dumpsnapshot)
1124 		AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1125 
1126 	if (AH->sync_snapshot_id)
1127 	{
1128 		PQExpBuffer query = createPQExpBuffer();
1129 
1130 		appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1131 		appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1132 		ExecuteSqlStatement(AH, query->data);
1133 		destroyPQExpBuffer(query);
1134 	}
1135 	else if (AH->numWorkers > 1 &&
1136 			 AH->remoteVersion >= 90200 &&
1137 			 !dopt->no_synchronized_snapshots)
1138 	{
1139 		if (AH->isStandby)
1140 			exit_horribly(NULL,
1141 			 "Synchronized snapshots are not supported on standby servers.\n"
1142 						  "Run with --no-synchronized-snapshots instead if you do not need\n"
1143 						  "synchronized snapshots.\n");
1144 
1145 
1146 		AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1147 	}
1148 }
1149 
1150 /* Set up connection for a parallel worker process */
1151 static void
setupDumpWorker(Archive * AH)1152 setupDumpWorker(Archive *AH)
1153 {
1154 	/*
1155 	 * We want to re-select all the same values the master connection is
1156 	 * using.  We'll have inherited directly-usable values in
1157 	 * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1158 	 * inherited encoding value back to a string to pass to setup_connection.
1159 	 */
1160 	setup_connection(AH,
1161 					 pg_encoding_to_char(AH->encoding),
1162 					 NULL,
1163 					 NULL);
1164 }
1165 
1166 static char *
get_synchronized_snapshot(Archive * fout)1167 get_synchronized_snapshot(Archive *fout)
1168 {
1169 	char	   *query = "SELECT pg_catalog.pg_export_snapshot()";
1170 	char	   *result;
1171 	PGresult   *res;
1172 
1173 	res = ExecuteSqlQueryForSingleRow(fout, query);
1174 	result = pg_strdup(PQgetvalue(res, 0, 0));
1175 	PQclear(res);
1176 
1177 	return result;
1178 }
1179 
1180 static ArchiveFormat
parseArchiveFormat(const char * format,ArchiveMode * mode)1181 parseArchiveFormat(const char *format, ArchiveMode *mode)
1182 {
1183 	ArchiveFormat archiveFormat;
1184 
1185 	*mode = archModeWrite;
1186 
1187 	if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1188 	{
1189 		/* This is used by pg_dumpall, and is not documented */
1190 		archiveFormat = archNull;
1191 		*mode = archModeAppend;
1192 	}
1193 	else if (pg_strcasecmp(format, "c") == 0)
1194 		archiveFormat = archCustom;
1195 	else if (pg_strcasecmp(format, "custom") == 0)
1196 		archiveFormat = archCustom;
1197 	else if (pg_strcasecmp(format, "d") == 0)
1198 		archiveFormat = archDirectory;
1199 	else if (pg_strcasecmp(format, "directory") == 0)
1200 		archiveFormat = archDirectory;
1201 	else if (pg_strcasecmp(format, "p") == 0)
1202 		archiveFormat = archNull;
1203 	else if (pg_strcasecmp(format, "plain") == 0)
1204 		archiveFormat = archNull;
1205 	else if (pg_strcasecmp(format, "t") == 0)
1206 		archiveFormat = archTar;
1207 	else if (pg_strcasecmp(format, "tar") == 0)
1208 		archiveFormat = archTar;
1209 	else
1210 		exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1211 	return archiveFormat;
1212 }
1213 
1214 /*
1215  * Find the OIDs of all schemas matching the given list of patterns,
1216  * and append them to the given OID list.
1217  */
1218 static void
expand_schema_name_patterns(Archive * fout,SimpleStringList * patterns,SimpleOidList * oids,bool strict_names)1219 expand_schema_name_patterns(Archive *fout,
1220 							SimpleStringList *patterns,
1221 							SimpleOidList *oids,
1222 							bool strict_names)
1223 {
1224 	PQExpBuffer query;
1225 	PGresult   *res;
1226 	SimpleStringListCell *cell;
1227 	int			i;
1228 
1229 	if (patterns->head == NULL)
1230 		return;					/* nothing to do */
1231 
1232 	if (fout->remoteVersion < 70300)
1233 		exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
1234 
1235 	query = createPQExpBuffer();
1236 
1237 	/*
1238 	 * The loop below runs multiple SELECTs might sometimes result in
1239 	 * duplicate entries in the OID list, but we don't care.
1240 	 */
1241 
1242 	for (cell = patterns->head; cell; cell = cell->next)
1243 	{
1244 		appendPQExpBuffer(query,
1245 						  "SELECT oid FROM pg_catalog.pg_namespace n\n");
1246 		processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1247 							  false, NULL, "n.nspname", NULL, NULL);
1248 
1249 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1250 		if (strict_names && PQntuples(res) == 0)
1251 			exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
1252 
1253 		for (i = 0; i < PQntuples(res); i++)
1254 		{
1255 			simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1256 		}
1257 
1258 		PQclear(res);
1259 		resetPQExpBuffer(query);
1260 	}
1261 
1262 	destroyPQExpBuffer(query);
1263 }
1264 
1265 /*
1266  * Find the OIDs of all tables matching the given list of patterns,
1267  * and append them to the given OID list.
1268  */
1269 static void
expand_table_name_patterns(Archive * fout,SimpleStringList * patterns,SimpleOidList * oids,bool strict_names)1270 expand_table_name_patterns(Archive *fout,
1271 						   SimpleStringList *patterns, SimpleOidList *oids,
1272 						   bool strict_names)
1273 {
1274 	PQExpBuffer query;
1275 	PGresult   *res;
1276 	SimpleStringListCell *cell;
1277 	int			i;
1278 
1279 	if (patterns->head == NULL)
1280 		return;					/* nothing to do */
1281 
1282 	query = createPQExpBuffer();
1283 
1284 	/*
1285 	 * this might sometimes result in duplicate entries in the OID list, but
1286 	 * we don't care.
1287 	 */
1288 
1289 	for (cell = patterns->head; cell; cell = cell->next)
1290 	{
1291 		/*
1292 		 * Query must remain ABSOLUTELY devoid of unqualified names.  This
1293 		 * would be unnecessary given a pg_table_is_visible() variant taking a
1294 		 * search_path argument.
1295 		 */
1296 		appendPQExpBuffer(query,
1297 						  "SELECT c.oid"
1298 						  "\nFROM pg_catalog.pg_class c"
1299 						  "\n     LEFT JOIN pg_catalog.pg_namespace n"
1300 						  "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1301 						  "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1302 						  "\n    (array['%c', '%c', '%c', '%c', '%c'])\n",
1303 						  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1304 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
1305 		processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1306 							  false, "n.nspname", "c.relname", NULL,
1307 							  "pg_catalog.pg_table_is_visible(c.oid)");
1308 
1309 		ExecuteSqlStatement(fout, "RESET search_path");
1310 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1311 		PQclear(ExecuteSqlQueryForSingleRow(fout,
1312 											ALWAYS_SECURE_SEARCH_PATH_SQL));
1313 		if (strict_names && PQntuples(res) == 0)
1314 			exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
1315 
1316 		for (i = 0; i < PQntuples(res); i++)
1317 		{
1318 			simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1319 		}
1320 
1321 		PQclear(res);
1322 		resetPQExpBuffer(query);
1323 	}
1324 
1325 	destroyPQExpBuffer(query);
1326 }
1327 
1328 /*
1329  * checkExtensionMembership
1330  *		Determine whether object is an extension member, and if so,
1331  *		record an appropriate dependency and set the object's dump flag.
1332  *
1333  * It's important to call this for each object that could be an extension
1334  * member.  Generally, we integrate this with determining the object's
1335  * to-be-dumped-ness, since extension membership overrides other rules for that.
1336  *
1337  * Returns true if object is an extension member, else false.
1338  */
1339 static bool
checkExtensionMembership(DumpableObject * dobj,Archive * fout)1340 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1341 {
1342 	ExtensionInfo *ext = findOwningExtension(dobj->catId);
1343 
1344 	if (ext == NULL)
1345 		return false;
1346 
1347 	dobj->ext_member = true;
1348 
1349 	/* Record dependency so that getDependencies needn't deal with that */
1350 	addObjectDependency(dobj, ext->dobj.dumpId);
1351 
1352 	/*
1353 	 * In 9.6 and above, mark the member object to have any non-initial ACL,
1354 	 * policies, and security labels dumped.
1355 	 *
1356 	 * Note that any initial ACLs (see pg_init_privs) will be removed when we
1357 	 * extract the information about the object.  We don't provide support for
1358 	 * initial policies and security labels and it seems unlikely for those to
1359 	 * ever exist, but we may have to revisit this later.
1360 	 *
1361 	 * Prior to 9.6, we do not include any extension member components.
1362 	 *
1363 	 * In binary upgrades, we still dump all components of the members
1364 	 * individually, since the idea is to exactly reproduce the database
1365 	 * contents rather than replace the extension contents with something
1366 	 * different.
1367 	 */
1368 	if (fout->dopt->binary_upgrade)
1369 		dobj->dump = ext->dobj.dump;
1370 	else
1371 	{
1372 		if (fout->remoteVersion < 90600)
1373 			dobj->dump = DUMP_COMPONENT_NONE;
1374 		else
1375 			dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1376 													DUMP_COMPONENT_SECLABEL |
1377 													DUMP_COMPONENT_POLICY);
1378 	}
1379 
1380 	return true;
1381 }
1382 
1383 /*
1384  * selectDumpableNamespace: policy-setting subroutine
1385  *		Mark a namespace as to be dumped or not
1386  */
1387 static void
selectDumpableNamespace(NamespaceInfo * nsinfo,Archive * fout)1388 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1389 {
1390 	/*
1391 	 * If specific tables are being dumped, do not dump any complete
1392 	 * namespaces. If specific namespaces are being dumped, dump just those
1393 	 * namespaces. Otherwise, dump all non-system namespaces.
1394 	 */
1395 	if (table_include_oids.head != NULL)
1396 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1397 	else if (schema_include_oids.head != NULL)
1398 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1399 			simple_oid_list_member(&schema_include_oids,
1400 								   nsinfo->dobj.catId.oid) ?
1401 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1402 	else if (fout->remoteVersion >= 90600 &&
1403 			 strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1404 	{
1405 		/*
1406 		 * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1407 		 * they are interesting (and not the original ACLs which were set at
1408 		 * initdb time, see pg_init_privs).
1409 		 */
1410 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1411 	}
1412 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1413 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
1414 	{
1415 		/* Other system schemas don't get dumped */
1416 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1417 	}
1418 	else
1419 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1420 
1421 	/*
1422 	 * In any case, a namespace can be excluded by an exclusion switch
1423 	 */
1424 	if (nsinfo->dobj.dump_contains &&
1425 		simple_oid_list_member(&schema_exclude_oids,
1426 							   nsinfo->dobj.catId.oid))
1427 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1428 
1429 	/*
1430 	 * If the schema belongs to an extension, allow extension membership to
1431 	 * override the dump decision for the schema itself.  However, this does
1432 	 * not change dump_contains, so this won't change what we do with objects
1433 	 * within the schema.  (If they belong to the extension, they'll get
1434 	 * suppressed by it, otherwise not.)
1435 	 */
1436 	(void) checkExtensionMembership(&nsinfo->dobj, fout);
1437 }
1438 
1439 /*
1440  * selectDumpableTable: policy-setting subroutine
1441  *		Mark a table as to be dumped or not
1442  */
1443 static void
selectDumpableTable(TableInfo * tbinfo,Archive * fout)1444 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1445 {
1446 	if (checkExtensionMembership(&tbinfo->dobj, fout))
1447 		return;					/* extension membership overrides all else */
1448 
1449 	/*
1450 	 * If specific tables are being dumped, dump just those tables; else, dump
1451 	 * according to the parent namespace's dump flag.
1452 	 */
1453 	if (table_include_oids.head != NULL)
1454 		tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1455 												   tbinfo->dobj.catId.oid) ?
1456 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1457 	else
1458 		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1459 
1460 	/*
1461 	 * In any case, a table can be excluded by an exclusion switch
1462 	 */
1463 	if (tbinfo->dobj.dump &&
1464 		simple_oid_list_member(&table_exclude_oids,
1465 							   tbinfo->dobj.catId.oid))
1466 		tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1467 }
1468 
1469 /*
1470  * selectDumpableType: policy-setting subroutine
1471  *		Mark a type as to be dumped or not
1472  *
1473  * If it's a table's rowtype or an autogenerated array type, we also apply a
1474  * special type code to facilitate sorting into the desired order.  (We don't
1475  * want to consider those to be ordinary types because that would bring tables
1476  * up into the datatype part of the dump order.)  We still set the object's
1477  * dump flag; that's not going to cause the dummy type to be dumped, but we
1478  * need it so that casts involving such types will be dumped correctly -- see
1479  * dumpCast.  This means the flag should be set the same as for the underlying
1480  * object (the table or base type).
1481  */
1482 static void
selectDumpableType(TypeInfo * tyinfo,Archive * fout)1483 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1484 {
1485 	/* skip complex types, except for standalone composite types */
1486 	if (OidIsValid(tyinfo->typrelid) &&
1487 		tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1488 	{
1489 		TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1490 
1491 		tyinfo->dobj.objType = DO_DUMMY_TYPE;
1492 		if (tytable != NULL)
1493 			tyinfo->dobj.dump = tytable->dobj.dump;
1494 		else
1495 			tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1496 		return;
1497 	}
1498 
1499 	/* skip auto-generated array types */
1500 	if (tyinfo->isArray)
1501 	{
1502 		tyinfo->dobj.objType = DO_DUMMY_TYPE;
1503 
1504 		/*
1505 		 * Fall through to set the dump flag; we assume that the subsequent
1506 		 * rules will do the same thing as they would for the array's base
1507 		 * type.  (We cannot reliably look up the base type here, since
1508 		 * getTypes may not have processed it yet.)
1509 		 */
1510 	}
1511 
1512 	if (checkExtensionMembership(&tyinfo->dobj, fout))
1513 		return;					/* extension membership overrides all else */
1514 
1515 	/* Dump based on if the contents of the namespace are being dumped */
1516 	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1517 }
1518 
1519 /*
1520  * selectDumpableDefaultACL: policy-setting subroutine
1521  *		Mark a default ACL as to be dumped or not
1522  *
1523  * For per-schema default ACLs, dump if the schema is to be dumped.
1524  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1525  * and aclsSkip are checked separately.
1526  */
1527 static void
selectDumpableDefaultACL(DefaultACLInfo * dinfo,DumpOptions * dopt)1528 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1529 {
1530 	/* Default ACLs can't be extension members */
1531 
1532 	if (dinfo->dobj.namespace)
1533 		/* default ACLs are considered part of the namespace */
1534 		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1535 	else
1536 		dinfo->dobj.dump = dopt->include_everything ?
1537 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1538 }
1539 
1540 /*
1541  * selectDumpableCast: policy-setting subroutine
1542  *		Mark a cast as to be dumped or not
1543  *
1544  * Casts do not belong to any particular namespace (since they haven't got
1545  * names), nor do they have identifiable owners.  To distinguish user-defined
1546  * casts from built-in ones, we must resort to checking whether the cast's
1547  * OID is in the range reserved for initdb.
1548  */
1549 static void
selectDumpableCast(CastInfo * cast,Archive * fout)1550 selectDumpableCast(CastInfo *cast, Archive *fout)
1551 {
1552 	if (checkExtensionMembership(&cast->dobj, fout))
1553 		return;					/* extension membership overrides all else */
1554 
1555 	/*
1556 	 * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1557 	 * support ACLs currently.
1558 	 */
1559 	if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1560 		cast->dobj.dump = DUMP_COMPONENT_NONE;
1561 	else
1562 		cast->dobj.dump = fout->dopt->include_everything ?
1563 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1564 }
1565 
1566 /*
1567  * selectDumpableProcLang: policy-setting subroutine
1568  *		Mark a procedural language as to be dumped or not
1569  *
1570  * Procedural languages do not belong to any particular namespace.  To
1571  * identify built-in languages, we must resort to checking whether the
1572  * language's OID is in the range reserved for initdb.
1573  */
1574 static void
selectDumpableProcLang(ProcLangInfo * plang,Archive * fout)1575 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1576 {
1577 	if (checkExtensionMembership(&plang->dobj, fout))
1578 		return;					/* extension membership overrides all else */
1579 
1580 	/*
1581 	 * Only include procedural languages when we are dumping everything.
1582 	 *
1583 	 * For from-initdb procedural languages, only include ACLs, as we do for
1584 	 * the pg_catalog namespace.  We need this because procedural languages do
1585 	 * not live in any namespace.
1586 	 */
1587 	if (!fout->dopt->include_everything)
1588 		plang->dobj.dump = DUMP_COMPONENT_NONE;
1589 	else
1590 	{
1591 		if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1592 			plang->dobj.dump = fout->remoteVersion < 90600 ?
1593 				DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1594 		else
1595 			plang->dobj.dump = DUMP_COMPONENT_ALL;
1596 	}
1597 }
1598 
1599 /*
1600  * selectDumpableAccessMethod: policy-setting subroutine
1601  *		Mark an access method as to be dumped or not
1602  *
1603  * Access methods do not belong to any particular namespace.  To identify
1604  * built-in access methods, we must resort to checking whether the
1605  * method's OID is in the range reserved for initdb.
1606  */
1607 static void
selectDumpableAccessMethod(AccessMethodInfo * method,Archive * fout)1608 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1609 {
1610 	if (checkExtensionMembership(&method->dobj, fout))
1611 		return;					/* extension membership overrides all else */
1612 
1613 	/*
1614 	 * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1615 	 * they do not support ACLs currently.
1616 	 */
1617 	if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1618 		method->dobj.dump = DUMP_COMPONENT_NONE;
1619 	else
1620 		method->dobj.dump = fout->dopt->include_everything ?
1621 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1622 }
1623 
1624 /*
1625  * selectDumpableExtension: policy-setting subroutine
1626  *		Mark an extension as to be dumped or not
1627  *
1628  * Normally, we dump all extensions, or none of them if include_everything
1629  * is false (i.e., a --schema or --table switch was given).  However, in
1630  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1631  * assume those will already be installed in the target database.  We identify
1632  * such extensions by their having OIDs in the range reserved for initdb.
1633  */
1634 static void
selectDumpableExtension(ExtensionInfo * extinfo,DumpOptions * dopt)1635 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1636 {
1637 	/*
1638 	 * Use DUMP_COMPONENT_ACL for from-initdb extensions, to allow users to
1639 	 * change permissions on those objects, if they wish to, and have those
1640 	 * changes preserved.
1641 	 */
1642 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1643 		extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1644 	else
1645 		extinfo->dobj.dump = extinfo->dobj.dump_contains =
1646 			dopt->include_everything ? DUMP_COMPONENT_ALL :
1647 			DUMP_COMPONENT_NONE;
1648 }
1649 
1650 /*
1651  * selectDumpableObject: policy-setting subroutine
1652  *		Mark a generic dumpable object as to be dumped or not
1653  *
1654  * Use this only for object types without a special-case routine above.
1655  */
1656 static void
selectDumpableObject(DumpableObject * dobj,Archive * fout)1657 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1658 {
1659 	if (checkExtensionMembership(dobj, fout))
1660 		return;					/* extension membership overrides all else */
1661 
1662 	/*
1663 	 * Default policy is to dump if parent namespace is dumpable, or for
1664 	 * non-namespace-associated items, dump if we're dumping "everything".
1665 	 */
1666 	if (dobj->namespace)
1667 		dobj->dump = dobj->namespace->dobj.dump_contains;
1668 	else
1669 		dobj->dump = fout->dopt->include_everything ?
1670 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1671 }
1672 
1673 /*
1674  *	Dump a table's contents for loading using the COPY command
1675  *	- this routine is called by the Archiver when it wants the table
1676  *	  to be dumped.
1677  */
1678 
1679 static int
dumpTableData_copy(Archive * fout,void * dcontext)1680 dumpTableData_copy(Archive *fout, void *dcontext)
1681 {
1682 	TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1683 	TableInfo  *tbinfo = tdinfo->tdtable;
1684 	const char *classname = tbinfo->dobj.name;
1685 	const bool	hasoids = tbinfo->hasoids;
1686 	const bool	oids = tdinfo->oids;
1687 	PQExpBuffer q = createPQExpBuffer();
1688 
1689 	/*
1690 	 * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1691 	 * which uses it already.
1692 	 */
1693 	PQExpBuffer clistBuf = createPQExpBuffer();
1694 	PGconn	   *conn = GetConnection(fout);
1695 	PGresult   *res;
1696 	int			ret;
1697 	char	   *copybuf;
1698 	const char *column_list;
1699 
1700 	if (g_verbose)
1701 		write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
1702 				  tbinfo->dobj.namespace->dobj.name, classname);
1703 
1704 	/*
1705 	 * If possible, specify the column list explicitly so that we have no
1706 	 * possibility of retrieving data in the wrong column order.  (The default
1707 	 * column ordering of COPY will not be what we want in certain corner
1708 	 * cases involving ADD COLUMN and inheritance.)
1709 	 */
1710 	if (fout->remoteVersion >= 70300)
1711 		column_list = fmtCopyColumnList(tbinfo, clistBuf);
1712 	else
1713 		column_list = "";		/* can't select columns in COPY */
1714 
1715 	if (oids && hasoids)
1716 	{
1717 		appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1718 						  fmtQualifiedDumpable(tbinfo),
1719 						  column_list);
1720 	}
1721 	else if (tdinfo->filtercond)
1722 	{
1723 		/* Note: this syntax is only supported in 8.2 and up */
1724 		appendPQExpBufferStr(q, "COPY (SELECT ");
1725 		/* klugery to get rid of parens in column list */
1726 		if (strlen(column_list) > 2)
1727 		{
1728 			appendPQExpBufferStr(q, column_list + 1);
1729 			q->data[q->len - 1] = ' ';
1730 		}
1731 		else
1732 			appendPQExpBufferStr(q, "* ");
1733 		appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1734 						  fmtQualifiedDumpable(tbinfo),
1735 						  tdinfo->filtercond);
1736 	}
1737 	else
1738 	{
1739 		appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1740 						  fmtQualifiedDumpable(tbinfo),
1741 						  column_list);
1742 	}
1743 	res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1744 	PQclear(res);
1745 	destroyPQExpBuffer(clistBuf);
1746 
1747 	for (;;)
1748 	{
1749 		ret = PQgetCopyData(conn, &copybuf, 0);
1750 
1751 		if (ret < 0)
1752 			break;				/* done or error */
1753 
1754 		if (copybuf)
1755 		{
1756 			WriteData(fout, copybuf, ret);
1757 			PQfreemem(copybuf);
1758 		}
1759 
1760 		/* ----------
1761 		 * THROTTLE:
1762 		 *
1763 		 * There was considerable discussion in late July, 2000 regarding
1764 		 * slowing down pg_dump when backing up large tables. Users with both
1765 		 * slow & fast (multi-processor) machines experienced performance
1766 		 * degradation when doing a backup.
1767 		 *
1768 		 * Initial attempts based on sleeping for a number of ms for each ms
1769 		 * of work were deemed too complex, then a simple 'sleep in each loop'
1770 		 * implementation was suggested. The latter failed because the loop
1771 		 * was too tight. Finally, the following was implemented:
1772 		 *
1773 		 * If throttle is non-zero, then
1774 		 *		See how long since the last sleep.
1775 		 *		Work out how long to sleep (based on ratio).
1776 		 *		If sleep is more than 100ms, then
1777 		 *			sleep
1778 		 *			reset timer
1779 		 *		EndIf
1780 		 * EndIf
1781 		 *
1782 		 * where the throttle value was the number of ms to sleep per ms of
1783 		 * work. The calculation was done in each loop.
1784 		 *
1785 		 * Most of the hard work is done in the backend, and this solution
1786 		 * still did not work particularly well: on slow machines, the ratio
1787 		 * was 50:1, and on medium paced machines, 1:1, and on fast
1788 		 * multi-processor machines, it had little or no effect, for reasons
1789 		 * that were unclear.
1790 		 *
1791 		 * Further discussion ensued, and the proposal was dropped.
1792 		 *
1793 		 * For those people who want this feature, it can be implemented using
1794 		 * gettimeofday in each loop, calculating the time since last sleep,
1795 		 * multiplying that by the sleep ratio, then if the result is more
1796 		 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1797 		 * function to sleep for a subsecond period ie.
1798 		 *
1799 		 * select(0, NULL, NULL, NULL, &tvi);
1800 		 *
1801 		 * This will return after the interval specified in the structure tvi.
1802 		 * Finally, call gettimeofday again to save the 'last sleep time'.
1803 		 * ----------
1804 		 */
1805 	}
1806 	archprintf(fout, "\\.\n\n\n");
1807 
1808 	if (ret == -2)
1809 	{
1810 		/* copy data transfer failed */
1811 		write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1812 		write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1813 		write_msg(NULL, "The command was: %s\n", q->data);
1814 		exit_nicely(1);
1815 	}
1816 
1817 	/* Check command status and return to normal libpq state */
1818 	res = PQgetResult(conn);
1819 	if (PQresultStatus(res) != PGRES_COMMAND_OK)
1820 	{
1821 		write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1822 		write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1823 		write_msg(NULL, "The command was: %s\n", q->data);
1824 		exit_nicely(1);
1825 	}
1826 	PQclear(res);
1827 
1828 	/* Do this to ensure we've pumped libpq back to idle state */
1829 	if (PQgetResult(conn) != NULL)
1830 		write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
1831 				  classname);
1832 
1833 	destroyPQExpBuffer(q);
1834 	return 1;
1835 }
1836 
1837 /*
1838  * Dump table data using INSERT commands.
1839  *
1840  * Caution: when we restore from an archive file direct to database, the
1841  * INSERT commands emitted by this function have to be parsed by
1842  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1843  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1844  */
1845 static int
dumpTableData_insert(Archive * fout,void * dcontext)1846 dumpTableData_insert(Archive *fout, void *dcontext)
1847 {
1848 	TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1849 	TableInfo  *tbinfo = tdinfo->tdtable;
1850 	DumpOptions *dopt = fout->dopt;
1851 	PQExpBuffer q = createPQExpBuffer();
1852 	PQExpBuffer insertStmt = NULL;
1853 	PGresult   *res;
1854 	int			tuple;
1855 	int			nfields;
1856 	int			field;
1857 
1858 	if (fout->remoteVersion >= 70100)
1859 	{
1860 		appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1861 						  "SELECT * FROM ONLY %s",
1862 						  fmtQualifiedDumpable(tbinfo));
1863 	}
1864 	else
1865 	{
1866 		appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1867 						  "SELECT * FROM %s",
1868 						  fmtQualifiedDumpable(tbinfo));
1869 	}
1870 	if (tdinfo->filtercond)
1871 		appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1872 
1873 	ExecuteSqlStatement(fout, q->data);
1874 
1875 	while (1)
1876 	{
1877 		res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1878 							  PGRES_TUPLES_OK);
1879 		nfields = PQnfields(res);
1880 		for (tuple = 0; tuple < PQntuples(res); tuple++)
1881 		{
1882 			/*
1883 			 * First time through, we build as much of the INSERT statement as
1884 			 * possible in "insertStmt", which we can then just print for each
1885 			 * line. If the table happens to have zero columns then this will
1886 			 * be a complete statement, otherwise it will end in "VALUES(" and
1887 			 * be ready to have the row's column values appended.
1888 			 */
1889 			if (insertStmt == NULL)
1890 			{
1891 				insertStmt = createPQExpBuffer();
1892 				appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1893 								  fmtQualifiedDumpable(tbinfo));
1894 
1895 				/* corner case for zero-column table */
1896 				if (nfields == 0)
1897 				{
1898 					appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1899 				}
1900 				else
1901 				{
1902 					/* append the list of column names if required */
1903 					if (dopt->column_inserts)
1904 					{
1905 						appendPQExpBufferChar(insertStmt, '(');
1906 						for (field = 0; field < nfields; field++)
1907 						{
1908 							if (field > 0)
1909 								appendPQExpBufferStr(insertStmt, ", ");
1910 							appendPQExpBufferStr(insertStmt,
1911 												 fmtId(PQfname(res, field)));
1912 						}
1913 						appendPQExpBufferStr(insertStmt, ") ");
1914 					}
1915 
1916 					appendPQExpBufferStr(insertStmt, "VALUES (");
1917 				}
1918 			}
1919 
1920 			archputs(insertStmt->data, fout);
1921 
1922 			/* if it is zero-column table then we're done */
1923 			if (nfields == 0)
1924 				continue;
1925 
1926 			for (field = 0; field < nfields; field++)
1927 			{
1928 				if (field > 0)
1929 					archputs(", ", fout);
1930 				if (PQgetisnull(res, tuple, field))
1931 				{
1932 					archputs("NULL", fout);
1933 					continue;
1934 				}
1935 
1936 				/* XXX This code is partially duplicated in ruleutils.c */
1937 				switch (PQftype(res, field))
1938 				{
1939 					case INT2OID:
1940 					case INT4OID:
1941 					case INT8OID:
1942 					case OIDOID:
1943 					case FLOAT4OID:
1944 					case FLOAT8OID:
1945 					case NUMERICOID:
1946 						{
1947 							/*
1948 							 * These types are printed without quotes unless
1949 							 * they contain values that aren't accepted by the
1950 							 * scanner unquoted (e.g., 'NaN').  Note that
1951 							 * strtod() and friends might accept NaN, so we
1952 							 * can't use that to test.
1953 							 *
1954 							 * In reality we only need to defend against
1955 							 * infinity and NaN, so we need not get too crazy
1956 							 * about pattern matching here.
1957 							 */
1958 							const char *s = PQgetvalue(res, tuple, field);
1959 
1960 							if (strspn(s, "0123456789 +-eE.") == strlen(s))
1961 								archputs(s, fout);
1962 							else
1963 								archprintf(fout, "'%s'", s);
1964 						}
1965 						break;
1966 
1967 					case BITOID:
1968 					case VARBITOID:
1969 						archprintf(fout, "B'%s'",
1970 								   PQgetvalue(res, tuple, field));
1971 						break;
1972 
1973 					case BOOLOID:
1974 						if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1975 							archputs("true", fout);
1976 						else
1977 							archputs("false", fout);
1978 						break;
1979 
1980 					default:
1981 						/* All other types are printed as string literals. */
1982 						resetPQExpBuffer(q);
1983 						appendStringLiteralAH(q,
1984 											  PQgetvalue(res, tuple, field),
1985 											  fout);
1986 						archputs(q->data, fout);
1987 						break;
1988 				}
1989 			}
1990 			archputs(");\n", fout);
1991 		}
1992 
1993 		if (PQntuples(res) <= 0)
1994 		{
1995 			PQclear(res);
1996 			break;
1997 		}
1998 		PQclear(res);
1999 	}
2000 
2001 	archputs("\n\n", fout);
2002 
2003 	ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2004 
2005 	destroyPQExpBuffer(q);
2006 	if (insertStmt != NULL)
2007 		destroyPQExpBuffer(insertStmt);
2008 
2009 	return 1;
2010 }
2011 
2012 
2013 /*
2014  * dumpTableData -
2015  *	  dump the contents of a single table
2016  *
2017  * Actually, this just makes an ArchiveEntry for the table contents.
2018  */
2019 static void
dumpTableData(Archive * fout,TableDataInfo * tdinfo)2020 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2021 {
2022 	DumpOptions *dopt = fout->dopt;
2023 	TableInfo  *tbinfo = tdinfo->tdtable;
2024 	PQExpBuffer copyBuf = createPQExpBuffer();
2025 	PQExpBuffer clistBuf = createPQExpBuffer();
2026 	DataDumperPtr dumpFn;
2027 	char	   *copyStmt;
2028 
2029 	/* We had better have loaded per-column details about this table */
2030 	Assert(tbinfo->interesting);
2031 
2032 	if (!dopt->dump_inserts)
2033 	{
2034 		/* Dump/restore using COPY */
2035 		dumpFn = dumpTableData_copy;
2036 		/* must use 2 steps here 'cause fmtId is nonreentrant */
2037 		appendPQExpBuffer(copyBuf, "COPY %s ",
2038 						  fmtQualifiedDumpable(tbinfo));
2039 		appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
2040 						  fmtCopyColumnList(tbinfo, clistBuf),
2041 					  (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
2042 		copyStmt = copyBuf->data;
2043 	}
2044 	else
2045 	{
2046 		/* Restore using INSERT */
2047 		dumpFn = dumpTableData_insert;
2048 		copyStmt = NULL;
2049 	}
2050 
2051 	/*
2052 	 * Note: although the TableDataInfo is a full DumpableObject, we treat its
2053 	 * dependency on its table as "special" and pass it to ArchiveEntry now.
2054 	 * See comments for BuildArchiveDependencies.
2055 	 */
2056 	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2057 		ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2058 					 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
2059 					 NULL, tbinfo->rolname,
2060 					 false, "TABLE DATA", SECTION_DATA,
2061 					 "", "", copyStmt,
2062 					 &(tbinfo->dobj.dumpId), 1,
2063 					 dumpFn, tdinfo);
2064 
2065 	destroyPQExpBuffer(copyBuf);
2066 	destroyPQExpBuffer(clistBuf);
2067 }
2068 
2069 /*
2070  * refreshMatViewData -
2071  *	  load or refresh the contents of a single materialized view
2072  *
2073  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2074  * statement.
2075  */
2076 static void
refreshMatViewData(Archive * fout,TableDataInfo * tdinfo)2077 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2078 {
2079 	TableInfo  *tbinfo = tdinfo->tdtable;
2080 	PQExpBuffer q;
2081 
2082 	/* If the materialized view is not flagged as populated, skip this. */
2083 	if (!tbinfo->relispopulated)
2084 		return;
2085 
2086 	q = createPQExpBuffer();
2087 
2088 	appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2089 					  fmtQualifiedDumpable(tbinfo));
2090 
2091 	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2092 		ArchiveEntry(fout,
2093 					 tdinfo->dobj.catId,		/* catalog ID */
2094 					 tdinfo->dobj.dumpId,		/* dump ID */
2095 					 tbinfo->dobj.name, /* Name */
2096 					 tbinfo->dobj.namespace->dobj.name, /* Namespace */
2097 					 NULL,		/* Tablespace */
2098 					 tbinfo->rolname,	/* Owner */
2099 					 false,		/* with oids */
2100 					 "MATERIALIZED VIEW DATA",	/* Desc */
2101 					 SECTION_POST_DATA, /* Section */
2102 					 q->data,	/* Create */
2103 					 "",		/* Del */
2104 					 NULL,		/* Copy */
2105 					 tdinfo->dobj.dependencies, /* Deps */
2106 					 tdinfo->dobj.nDeps,		/* # Deps */
2107 					 NULL,		/* Dumper */
2108 					 NULL);		/* Dumper Arg */
2109 
2110 	destroyPQExpBuffer(q);
2111 }
2112 
2113 /*
2114  * getTableData -
2115  *	  set up dumpable objects representing the contents of tables
2116  */
2117 static void
getTableData(DumpOptions * dopt,TableInfo * tblinfo,int numTables,bool oids)2118 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids)
2119 {
2120 	int			i;
2121 
2122 	for (i = 0; i < numTables; i++)
2123 	{
2124 		if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA)
2125 			makeTableDataInfo(dopt, &(tblinfo[i]), oids);
2126 	}
2127 }
2128 
2129 /*
2130  * Make a dumpable object for the data of this specific table
2131  *
2132  * Note: we make a TableDataInfo if and only if we are going to dump the
2133  * table data; the "dump" flag in such objects isn't used.
2134  */
2135 static void
makeTableDataInfo(DumpOptions * dopt,TableInfo * tbinfo,bool oids)2136 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids)
2137 {
2138 	TableDataInfo *tdinfo;
2139 
2140 	/*
2141 	 * Nothing to do if we already decided to dump the table.  This will
2142 	 * happen for "config" tables.
2143 	 */
2144 	if (tbinfo->dataObj != NULL)
2145 		return;
2146 
2147 	/* Skip VIEWs (no data to dump) */
2148 	if (tbinfo->relkind == RELKIND_VIEW)
2149 		return;
2150 	/* Skip FOREIGN TABLEs (no data to dump) */
2151 	if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2152 		return;
2153 
2154 	/* Don't dump data in unlogged tables, if so requested */
2155 	if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2156 		dopt->no_unlogged_table_data)
2157 		return;
2158 
2159 	/* Check that the data is not explicitly excluded */
2160 	if (simple_oid_list_member(&tabledata_exclude_oids,
2161 							   tbinfo->dobj.catId.oid))
2162 		return;
2163 
2164 	/* OK, let's dump it */
2165 	tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2166 
2167 	if (tbinfo->relkind == RELKIND_MATVIEW)
2168 		tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2169 	else
2170 		tdinfo->dobj.objType = DO_TABLE_DATA;
2171 
2172 	/*
2173 	 * Note: use tableoid 0 so that this object won't be mistaken for
2174 	 * something that pg_depend entries apply to.
2175 	 */
2176 	tdinfo->dobj.catId.tableoid = 0;
2177 	tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2178 	AssignDumpId(&tdinfo->dobj);
2179 	tdinfo->dobj.name = tbinfo->dobj.name;
2180 	tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2181 	tdinfo->tdtable = tbinfo;
2182 	tdinfo->oids = oids;
2183 	tdinfo->filtercond = NULL;	/* might get set later */
2184 	addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2185 
2186 	tbinfo->dataObj = tdinfo;
2187 
2188 	/* Make sure that we'll collect per-column info for this table. */
2189 	tbinfo->interesting = true;
2190 }
2191 
2192 /*
2193  * The refresh for a materialized view must be dependent on the refresh for
2194  * any materialized view that this one is dependent on.
2195  *
2196  * This must be called after all the objects are created, but before they are
2197  * sorted.
2198  */
2199 static void
buildMatViewRefreshDependencies(Archive * fout)2200 buildMatViewRefreshDependencies(Archive *fout)
2201 {
2202 	PQExpBuffer query;
2203 	PGresult   *res;
2204 	int			ntups,
2205 				i;
2206 	int			i_classid,
2207 				i_objid,
2208 				i_refobjid;
2209 
2210 	/* No Mat Views before 9.3. */
2211 	if (fout->remoteVersion < 90300)
2212 		return;
2213 
2214 	query = createPQExpBuffer();
2215 
2216 	appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2217 						 "( "
2218 					"SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2219 						 "FROM pg_depend d1 "
2220 						 "JOIN pg_class c1 ON c1.oid = d1.objid "
2221 						 "AND c1.relkind = 'm' "
2222 						 "JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2223 				  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2224 						 "AND d2.objid = r1.oid "
2225 						 "AND d2.refobjid <> d1.objid "
2226 						 "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2227 						 "AND c2.relkind IN ('m','v') "
2228 						 "WHERE d1.classid = 'pg_class'::regclass "
2229 						 "UNION "
2230 						 "SELECT w.objid, d3.refobjid, c3.relkind "
2231 						 "FROM w "
2232 						 "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2233 				  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2234 						 "AND d3.objid = r3.oid "
2235 						 "AND d3.refobjid <> w.refobjid "
2236 						 "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2237 						 "AND c3.relkind IN ('m','v') "
2238 						 ") "
2239 			  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2240 						 "FROM w "
2241 						 "WHERE refrelkind = 'm'");
2242 
2243 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2244 
2245 	ntups = PQntuples(res);
2246 
2247 	i_classid = PQfnumber(res, "classid");
2248 	i_objid = PQfnumber(res, "objid");
2249 	i_refobjid = PQfnumber(res, "refobjid");
2250 
2251 	for (i = 0; i < ntups; i++)
2252 	{
2253 		CatalogId	objId;
2254 		CatalogId	refobjId;
2255 		DumpableObject *dobj;
2256 		DumpableObject *refdobj;
2257 		TableInfo  *tbinfo;
2258 		TableInfo  *reftbinfo;
2259 
2260 		objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2261 		objId.oid = atooid(PQgetvalue(res, i, i_objid));
2262 		refobjId.tableoid = objId.tableoid;
2263 		refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2264 
2265 		dobj = findObjectByCatalogId(objId);
2266 		if (dobj == NULL)
2267 			continue;
2268 
2269 		Assert(dobj->objType == DO_TABLE);
2270 		tbinfo = (TableInfo *) dobj;
2271 		Assert(tbinfo->relkind == RELKIND_MATVIEW);
2272 		dobj = (DumpableObject *) tbinfo->dataObj;
2273 		if (dobj == NULL)
2274 			continue;
2275 		Assert(dobj->objType == DO_REFRESH_MATVIEW);
2276 
2277 		refdobj = findObjectByCatalogId(refobjId);
2278 		if (refdobj == NULL)
2279 			continue;
2280 
2281 		Assert(refdobj->objType == DO_TABLE);
2282 		reftbinfo = (TableInfo *) refdobj;
2283 		Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2284 		refdobj = (DumpableObject *) reftbinfo->dataObj;
2285 		if (refdobj == NULL)
2286 			continue;
2287 		Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2288 
2289 		addObjectDependency(dobj, refdobj->dumpId);
2290 
2291 		if (!reftbinfo->relispopulated)
2292 			tbinfo->relispopulated = false;
2293 	}
2294 
2295 	PQclear(res);
2296 
2297 	destroyPQExpBuffer(query);
2298 }
2299 
2300 /*
2301  * getTableDataFKConstraints -
2302  *	  add dump-order dependencies reflecting foreign key constraints
2303  *
2304  * This code is executed only in a data-only dump --- in schema+data dumps
2305  * we handle foreign key issues by not creating the FK constraints until
2306  * after the data is loaded.  In a data-only dump, however, we want to
2307  * order the table data objects in such a way that a table's referenced
2308  * tables are restored first.  (In the presence of circular references or
2309  * self-references this may be impossible; we'll detect and complain about
2310  * that during the dependency sorting step.)
2311  */
2312 static void
getTableDataFKConstraints(void)2313 getTableDataFKConstraints(void)
2314 {
2315 	DumpableObject **dobjs;
2316 	int			numObjs;
2317 	int			i;
2318 
2319 	/* Search through all the dumpable objects for FK constraints */
2320 	getDumpableObjects(&dobjs, &numObjs);
2321 	for (i = 0; i < numObjs; i++)
2322 	{
2323 		if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2324 		{
2325 			ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2326 			TableInfo  *ftable;
2327 
2328 			/* Not interesting unless both tables are to be dumped */
2329 			if (cinfo->contable == NULL ||
2330 				cinfo->contable->dataObj == NULL)
2331 				continue;
2332 			ftable = findTableByOid(cinfo->confrelid);
2333 			if (ftable == NULL ||
2334 				ftable->dataObj == NULL)
2335 				continue;
2336 
2337 			/*
2338 			 * Okay, make referencing table's TABLE_DATA object depend on the
2339 			 * referenced table's TABLE_DATA object.
2340 			 */
2341 			addObjectDependency(&cinfo->contable->dataObj->dobj,
2342 								ftable->dataObj->dobj.dumpId);
2343 		}
2344 	}
2345 	free(dobjs);
2346 }
2347 
2348 
2349 /*
2350  * guessConstraintInheritance:
2351  *	In pre-8.4 databases, we can't tell for certain which constraints
2352  *	are inherited.  We assume a CHECK constraint is inherited if its name
2353  *	matches the name of any constraint in the parent.  Originally this code
2354  *	tried to compare the expression texts, but that can fail for various
2355  *	reasons --- for example, if the parent and child tables are in different
2356  *	schemas, reverse-listing of function calls may produce different text
2357  *	(schema-qualified or not) depending on search path.
2358  *
2359  *	In 8.4 and up we can rely on the conislocal field to decide which
2360  *	constraints must be dumped; much safer.
2361  *
2362  *	This function assumes all conislocal flags were initialized to TRUE.
2363  *	It clears the flag on anything that seems to be inherited.
2364  */
2365 static void
guessConstraintInheritance(TableInfo * tblinfo,int numTables)2366 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2367 {
2368 	int			i,
2369 				j,
2370 				k;
2371 
2372 	for (i = 0; i < numTables; i++)
2373 	{
2374 		TableInfo  *tbinfo = &(tblinfo[i]);
2375 		int			numParents;
2376 		TableInfo **parents;
2377 		TableInfo  *parent;
2378 
2379 		/* Sequences and views never have parents */
2380 		if (tbinfo->relkind == RELKIND_SEQUENCE ||
2381 			tbinfo->relkind == RELKIND_VIEW)
2382 			continue;
2383 
2384 		/* Don't bother computing anything for non-target tables, either */
2385 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2386 			continue;
2387 
2388 		numParents = tbinfo->numParents;
2389 		parents = tbinfo->parents;
2390 
2391 		if (numParents == 0)
2392 			continue;			/* nothing to see here, move along */
2393 
2394 		/* scan for inherited CHECK constraints */
2395 		for (j = 0; j < tbinfo->ncheck; j++)
2396 		{
2397 			ConstraintInfo *constr;
2398 
2399 			constr = &(tbinfo->checkexprs[j]);
2400 
2401 			for (k = 0; k < numParents; k++)
2402 			{
2403 				int			l;
2404 
2405 				parent = parents[k];
2406 				for (l = 0; l < parent->ncheck; l++)
2407 				{
2408 					ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2409 
2410 					if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2411 					{
2412 						constr->conislocal = false;
2413 						break;
2414 					}
2415 				}
2416 				if (!constr->conislocal)
2417 					break;
2418 			}
2419 		}
2420 	}
2421 }
2422 
2423 
2424 /*
2425  * dumpDatabase:
2426  *	dump the database definition
2427  */
2428 static void
dumpDatabase(Archive * fout)2429 dumpDatabase(Archive *fout)
2430 {
2431 	DumpOptions *dopt = fout->dopt;
2432 	PQExpBuffer dbQry = createPQExpBuffer();
2433 	PQExpBuffer delQry = createPQExpBuffer();
2434 	PQExpBuffer creaQry = createPQExpBuffer();
2435 	PQExpBuffer labelq = createPQExpBuffer();
2436 	PGconn	   *conn = GetConnection(fout);
2437 	PGresult   *res;
2438 	int			i_tableoid,
2439 				i_oid,
2440 				i_dba,
2441 				i_encoding,
2442 				i_collate,
2443 				i_ctype,
2444 				i_frozenxid,
2445 				i_minmxid,
2446 				i_tablespace;
2447 	CatalogId	dbCatId;
2448 	DumpId		dbDumpId;
2449 	const char *datname,
2450 			   *dba,
2451 			   *encoding,
2452 			   *collate,
2453 			   *ctype,
2454 			   *tablespace;
2455 	uint32		frozenxid,
2456 				minmxid;
2457 	char	   *qdatname;
2458 
2459 	datname = PQdb(conn);
2460 	qdatname = pg_strdup(fmtId(datname));
2461 
2462 	if (g_verbose)
2463 		write_msg(NULL, "saving database definition\n");
2464 
2465 	/* Get the database owner and parameters from pg_database */
2466 	if (fout->remoteVersion >= 90300)
2467 	{
2468 		appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2469 						  "(%s datdba) AS dba, "
2470 						  "pg_encoding_to_char(encoding) AS encoding, "
2471 						  "datcollate, datctype, datfrozenxid, datminmxid, "
2472 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2473 					  "shobj_description(oid, 'pg_database') AS description "
2474 
2475 						  "FROM pg_database "
2476 						  "WHERE datname = ",
2477 						  username_subquery);
2478 		appendStringLiteralAH(dbQry, datname, fout);
2479 	}
2480 	else if (fout->remoteVersion >= 80400)
2481 	{
2482 		appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2483 						  "(%s datdba) AS dba, "
2484 						  "pg_encoding_to_char(encoding) AS encoding, "
2485 					  "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2486 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2487 					  "shobj_description(oid, 'pg_database') AS description "
2488 
2489 						  "FROM pg_database "
2490 						  "WHERE datname = ",
2491 						  username_subquery);
2492 		appendStringLiteralAH(dbQry, datname, fout);
2493 	}
2494 	else if (fout->remoteVersion >= 80200)
2495 	{
2496 		appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2497 						  "(%s datdba) AS dba, "
2498 						  "pg_encoding_to_char(encoding) AS encoding, "
2499 						  "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2500 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2501 					  "shobj_description(oid, 'pg_database') AS description "
2502 
2503 						  "FROM pg_database "
2504 						  "WHERE datname = ",
2505 						  username_subquery);
2506 		appendStringLiteralAH(dbQry, datname, fout);
2507 	}
2508 	else if (fout->remoteVersion >= 80000)
2509 	{
2510 		appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2511 						  "(%s datdba) AS dba, "
2512 						  "pg_encoding_to_char(encoding) AS encoding, "
2513 						  "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2514 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2515 						  "FROM pg_database "
2516 						  "WHERE datname = ",
2517 						  username_subquery);
2518 		appendStringLiteralAH(dbQry, datname, fout);
2519 	}
2520 	else if (fout->remoteVersion >= 70100)
2521 	{
2522 		appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2523 						  "(%s datdba) AS dba, "
2524 						  "pg_encoding_to_char(encoding) AS encoding, "
2525 						  "NULL AS datcollate, NULL AS datctype, "
2526 						  "0 AS datfrozenxid, 0 AS datminmxid, "
2527 						  "NULL AS tablespace "
2528 						  "FROM pg_database "
2529 						  "WHERE datname = ",
2530 						  username_subquery);
2531 		appendStringLiteralAH(dbQry, datname, fout);
2532 	}
2533 	else
2534 	{
2535 		appendPQExpBuffer(dbQry, "SELECT "
2536 						  "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
2537 						  "oid, "
2538 						  "(%s datdba) AS dba, "
2539 						  "pg_encoding_to_char(encoding) AS encoding, "
2540 						  "NULL AS datcollate, NULL AS datctype, "
2541 						  "0 AS datfrozenxid, 0 AS datminmxid, "
2542 						  "NULL AS tablespace "
2543 						  "FROM pg_database "
2544 						  "WHERE datname = ",
2545 						  username_subquery);
2546 		appendStringLiteralAH(dbQry, datname, fout);
2547 	}
2548 
2549 	res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2550 
2551 	i_tableoid = PQfnumber(res, "tableoid");
2552 	i_oid = PQfnumber(res, "oid");
2553 	i_dba = PQfnumber(res, "dba");
2554 	i_encoding = PQfnumber(res, "encoding");
2555 	i_collate = PQfnumber(res, "datcollate");
2556 	i_ctype = PQfnumber(res, "datctype");
2557 	i_frozenxid = PQfnumber(res, "datfrozenxid");
2558 	i_minmxid = PQfnumber(res, "datminmxid");
2559 	i_tablespace = PQfnumber(res, "tablespace");
2560 
2561 	dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2562 	dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2563 	dba = PQgetvalue(res, 0, i_dba);
2564 	encoding = PQgetvalue(res, 0, i_encoding);
2565 	collate = PQgetvalue(res, 0, i_collate);
2566 	ctype = PQgetvalue(res, 0, i_ctype);
2567 	frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2568 	minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2569 	tablespace = PQgetvalue(res, 0, i_tablespace);
2570 
2571 	appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2572 					  qdatname);
2573 	if (strlen(encoding) > 0)
2574 	{
2575 		appendPQExpBufferStr(creaQry, " ENCODING = ");
2576 		appendStringLiteralAH(creaQry, encoding, fout);
2577 	}
2578 	if (strlen(collate) > 0)
2579 	{
2580 		appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2581 		appendStringLiteralAH(creaQry, collate, fout);
2582 	}
2583 	if (strlen(ctype) > 0)
2584 	{
2585 		appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2586 		appendStringLiteralAH(creaQry, ctype, fout);
2587 	}
2588 	if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2589 		!dopt->outputNoTablespaces)
2590 		appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2591 						  fmtId(tablespace));
2592 	appendPQExpBufferStr(creaQry, ";\n");
2593 
2594 	if (dopt->binary_upgrade)
2595 	{
2596 		appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2597 		appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2598 						  "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2599 						  "WHERE	datname = ",
2600 						  frozenxid, minmxid);
2601 		appendStringLiteralAH(creaQry, datname, fout);
2602 		appendPQExpBufferStr(creaQry, ";\n");
2603 	}
2604 
2605 	appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2606 					  qdatname);
2607 
2608 	dbDumpId = createDumpId();
2609 
2610 	ArchiveEntry(fout,
2611 				 dbCatId,		/* catalog ID */
2612 				 dbDumpId,		/* dump ID */
2613 				 datname,		/* Name */
2614 				 NULL,			/* Namespace */
2615 				 NULL,			/* Tablespace */
2616 				 dba,			/* Owner */
2617 				 false,			/* with oids */
2618 				 "DATABASE",	/* Desc */
2619 				 SECTION_PRE_DATA,		/* Section */
2620 				 creaQry->data, /* Create */
2621 				 delQry->data,	/* Del */
2622 				 NULL,			/* Copy */
2623 				 NULL,			/* Deps */
2624 				 0,				/* # Deps */
2625 				 NULL,			/* Dumper */
2626 				 NULL);			/* Dumper Arg */
2627 
2628 	/*
2629 	 * pg_largeobject and pg_largeobject_metadata come from the old system
2630 	 * intact, so set their relfrozenxids and relminmxids.
2631 	 */
2632 	if (dopt->binary_upgrade)
2633 	{
2634 		PGresult   *lo_res;
2635 		PQExpBuffer loFrozenQry = createPQExpBuffer();
2636 		PQExpBuffer loOutQry = createPQExpBuffer();
2637 		int			i_relfrozenxid,
2638 					i_relminmxid;
2639 
2640 		/*
2641 		 * pg_largeobject
2642 		 */
2643 		if (fout->remoteVersion >= 90300)
2644 			appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2645 							  "FROM pg_catalog.pg_class\n"
2646 							  "WHERE oid = %u;\n",
2647 							  LargeObjectRelationId);
2648 		else
2649 			appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2650 							  "FROM pg_catalog.pg_class\n"
2651 							  "WHERE oid = %u;\n",
2652 							  LargeObjectRelationId);
2653 
2654 		lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2655 
2656 		i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2657 		i_relminmxid = PQfnumber(lo_res, "relminmxid");
2658 
2659 		appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
2660 		appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2661 						  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2662 						  "WHERE oid = %u;\n",
2663 						  atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2664 						  atoi(PQgetvalue(lo_res, 0, i_relminmxid)),
2665 						  LargeObjectRelationId);
2666 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
2667 					 "pg_largeobject", NULL, NULL, "",
2668 					 false, "pg_largeobject", SECTION_PRE_DATA,
2669 					 loOutQry->data, "", NULL,
2670 					 NULL, 0,
2671 					 NULL, NULL);
2672 
2673 		PQclear(lo_res);
2674 
2675 		/*
2676 		 * pg_largeobject_metadata
2677 		 */
2678 		if (fout->remoteVersion >= 90000)
2679 		{
2680 			resetPQExpBuffer(loFrozenQry);
2681 			resetPQExpBuffer(loOutQry);
2682 
2683 			if (fout->remoteVersion >= 90300)
2684 				appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2685 								  "FROM pg_catalog.pg_class\n"
2686 								  "WHERE oid = %u;\n",
2687 								  LargeObjectMetadataRelationId);
2688 			else
2689 				appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2690 								  "FROM pg_catalog.pg_class\n"
2691 								  "WHERE oid = %u;\n",
2692 								  LargeObjectMetadataRelationId);
2693 
2694 			lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2695 
2696 			i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2697 			i_relminmxid = PQfnumber(lo_res, "relminmxid");
2698 
2699 			appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
2700 			appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2701 							  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2702 							  "WHERE oid = %u;\n",
2703 							  atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2704 							  atoi(PQgetvalue(lo_res, 0, i_relminmxid)),
2705 							  LargeObjectMetadataRelationId);
2706 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
2707 						 "pg_largeobject_metadata", NULL, NULL, "",
2708 						 false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2709 						 loOutQry->data, "", NULL,
2710 						 NULL, 0,
2711 						 NULL, NULL);
2712 
2713 			PQclear(lo_res);
2714 		}
2715 
2716 		destroyPQExpBuffer(loFrozenQry);
2717 		destroyPQExpBuffer(loOutQry);
2718 	}
2719 
2720 	/* Compute correct tag for archive entry */
2721 	appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2722 
2723 	/* Dump DB comment if any */
2724 	if (fout->remoteVersion >= 80200)
2725 	{
2726 		/*
2727 		 * 8.2 and up keep comments on shared objects in a shared table, so we
2728 		 * cannot use the dumpComment() code used for other database objects.
2729 		 * Be careful that the ArchiveEntry parameters match that function.
2730 		 */
2731 		char	   *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2732 
2733 		if (comment && *comment)
2734 		{
2735 			resetPQExpBuffer(dbQry);
2736 
2737 			/*
2738 			 * Generates warning when loaded into a differently-named
2739 			 * database.
2740 			 */
2741 			appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2742 			appendStringLiteralAH(dbQry, comment, fout);
2743 			appendPQExpBufferStr(dbQry, ";\n");
2744 
2745 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
2746 						 labelq->data, NULL, NULL, dba,
2747 						 false, "COMMENT", SECTION_NONE,
2748 						 dbQry->data, "", NULL,
2749 						 &(dbDumpId), 1,
2750 						 NULL, NULL);
2751 		}
2752 	}
2753 	else
2754 	{
2755 		dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2756 					dbCatId, 0, dbDumpId);
2757 	}
2758 
2759 	/* Dump shared security label. */
2760 	if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2761 	{
2762 		PGresult   *shres;
2763 		PQExpBuffer seclabelQry;
2764 
2765 		seclabelQry = createPQExpBuffer();
2766 
2767 		buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2768 		shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2769 		resetPQExpBuffer(seclabelQry);
2770 		emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2771 		if (seclabelQry->len > 0)
2772 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
2773 						 labelq->data, NULL, NULL, dba,
2774 						 false, "SECURITY LABEL", SECTION_NONE,
2775 						 seclabelQry->data, "", NULL,
2776 						 &(dbDumpId), 1,
2777 						 NULL, NULL);
2778 		destroyPQExpBuffer(seclabelQry);
2779 		PQclear(shres);
2780 	}
2781 
2782 	PQclear(res);
2783 
2784 	free(qdatname);
2785 	destroyPQExpBuffer(dbQry);
2786 	destroyPQExpBuffer(delQry);
2787 	destroyPQExpBuffer(creaQry);
2788 	destroyPQExpBuffer(labelq);
2789 }
2790 
2791 /*
2792  * dumpEncoding: put the correct encoding into the archive
2793  */
2794 static void
dumpEncoding(Archive * AH)2795 dumpEncoding(Archive *AH)
2796 {
2797 	const char *encname = pg_encoding_to_char(AH->encoding);
2798 	PQExpBuffer qry = createPQExpBuffer();
2799 
2800 	if (g_verbose)
2801 		write_msg(NULL, "saving encoding = %s\n", encname);
2802 
2803 	appendPQExpBufferStr(qry, "SET client_encoding = ");
2804 	appendStringLiteralAH(qry, encname, AH);
2805 	appendPQExpBufferStr(qry, ";\n");
2806 
2807 	ArchiveEntry(AH, nilCatalogId, createDumpId(),
2808 				 "ENCODING", NULL, NULL, "",
2809 				 false, "ENCODING", SECTION_PRE_DATA,
2810 				 qry->data, "", NULL,
2811 				 NULL, 0,
2812 				 NULL, NULL);
2813 
2814 	destroyPQExpBuffer(qry);
2815 }
2816 
2817 
2818 /*
2819  * dumpStdStrings: put the correct escape string behavior into the archive
2820  */
2821 static void
dumpStdStrings(Archive * AH)2822 dumpStdStrings(Archive *AH)
2823 {
2824 	const char *stdstrings = AH->std_strings ? "on" : "off";
2825 	PQExpBuffer qry = createPQExpBuffer();
2826 
2827 	if (g_verbose)
2828 		write_msg(NULL, "saving standard_conforming_strings = %s\n",
2829 				  stdstrings);
2830 
2831 	appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2832 					  stdstrings);
2833 
2834 	ArchiveEntry(AH, nilCatalogId, createDumpId(),
2835 				 "STDSTRINGS", NULL, NULL, "",
2836 				 false, "STDSTRINGS", SECTION_PRE_DATA,
2837 				 qry->data, "", NULL,
2838 				 NULL, 0,
2839 				 NULL, NULL);
2840 
2841 	destroyPQExpBuffer(qry);
2842 }
2843 
2844 /*
2845  * dumpSearchPath: record the active search_path in the archive
2846  */
2847 static void
dumpSearchPath(Archive * AH)2848 dumpSearchPath(Archive *AH)
2849 {
2850 	PQExpBuffer qry = createPQExpBuffer();
2851 	PQExpBuffer path = createPQExpBuffer();
2852 	PGresult   *res;
2853 	char	  **schemanames = NULL;
2854 	int			nschemanames = 0;
2855 	int			i;
2856 
2857 	if (AH->remoteVersion >= 70300)
2858 	{
2859 		/*
2860 		 * We use the result of current_schemas(), not the search_path GUC,
2861 		 * because that might contain wildcards such as "$user", which won't
2862 		 * necessarily have the same value during restore.  Also, this way
2863 		 * avoids listing schemas that may appear in search_path but not
2864 		 * actually exist, which seems like a prudent exclusion.
2865 		 */
2866 		res = ExecuteSqlQueryForSingleRow(AH,
2867 								 "SELECT pg_catalog.current_schemas(false)");
2868 
2869 		if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
2870 			exit_horribly(NULL, "could not parse result of current_schemas()\n");
2871 
2872 		/*
2873 		 * We use set_config(), not a simple "SET search_path" command,
2874 		 * because the latter has less-clean behavior if the search path is
2875 		 * empty.  While that's likely to get fixed at some point, it seems
2876 		 * like a good idea to be as backwards-compatible as possible in what
2877 		 * we put into archives.
2878 		 */
2879 		for (i = 0; i < nschemanames; i++)
2880 		{
2881 			if (i > 0)
2882 				appendPQExpBufferStr(path, ", ");
2883 			appendPQExpBufferStr(path, fmtId(schemanames[i]));
2884 		}
2885 
2886 		PQclear(res);
2887 	}
2888 	else
2889 	{
2890 		/*
2891 		 * For pre-schema servers, we must force the output search path to be
2892 		 * "public", because the source server's ruleutils functions will not
2893 		 * schema-qualify anything.  Thus, for example, references to user
2894 		 * tables in view definitions won't work otherwise.
2895 		 */
2896 		appendPQExpBufferStr(path, "public");
2897 	}
2898 
2899 	appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
2900 	appendStringLiteralAH(qry, path->data, AH);
2901 	appendPQExpBufferStr(qry, ", false);\n");
2902 
2903 	if (g_verbose)
2904 		write_msg(NULL, "saving search_path = %s\n", path->data);
2905 
2906 	ArchiveEntry(AH, nilCatalogId, createDumpId(),
2907 				 "SEARCHPATH", NULL, NULL, "",
2908 				 false, "SEARCHPATH", SECTION_PRE_DATA,
2909 				 qry->data, "", NULL,
2910 				 NULL, 0,
2911 				 NULL, NULL);
2912 
2913 	/* Also save it in AH->searchpath, in case we're doing plain text dump */
2914 	AH->searchpath = pg_strdup(qry->data);
2915 
2916 	if (schemanames)
2917 		free(schemanames);
2918 	destroyPQExpBuffer(qry);
2919 	destroyPQExpBuffer(path);
2920 }
2921 
2922 
2923 /*
2924  * getBlobs:
2925  *	Collect schema-level data about large objects
2926  */
2927 static void
getBlobs(Archive * fout)2928 getBlobs(Archive *fout)
2929 {
2930 	DumpOptions *dopt = fout->dopt;
2931 	PQExpBuffer blobQry = createPQExpBuffer();
2932 	BlobInfo   *binfo;
2933 	DumpableObject *bdata;
2934 	PGresult   *res;
2935 	int			ntups;
2936 	int			i;
2937 	int			i_oid;
2938 	int			i_lomowner;
2939 	int			i_lomacl;
2940 	int			i_rlomacl;
2941 	int			i_initlomacl;
2942 	int			i_initrlomacl;
2943 
2944 	/* Verbose message */
2945 	if (g_verbose)
2946 		write_msg(NULL, "reading large objects\n");
2947 
2948 	/* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2949 	if (fout->remoteVersion >= 90600)
2950 	{
2951 		PQExpBuffer acl_subquery = createPQExpBuffer();
2952 		PQExpBuffer racl_subquery = createPQExpBuffer();
2953 		PQExpBuffer init_acl_subquery = createPQExpBuffer();
2954 		PQExpBuffer init_racl_subquery = createPQExpBuffer();
2955 
2956 		buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
2957 						init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
2958 						dopt->binary_upgrade);
2959 
2960 		appendPQExpBuffer(blobQry,
2961 						  "SELECT l.oid, (%s l.lomowner) AS rolname, "
2962 						  "%s AS lomacl, "
2963 						  "%s AS rlomacl, "
2964 						  "%s AS initlomacl, "
2965 						  "%s AS initrlomacl "
2966 						  "FROM pg_largeobject_metadata l "
2967 						  "LEFT JOIN pg_init_privs pip ON "
2968 						  "(l.oid = pip.objoid "
2969 						  "AND pip.classoid = 'pg_largeobject'::regclass "
2970 						  "AND pip.objsubid = 0) ",
2971 						  username_subquery,
2972 						  acl_subquery->data,
2973 						  racl_subquery->data,
2974 						  init_acl_subquery->data,
2975 						  init_racl_subquery->data);
2976 
2977 		destroyPQExpBuffer(acl_subquery);
2978 		destroyPQExpBuffer(racl_subquery);
2979 		destroyPQExpBuffer(init_acl_subquery);
2980 		destroyPQExpBuffer(init_racl_subquery);
2981 	}
2982 	else if (fout->remoteVersion >= 90000)
2983 		appendPQExpBuffer(blobQry,
2984 						  "SELECT oid, (%s lomowner) AS rolname, lomacl, "
2985 						  "NULL AS rlomacl, NULL AS initlomacl, "
2986 						  "NULL AS initrlomacl "
2987 						  " FROM pg_largeobject_metadata",
2988 						  username_subquery);
2989 	else if (fout->remoteVersion >= 70100)
2990 		appendPQExpBufferStr(blobQry,
2991 							 "SELECT DISTINCT loid AS oid, "
2992 							 "NULL::name AS rolname, NULL::oid AS lomacl, "
2993 							 "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
2994 							 "NULL::oid AS initrlomacl "
2995 							 " FROM pg_largeobject");
2996 	else
2997 		appendPQExpBufferStr(blobQry,
2998 							 "SELECT oid, NULL AS rolname, NULL AS lomacl, "
2999 							 "NULL AS rlomacl, NULL AS initlomacl, "
3000 							 "NULL AS initrlomacl "
3001 							 " FROM pg_class WHERE relkind = 'l'");
3002 
3003 	res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3004 
3005 	i_oid = PQfnumber(res, "oid");
3006 	i_lomowner = PQfnumber(res, "rolname");
3007 	i_lomacl = PQfnumber(res, "lomacl");
3008 	i_rlomacl = PQfnumber(res, "rlomacl");
3009 	i_initlomacl = PQfnumber(res, "initlomacl");
3010 	i_initrlomacl = PQfnumber(res, "initrlomacl");
3011 
3012 	ntups = PQntuples(res);
3013 
3014 	/*
3015 	 * Each large object has its own BLOB archive entry.
3016 	 */
3017 	binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3018 
3019 	for (i = 0; i < ntups; i++)
3020 	{
3021 		binfo[i].dobj.objType = DO_BLOB;
3022 		binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3023 		binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3024 		AssignDumpId(&binfo[i].dobj);
3025 
3026 		binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3027 		binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3028 		binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3029 		binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3030 		binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3031 		binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3032 
3033 		if (PQgetisnull(res, i, i_lomacl) &&
3034 			PQgetisnull(res, i, i_rlomacl) &&
3035 			PQgetisnull(res, i, i_initlomacl) &&
3036 			PQgetisnull(res, i, i_initrlomacl))
3037 			binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3038 
3039 		/*
3040 		 * In binary-upgrade mode for blobs, we do *not* dump out the data or
3041 		 * the ACLs, should any exist.  The data and ACL (if any) will be
3042 		 * copied by pg_upgrade, which simply copies the pg_largeobject and
3043 		 * pg_largeobject_metadata tables.
3044 		 *
3045 		 * We *do* dump out the definition of the blob because we need that to
3046 		 * make the restoration of the comments, and anything else, work since
3047 		 * pg_upgrade copies the files behind pg_largeobject and
3048 		 * pg_largeobject_metadata after the dump is restored.
3049 		 */
3050 		if (dopt->binary_upgrade)
3051 			binfo[i].dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL);
3052 	}
3053 
3054 	/*
3055 	 * If we have any large objects, a "BLOBS" archive entry is needed. This
3056 	 * is just a placeholder for sorting; it carries no data now.
3057 	 */
3058 	if (ntups > 0)
3059 	{
3060 		bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3061 		bdata->objType = DO_BLOB_DATA;
3062 		bdata->catId = nilCatalogId;
3063 		AssignDumpId(bdata);
3064 		bdata->name = pg_strdup("BLOBS");
3065 	}
3066 
3067 	PQclear(res);
3068 	destroyPQExpBuffer(blobQry);
3069 }
3070 
3071 /*
3072  * dumpBlob
3073  *
3074  * dump the definition (metadata) of the given large object
3075  */
3076 static void
dumpBlob(Archive * fout,BlobInfo * binfo)3077 dumpBlob(Archive *fout, BlobInfo *binfo)
3078 {
3079 	PQExpBuffer cquery = createPQExpBuffer();
3080 	PQExpBuffer dquery = createPQExpBuffer();
3081 
3082 	appendPQExpBuffer(cquery,
3083 					  "SELECT pg_catalog.lo_create('%s');\n",
3084 					  binfo->dobj.name);
3085 
3086 	appendPQExpBuffer(dquery,
3087 					  "SELECT pg_catalog.lo_unlink('%s');\n",
3088 					  binfo->dobj.name);
3089 
3090 	if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3091 		ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3092 					 binfo->dobj.name,
3093 					 NULL, NULL,
3094 					 binfo->rolname, false,
3095 					 "BLOB", SECTION_PRE_DATA,
3096 					 cquery->data, dquery->data, NULL,
3097 					 NULL, 0,
3098 					 NULL, NULL);
3099 
3100 	/* Dump comment if any */
3101 	if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3102 		dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3103 					NULL, binfo->rolname,
3104 					binfo->dobj.catId, 0, binfo->dobj.dumpId);
3105 
3106 	/* Dump security label if any */
3107 	if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3108 		dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3109 					 NULL, binfo->rolname,
3110 					 binfo->dobj.catId, 0, binfo->dobj.dumpId);
3111 
3112 	/* Dump ACL if any */
3113 	if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3114 		dumpACL(fout, binfo->dobj.dumpId, InvalidDumpId, "LARGE OBJECT",
3115 				binfo->dobj.name, NULL,
3116 				NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3117 				binfo->initblobacl, binfo->initrblobacl);
3118 
3119 	destroyPQExpBuffer(cquery);
3120 	destroyPQExpBuffer(dquery);
3121 }
3122 
3123 /*
3124  * dumpBlobs:
3125  *	dump the data contents of all large objects
3126  */
3127 static int
dumpBlobs(Archive * fout,void * arg)3128 dumpBlobs(Archive *fout, void *arg)
3129 {
3130 	const char *blobQry;
3131 	const char *blobFetchQry;
3132 	PGconn	   *conn = GetConnection(fout);
3133 	PGresult   *res;
3134 	char		buf[LOBBUFSIZE];
3135 	int			ntups;
3136 	int			i;
3137 	int			cnt;
3138 
3139 	if (g_verbose)
3140 		write_msg(NULL, "saving large objects\n");
3141 
3142 	/*
3143 	 * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3144 	 * the already-in-memory dumpable objects instead...
3145 	 */
3146 	if (fout->remoteVersion >= 90000)
3147 		blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
3148 	else if (fout->remoteVersion >= 70100)
3149 		blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
3150 	else
3151 		blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
3152 
3153 	ExecuteSqlStatement(fout, blobQry);
3154 
3155 	/* Command to fetch from cursor */
3156 	blobFetchQry = "FETCH 1000 IN bloboid";
3157 
3158 	do
3159 	{
3160 		/* Do a fetch */
3161 		res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3162 
3163 		/* Process the tuples, if any */
3164 		ntups = PQntuples(res);
3165 		for (i = 0; i < ntups; i++)
3166 		{
3167 			Oid			blobOid;
3168 			int			loFd;
3169 
3170 			blobOid = atooid(PQgetvalue(res, i, 0));
3171 			/* Open the BLOB */
3172 			loFd = lo_open(conn, blobOid, INV_READ);
3173 			if (loFd == -1)
3174 				exit_horribly(NULL, "could not open large object %u: %s",
3175 							  blobOid, PQerrorMessage(conn));
3176 
3177 			StartBlob(fout, blobOid);
3178 
3179 			/* Now read it in chunks, sending data to archive */
3180 			do
3181 			{
3182 				cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3183 				if (cnt < 0)
3184 					exit_horribly(NULL, "error reading large object %u: %s",
3185 								  blobOid, PQerrorMessage(conn));
3186 
3187 				WriteData(fout, buf, cnt);
3188 			} while (cnt > 0);
3189 
3190 			lo_close(conn, loFd);
3191 
3192 			EndBlob(fout, blobOid);
3193 		}
3194 
3195 		PQclear(res);
3196 	} while (ntups > 0);
3197 
3198 	return 1;
3199 }
3200 
3201 /*
3202  * getPolicies
3203  *	  get information about all RLS policies on dumpable tables.
3204  */
3205 void
getPolicies(Archive * fout,TableInfo tblinfo[],int numTables)3206 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3207 {
3208 	PQExpBuffer query;
3209 	PGresult   *res;
3210 	PolicyInfo *polinfo;
3211 	int			i_oid;
3212 	int			i_tableoid;
3213 	int			i_polrelid;
3214 	int			i_polname;
3215 	int			i_polcmd;
3216 	int			i_polroles;
3217 	int			i_polqual;
3218 	int			i_polwithcheck;
3219 	int			i,
3220 				j,
3221 				ntups;
3222 
3223 	if (fout->remoteVersion < 90500)
3224 		return;
3225 
3226 	query = createPQExpBuffer();
3227 
3228 	/*
3229 	 * First, check which tables have RLS enabled.  We represent RLS being
3230 	 * enabled on a table by creating a PolicyInfo object with null polname.
3231 	 */
3232 	for (i = 0; i < numTables; i++)
3233 	{
3234 		TableInfo  *tbinfo = &tblinfo[i];
3235 
3236 		/* Ignore row security on tables not to be dumped */
3237 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3238 			continue;
3239 
3240 		if (tbinfo->rowsec)
3241 		{
3242 			/*
3243 			 * Note: use tableoid 0 so that this object won't be mistaken for
3244 			 * something that pg_depend entries apply to.
3245 			 */
3246 			polinfo = pg_malloc(sizeof(PolicyInfo));
3247 			polinfo->dobj.objType = DO_POLICY;
3248 			polinfo->dobj.catId.tableoid = 0;
3249 			polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3250 			AssignDumpId(&polinfo->dobj);
3251 			polinfo->dobj.namespace = tbinfo->dobj.namespace;
3252 			polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3253 			polinfo->poltable = tbinfo;
3254 			polinfo->polname = NULL;
3255 			polinfo->polcmd = NULL;
3256 			polinfo->polroles = NULL;
3257 			polinfo->polqual = NULL;
3258 			polinfo->polwithcheck = NULL;
3259 		}
3260 	}
3261 
3262 	/*
3263 	 * Now, read all RLS policies, and create PolicyInfo objects for all those
3264 	 * that are of interest.
3265 	 */
3266 	if (g_verbose)
3267 		write_msg(NULL, "reading row-level security policies\n");
3268 
3269 	printfPQExpBuffer(query,
3270 					  "SELECT oid, tableoid, pol.polrelid, pol.polname, pol.polcmd, "
3271 					  "CASE WHEN pol.polroles = '{0}' THEN 'PUBLIC' ELSE "
3272 					  "   pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
3273 					  "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3274 					  "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3275 					  "FROM pg_catalog.pg_policy pol");
3276 
3277 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3278 
3279 	ntups = PQntuples(res);
3280 	if (ntups > 0)
3281 	{
3282 		i_oid = PQfnumber(res, "oid");
3283 		i_tableoid = PQfnumber(res, "tableoid");
3284 		i_polrelid = PQfnumber(res, "polrelid");
3285 		i_polname = PQfnumber(res, "polname");
3286 		i_polcmd = PQfnumber(res, "polcmd");
3287 		i_polroles = PQfnumber(res, "polroles");
3288 		i_polqual = PQfnumber(res, "polqual");
3289 		i_polwithcheck = PQfnumber(res, "polwithcheck");
3290 
3291 		polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3292 
3293 		for (j = 0; j < ntups; j++)
3294 		{
3295 			Oid			polrelid = atooid(PQgetvalue(res, j, i_polrelid));
3296 			TableInfo  *tbinfo = findTableByOid(polrelid);
3297 
3298 			/*
3299 			 * Ignore row security on tables not to be dumped.  (This will
3300 			 * result in some harmless wasted slots in polinfo[].)
3301 			 */
3302 			if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3303 				continue;
3304 
3305 			polinfo[j].dobj.objType = DO_POLICY;
3306 			polinfo[j].dobj.catId.tableoid =
3307 				atooid(PQgetvalue(res, j, i_tableoid));
3308 			polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3309 			AssignDumpId(&polinfo[j].dobj);
3310 			polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3311 			polinfo[j].poltable = tbinfo;
3312 			polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3313 			polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3314 
3315 			polinfo[j].polcmd = pg_strdup(PQgetvalue(res, j, i_polcmd));
3316 			polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3317 
3318 			if (PQgetisnull(res, j, i_polqual))
3319 				polinfo[j].polqual = NULL;
3320 			else
3321 				polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3322 
3323 			if (PQgetisnull(res, j, i_polwithcheck))
3324 				polinfo[j].polwithcheck = NULL;
3325 			else
3326 				polinfo[j].polwithcheck
3327 					= pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3328 		}
3329 	}
3330 
3331 	PQclear(res);
3332 
3333 	destroyPQExpBuffer(query);
3334 }
3335 
3336 /*
3337  * dumpPolicy
3338  *	  dump the definition of the given policy
3339  */
3340 static void
dumpPolicy(Archive * fout,PolicyInfo * polinfo)3341 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3342 {
3343 	DumpOptions *dopt = fout->dopt;
3344 	TableInfo  *tbinfo = polinfo->poltable;
3345 	PQExpBuffer query;
3346 	PQExpBuffer delqry;
3347 	PQExpBuffer polprefix;
3348 	char	   *qtabname;
3349 	const char *cmd;
3350 	char	   *tag;
3351 
3352 	if (dopt->dataOnly)
3353 		return;
3354 
3355 	/*
3356 	 * If polname is NULL, then this record is just indicating that ROW LEVEL
3357 	 * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3358 	 * ROW LEVEL SECURITY.
3359 	 */
3360 	if (polinfo->polname == NULL)
3361 	{
3362 		query = createPQExpBuffer();
3363 
3364 		appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3365 						  fmtQualifiedDumpable(tbinfo));
3366 
3367 		/*
3368 		 * We must emit the ROW SECURITY object's dependency on its table
3369 		 * explicitly, because it will not match anything in pg_depend (unlike
3370 		 * the case for other PolicyInfo objects).
3371 		 */
3372 		if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3373 			ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3374 						 polinfo->dobj.name,
3375 						 polinfo->dobj.namespace->dobj.name,
3376 						 NULL,
3377 						 tbinfo->rolname, false,
3378 						 "ROW SECURITY", SECTION_POST_DATA,
3379 						 query->data, "", NULL,
3380 						 &(tbinfo->dobj.dumpId), 1,
3381 						 NULL, NULL);
3382 
3383 		destroyPQExpBuffer(query);
3384 		return;
3385 	}
3386 
3387 	if (strcmp(polinfo->polcmd, "*") == 0)
3388 		cmd = "ALL";
3389 	else if (strcmp(polinfo->polcmd, "r") == 0)
3390 		cmd = "SELECT";
3391 	else if (strcmp(polinfo->polcmd, "a") == 0)
3392 		cmd = "INSERT";
3393 	else if (strcmp(polinfo->polcmd, "w") == 0)
3394 		cmd = "UPDATE";
3395 	else if (strcmp(polinfo->polcmd, "d") == 0)
3396 		cmd = "DELETE";
3397 	else
3398 	{
3399 		write_msg(NULL, "unexpected policy command type: \"%s\"\n",
3400 				  polinfo->polcmd);
3401 		exit_nicely(1);
3402 	}
3403 
3404 	query = createPQExpBuffer();
3405 	delqry = createPQExpBuffer();
3406 	polprefix = createPQExpBuffer();
3407 
3408 	qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
3409 
3410 	appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3411 
3412 	appendPQExpBuffer(query, " ON %s FOR %s", fmtQualifiedDumpable(tbinfo),
3413 					  cmd);
3414 
3415 	if (polinfo->polroles != NULL)
3416 		appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3417 
3418 	if (polinfo->polqual != NULL)
3419 		appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3420 
3421 	if (polinfo->polwithcheck != NULL)
3422 		appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3423 
3424 	appendPQExpBuffer(query, ";\n");
3425 
3426 	appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3427 	appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3428 
3429 	appendPQExpBuffer(polprefix, "POLICY %s ON",
3430 					  fmtId(polinfo->polname));
3431 
3432 	tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3433 
3434 	if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3435 		ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3436 					 tag,
3437 					 polinfo->dobj.namespace->dobj.name,
3438 					 NULL,
3439 					 tbinfo->rolname, false,
3440 					 "POLICY", SECTION_POST_DATA,
3441 					 query->data, delqry->data, NULL,
3442 					 NULL, 0,
3443 					 NULL, NULL);
3444 
3445 	if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3446 		dumpComment(fout, polprefix->data, qtabname,
3447 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
3448 					polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
3449 
3450 	free(tag);
3451 	destroyPQExpBuffer(query);
3452 	destroyPQExpBuffer(delqry);
3453 	destroyPQExpBuffer(polprefix);
3454 	free(qtabname);
3455 }
3456 
3457 /*
3458  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
3459  * the object needs.
3460  */
3461 static void
append_depends_on_extension(Archive * fout,PQExpBuffer create,DumpableObject * dobj,const char * catalog,const char * keyword,const char * objname)3462 append_depends_on_extension(Archive *fout,
3463 							PQExpBuffer create,
3464 							DumpableObject *dobj,
3465 							const char *catalog,
3466 							const char *keyword,
3467 							const char *objname)
3468 {
3469 	if (dobj->depends_on_ext)
3470 	{
3471 		char   *nm;
3472 		PGresult   *res;
3473 		PQExpBuffer	query;
3474 		int		ntups;
3475 		int		i_extname;
3476 		int		i;
3477 
3478 		/* dodge fmtId() non-reentrancy */
3479 		nm = pg_strdup(objname);
3480 
3481 		query = createPQExpBuffer();
3482 		appendPQExpBuffer(query,
3483 						  "SELECT e.extname "
3484 						  "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
3485 						  "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
3486 						  "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
3487 						  "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
3488 						  catalog,
3489 						  dobj->catId.oid);
3490 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3491 		ntups = PQntuples(res);
3492 		i_extname = PQfnumber(res, "extname");
3493 		for (i = 0; i < ntups; i++)
3494 		{
3495 			appendPQExpBuffer(create, "ALTER %s %s DEPENDS ON EXTENSION %s;\n",
3496 							  keyword, nm,
3497 							  fmtId(PQgetvalue(res, i, i_extname)));
3498 		}
3499 
3500 		PQclear(res);
3501 		destroyPQExpBuffer(query);
3502 		pg_free(nm);
3503 	}
3504 }
3505 
3506 
3507 static void
binary_upgrade_set_type_oids_by_type_oid(Archive * fout,PQExpBuffer upgrade_buffer,Oid pg_type_oid)3508 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
3509 										 PQExpBuffer upgrade_buffer,
3510 										 Oid pg_type_oid)
3511 {
3512 	PQExpBuffer upgrade_query = createPQExpBuffer();
3513 	PGresult   *upgrade_res;
3514 	Oid			pg_type_array_oid;
3515 
3516 	appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
3517 	appendPQExpBuffer(upgrade_buffer,
3518 					  "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3519 					  pg_type_oid);
3520 
3521 	/* we only support old >= 8.3 for binary upgrades */
3522 	appendPQExpBuffer(upgrade_query,
3523 					  "SELECT typarray "
3524 					  "FROM pg_catalog.pg_type "
3525 					  "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
3526 					  pg_type_oid);
3527 
3528 	upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
3529 
3530 	pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
3531 
3532 	if (OidIsValid(pg_type_array_oid))
3533 	{
3534 		appendPQExpBufferStr(upgrade_buffer,
3535 			   "\n-- For binary upgrade, must preserve pg_type array oid\n");
3536 		appendPQExpBuffer(upgrade_buffer,
3537 						  "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3538 						  pg_type_array_oid);
3539 	}
3540 
3541 	PQclear(upgrade_res);
3542 	destroyPQExpBuffer(upgrade_query);
3543 }
3544 
3545 static bool
binary_upgrade_set_type_oids_by_rel_oid(Archive * fout,PQExpBuffer upgrade_buffer,Oid pg_rel_oid)3546 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
3547 										PQExpBuffer upgrade_buffer,
3548 										Oid pg_rel_oid)
3549 {
3550 	PQExpBuffer upgrade_query = createPQExpBuffer();
3551 	PGresult   *upgrade_res;
3552 	Oid			pg_type_oid;
3553 	bool		toast_set = false;
3554 
3555 	/* we only support old >= 8.3 for binary upgrades */
3556 	appendPQExpBuffer(upgrade_query,
3557 					  "SELECT c.reltype AS crel, t.reltype AS trel "
3558 					  "FROM pg_catalog.pg_class c "
3559 					  "LEFT JOIN pg_catalog.pg_class t ON "
3560 					  "  (c.reltoastrelid = t.oid) "
3561 					  "WHERE c.oid = '%u'::pg_catalog.oid;",
3562 					  pg_rel_oid);
3563 
3564 	upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
3565 
3566 	pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
3567 
3568 	binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
3569 											 pg_type_oid);
3570 
3571 	if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
3572 	{
3573 		/* Toast tables do not have pg_type array rows */
3574 		Oid			pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
3575 											PQfnumber(upgrade_res, "trel")));
3576 
3577 		appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
3578 		appendPQExpBuffer(upgrade_buffer,
3579 						  "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3580 						  pg_type_toast_oid);
3581 
3582 		toast_set = true;
3583 	}
3584 
3585 	PQclear(upgrade_res);
3586 	destroyPQExpBuffer(upgrade_query);
3587 
3588 	return toast_set;
3589 }
3590 
3591 static void
binary_upgrade_set_pg_class_oids(Archive * fout,PQExpBuffer upgrade_buffer,Oid pg_class_oid,bool is_index)3592 binary_upgrade_set_pg_class_oids(Archive *fout,
3593 								 PQExpBuffer upgrade_buffer, Oid pg_class_oid,
3594 								 bool is_index)
3595 {
3596 	PQExpBuffer upgrade_query = createPQExpBuffer();
3597 	PGresult   *upgrade_res;
3598 	Oid			pg_class_reltoastrelid;
3599 	Oid			pg_index_indexrelid;
3600 
3601 	appendPQExpBuffer(upgrade_query,
3602 					  "SELECT c.reltoastrelid, i.indexrelid "
3603 					  "FROM pg_catalog.pg_class c LEFT JOIN "
3604 					  "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
3605 					  "WHERE c.oid = '%u'::pg_catalog.oid;",
3606 					  pg_class_oid);
3607 
3608 	upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
3609 
3610 	pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
3611 	pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
3612 
3613 	appendPQExpBufferStr(upgrade_buffer,
3614 				   "\n-- For binary upgrade, must preserve pg_class oids\n");
3615 
3616 	if (!is_index)
3617 	{
3618 		appendPQExpBuffer(upgrade_buffer,
3619 						  "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
3620 						  pg_class_oid);
3621 		/* only tables have toast tables, not indexes */
3622 		if (OidIsValid(pg_class_reltoastrelid))
3623 		{
3624 			/*
3625 			 * One complexity is that the table definition might not require
3626 			 * the creation of a TOAST table, and the TOAST table might have
3627 			 * been created long after table creation, when the table was
3628 			 * loaded with wide data.  By setting the TOAST oid we force
3629 			 * creation of the TOAST heap and TOAST index by the backend so we
3630 			 * can cleanly copy the files during binary upgrade.
3631 			 */
3632 
3633 			appendPQExpBuffer(upgrade_buffer,
3634 							  "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
3635 							  pg_class_reltoastrelid);
3636 
3637 			/* every toast table has an index */
3638 			appendPQExpBuffer(upgrade_buffer,
3639 							  "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
3640 							  pg_index_indexrelid);
3641 		}
3642 	}
3643 	else
3644 		appendPQExpBuffer(upgrade_buffer,
3645 						  "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
3646 						  pg_class_oid);
3647 
3648 	appendPQExpBufferChar(upgrade_buffer, '\n');
3649 
3650 	PQclear(upgrade_res);
3651 	destroyPQExpBuffer(upgrade_query);
3652 }
3653 
3654 /*
3655  * If the DumpableObject is a member of an extension, add a suitable
3656  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
3657  *
3658  * For somewhat historical reasons, objname should already be quoted,
3659  * but not objnamespace (if any).
3660  */
3661 static void
binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,DumpableObject * dobj,const char * objtype,const char * objname,const char * objnamespace)3662 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
3663 								DumpableObject *dobj,
3664 								const char *objtype,
3665 								const char *objname,
3666 								const char *objnamespace)
3667 {
3668 	DumpableObject *extobj = NULL;
3669 	int			i;
3670 
3671 	if (!dobj->ext_member)
3672 		return;
3673 
3674 	/*
3675 	 * Find the parent extension.  We could avoid this search if we wanted to
3676 	 * add a link field to DumpableObject, but the space costs of that would
3677 	 * be considerable.  We assume that member objects could only have a
3678 	 * direct dependency on their own extension, not any others.
3679 	 */
3680 	for (i = 0; i < dobj->nDeps; i++)
3681 	{
3682 		extobj = findObjectByDumpId(dobj->dependencies[i]);
3683 		if (extobj && extobj->objType == DO_EXTENSION)
3684 			break;
3685 		extobj = NULL;
3686 	}
3687 	if (extobj == NULL)
3688 		exit_horribly(NULL, "could not find parent extension for %s %s\n",
3689 					  objtype, objname);
3690 
3691 	appendPQExpBufferStr(upgrade_buffer,
3692 	  "\n-- For binary upgrade, handle extension membership the hard way\n");
3693 	appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
3694 					  fmtId(extobj->name),
3695 					  objtype);
3696 	if (objnamespace && *objnamespace)
3697 		appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
3698 	appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
3699 }
3700 
3701 /*
3702  * getNamespaces:
3703  *	  read all namespaces in the system catalogs and return them in the
3704  * NamespaceInfo* structure
3705  *
3706  *	numNamespaces is set to the number of namespaces read in
3707  */
3708 NamespaceInfo *
getNamespaces(Archive * fout,int * numNamespaces)3709 getNamespaces(Archive *fout, int *numNamespaces)
3710 {
3711 	DumpOptions *dopt = fout->dopt;
3712 	PGresult   *res;
3713 	int			ntups;
3714 	int			i;
3715 	PQExpBuffer query;
3716 	NamespaceInfo *nsinfo;
3717 	int			i_tableoid;
3718 	int			i_oid;
3719 	int			i_nspname;
3720 	int			i_rolname;
3721 	int			i_nspacl;
3722 	int			i_rnspacl;
3723 	int			i_initnspacl;
3724 	int			i_initrnspacl;
3725 
3726 	/*
3727 	 * Before 7.3, there are no real namespaces; create two dummy entries, one
3728 	 * for user stuff and one for system stuff.
3729 	 */
3730 	if (fout->remoteVersion < 70300)
3731 	{
3732 		nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
3733 
3734 		nsinfo[0].dobj.objType = DO_NAMESPACE;
3735 		nsinfo[0].dobj.catId.tableoid = 0;
3736 		nsinfo[0].dobj.catId.oid = 0;
3737 		AssignDumpId(&nsinfo[0].dobj);
3738 		nsinfo[0].dobj.name = pg_strdup("public");
3739 		nsinfo[0].rolname = pg_strdup("");
3740 		nsinfo[0].nspacl = pg_strdup("");
3741 		nsinfo[0].rnspacl = pg_strdup("");
3742 		nsinfo[0].initnspacl = pg_strdup("");
3743 		nsinfo[0].initrnspacl = pg_strdup("");
3744 
3745 		selectDumpableNamespace(&nsinfo[0], fout);
3746 
3747 		nsinfo[1].dobj.objType = DO_NAMESPACE;
3748 		nsinfo[1].dobj.catId.tableoid = 0;
3749 		nsinfo[1].dobj.catId.oid = 1;
3750 		AssignDumpId(&nsinfo[1].dobj);
3751 		nsinfo[1].dobj.name = pg_strdup("pg_catalog");
3752 		nsinfo[1].rolname = pg_strdup("");
3753 		nsinfo[1].nspacl = pg_strdup("");
3754 		nsinfo[1].rnspacl = pg_strdup("");
3755 		nsinfo[1].initnspacl = pg_strdup("");
3756 		nsinfo[1].initrnspacl = pg_strdup("");
3757 
3758 		selectDumpableNamespace(&nsinfo[1], fout);
3759 
3760 		*numNamespaces = 2;
3761 
3762 		return nsinfo;
3763 	}
3764 
3765 	query = createPQExpBuffer();
3766 
3767 	/*
3768 	 * we fetch all namespaces including system ones, so that every object we
3769 	 * read in can be linked to a containing namespace.
3770 	 */
3771 	if (fout->remoteVersion >= 90600)
3772 	{
3773 		PQExpBuffer acl_subquery = createPQExpBuffer();
3774 		PQExpBuffer racl_subquery = createPQExpBuffer();
3775 		PQExpBuffer init_acl_subquery = createPQExpBuffer();
3776 		PQExpBuffer init_racl_subquery = createPQExpBuffer();
3777 
3778 		buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3779 						init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
3780 						dopt->binary_upgrade);
3781 
3782 		appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
3783 						  "(%s nspowner) AS rolname, "
3784 						  "%s as nspacl, "
3785 						  "%s as rnspacl, "
3786 						  "%s as initnspacl, "
3787 						  "%s as initrnspacl "
3788 						  "FROM pg_namespace n "
3789 						  "LEFT JOIN pg_init_privs pip "
3790 						  "ON (n.oid = pip.objoid "
3791 						  "AND pip.classoid = 'pg_namespace'::regclass "
3792 						  "AND pip.objsubid = 0",
3793 						  username_subquery,
3794 						  acl_subquery->data,
3795 						  racl_subquery->data,
3796 						  init_acl_subquery->data,
3797 						  init_racl_subquery->data);
3798 
3799 		/*
3800 		 * When we are doing a 'clean' run, we will be dropping and recreating
3801 		 * the 'public' schema (the only object which has that kind of
3802 		 * treatment in the backend and which has an entry in pg_init_privs)
3803 		 * and therefore we should not consider any initial privileges in
3804 		 * pg_init_privs in that case.
3805 		 *
3806 		 * See pg_backup_archiver.c:_printTocEntry() for the details on why
3807 		 * the public schema is special in this regard.
3808 		 *
3809 		 * Note that if the public schema is dropped and re-created, this is
3810 		 * essentially a no-op because the new public schema won't have an
3811 		 * entry in pg_init_privs anyway, as the entry will be removed when
3812 		 * the public schema is dropped.
3813 		 *
3814 		 * Further, we have to handle the case where the public schema does
3815 		 * not exist at all.
3816 		 */
3817 		if (dopt->outputClean)
3818 			appendPQExpBuffer(query," AND pip.objoid <> "
3819 									"coalesce((select oid from pg_namespace "
3820 									"where nspname = 'public'),0)");
3821 
3822 		appendPQExpBuffer(query,") ");
3823 
3824 		destroyPQExpBuffer(acl_subquery);
3825 		destroyPQExpBuffer(racl_subquery);
3826 		destroyPQExpBuffer(init_acl_subquery);
3827 		destroyPQExpBuffer(init_racl_subquery);
3828 	}
3829 	else
3830 		appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
3831 						  "(%s nspowner) AS rolname, "
3832 						  "nspacl, NULL as rnspacl, "
3833 						  "NULL AS initnspacl, NULL as initrnspacl "
3834 						  "FROM pg_namespace",
3835 						  username_subquery);
3836 
3837 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3838 
3839 	ntups = PQntuples(res);
3840 
3841 	nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
3842 
3843 	i_tableoid = PQfnumber(res, "tableoid");
3844 	i_oid = PQfnumber(res, "oid");
3845 	i_nspname = PQfnumber(res, "nspname");
3846 	i_rolname = PQfnumber(res, "rolname");
3847 	i_nspacl = PQfnumber(res, "nspacl");
3848 	i_rnspacl = PQfnumber(res, "rnspacl");
3849 	i_initnspacl = PQfnumber(res, "initnspacl");
3850 	i_initrnspacl = PQfnumber(res, "initrnspacl");
3851 
3852 	for (i = 0; i < ntups; i++)
3853 	{
3854 		nsinfo[i].dobj.objType = DO_NAMESPACE;
3855 		nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3856 		nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3857 		AssignDumpId(&nsinfo[i].dobj);
3858 		nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
3859 		nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3860 		nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
3861 		nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
3862 		nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
3863 		nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
3864 
3865 		/* Decide whether to dump this namespace */
3866 		selectDumpableNamespace(&nsinfo[i], fout);
3867 
3868 		/*
3869 		 * Do not try to dump ACL if the ACL is empty or the default.
3870 		 *
3871 		 * This is useful because, for some schemas/objects, the only
3872 		 * component we are going to try and dump is the ACL and if we can
3873 		 * remove that then 'dump' goes to zero/false and we don't consider
3874 		 * this object for dumping at all later on.
3875 		 */
3876 		if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
3877 			PQgetisnull(res, i, i_initnspacl) &&
3878 			PQgetisnull(res, i, i_initrnspacl))
3879 			nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3880 
3881 		if (strlen(nsinfo[i].rolname) == 0)
3882 			write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
3883 					  nsinfo[i].dobj.name);
3884 	}
3885 
3886 	PQclear(res);
3887 	destroyPQExpBuffer(query);
3888 
3889 	*numNamespaces = ntups;
3890 
3891 	return nsinfo;
3892 }
3893 
3894 /*
3895  * findNamespace:
3896  *		given a namespace OID and an object OID, look up the info read by
3897  *		getNamespaces
3898  *
3899  * NB: for pre-7.3 source database, we use object OID to guess whether it's
3900  * a system object or not.  In 7.3 and later there is no guessing, and we
3901  * don't use objoid at all.
3902  */
3903 static NamespaceInfo *
findNamespace(Archive * fout,Oid nsoid,Oid objoid)3904 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
3905 {
3906 	NamespaceInfo *nsinfo;
3907 
3908 	if (fout->remoteVersion >= 70300)
3909 	{
3910 		nsinfo = findNamespaceByOid(nsoid);
3911 	}
3912 	else
3913 	{
3914 		/* This code depends on the dummy objects set up by getNamespaces. */
3915 		Oid			i;
3916 
3917 		if (objoid > g_last_builtin_oid)
3918 			i = 0;				/* user object */
3919 		else
3920 			i = 1;				/* system object */
3921 		nsinfo = findNamespaceByOid(i);
3922 	}
3923 
3924 	if (nsinfo == NULL)
3925 		exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
3926 
3927 	return nsinfo;
3928 }
3929 
3930 /*
3931  * getExtensions:
3932  *	  read all extensions in the system catalogs and return them in the
3933  * ExtensionInfo* structure
3934  *
3935  *	numExtensions is set to the number of extensions read in
3936  */
3937 ExtensionInfo *
getExtensions(Archive * fout,int * numExtensions)3938 getExtensions(Archive *fout, int *numExtensions)
3939 {
3940 	DumpOptions *dopt = fout->dopt;
3941 	PGresult   *res;
3942 	int			ntups;
3943 	int			i;
3944 	PQExpBuffer query;
3945 	ExtensionInfo *extinfo;
3946 	int			i_tableoid;
3947 	int			i_oid;
3948 	int			i_extname;
3949 	int			i_nspname;
3950 	int			i_extrelocatable;
3951 	int			i_extversion;
3952 	int			i_extconfig;
3953 	int			i_extcondition;
3954 
3955 	/*
3956 	 * Before 9.1, there are no extensions.
3957 	 */
3958 	if (fout->remoteVersion < 90100)
3959 	{
3960 		*numExtensions = 0;
3961 		return NULL;
3962 	}
3963 
3964 	query = createPQExpBuffer();
3965 
3966 	appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
3967 						 "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
3968 						 "FROM pg_extension x "
3969 						 "JOIN pg_namespace n ON n.oid = x.extnamespace");
3970 
3971 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3972 
3973 	ntups = PQntuples(res);
3974 
3975 	extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
3976 
3977 	i_tableoid = PQfnumber(res, "tableoid");
3978 	i_oid = PQfnumber(res, "oid");
3979 	i_extname = PQfnumber(res, "extname");
3980 	i_nspname = PQfnumber(res, "nspname");
3981 	i_extrelocatable = PQfnumber(res, "extrelocatable");
3982 	i_extversion = PQfnumber(res, "extversion");
3983 	i_extconfig = PQfnumber(res, "extconfig");
3984 	i_extcondition = PQfnumber(res, "extcondition");
3985 
3986 	for (i = 0; i < ntups; i++)
3987 	{
3988 		extinfo[i].dobj.objType = DO_EXTENSION;
3989 		extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3990 		extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3991 		AssignDumpId(&extinfo[i].dobj);
3992 		extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
3993 		extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
3994 		extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
3995 		extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
3996 		extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
3997 		extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
3998 
3999 		/* Decide whether we want to dump it */
4000 		selectDumpableExtension(&(extinfo[i]), dopt);
4001 	}
4002 
4003 	PQclear(res);
4004 	destroyPQExpBuffer(query);
4005 
4006 	*numExtensions = ntups;
4007 
4008 	return extinfo;
4009 }
4010 
4011 /*
4012  * getTypes:
4013  *	  read all types in the system catalogs and return them in the
4014  * TypeInfo* structure
4015  *
4016  *	numTypes is set to the number of types read in
4017  *
4018  * NB: this must run after getFuncs() because we assume we can do
4019  * findFuncByOid().
4020  */
4021 TypeInfo *
getTypes(Archive * fout,int * numTypes)4022 getTypes(Archive *fout, int *numTypes)
4023 {
4024 	DumpOptions *dopt = fout->dopt;
4025 	PGresult   *res;
4026 	int			ntups;
4027 	int			i;
4028 	PQExpBuffer query = createPQExpBuffer();
4029 	TypeInfo   *tyinfo;
4030 	ShellTypeInfo *stinfo;
4031 	int			i_tableoid;
4032 	int			i_oid;
4033 	int			i_typname;
4034 	int			i_typnamespace;
4035 	int			i_typacl;
4036 	int			i_rtypacl;
4037 	int			i_inittypacl;
4038 	int			i_initrtypacl;
4039 	int			i_rolname;
4040 	int			i_typinput;
4041 	int			i_typoutput;
4042 	int			i_typelem;
4043 	int			i_typrelid;
4044 	int			i_typrelkind;
4045 	int			i_typtype;
4046 	int			i_typisdefined;
4047 	int			i_isarray;
4048 
4049 	/*
4050 	 * we include even the built-in types because those may be used as array
4051 	 * elements by user-defined types
4052 	 *
4053 	 * we filter out the built-in types when we dump out the types
4054 	 *
4055 	 * same approach for undefined (shell) types and array types
4056 	 *
4057 	 * Note: as of 8.3 we can reliably detect whether a type is an
4058 	 * auto-generated array type by checking the element type's typarray.
4059 	 * (Before that the test is capable of generating false positives.) We
4060 	 * still check for name beginning with '_', though, so as to avoid the
4061 	 * cost of the subselect probe for all standard types.  This would have to
4062 	 * be revisited if the backend ever allows renaming of array types.
4063 	 */
4064 
4065 	if (fout->remoteVersion >= 90600)
4066 	{
4067 		PQExpBuffer acl_subquery = createPQExpBuffer();
4068 		PQExpBuffer racl_subquery = createPQExpBuffer();
4069 		PQExpBuffer initacl_subquery = createPQExpBuffer();
4070 		PQExpBuffer initracl_subquery = createPQExpBuffer();
4071 
4072 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4073 						initracl_subquery, "t.typacl", "t.typowner", "'T'",
4074 						dopt->binary_upgrade);
4075 
4076 		appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4077 						  "t.typnamespace, "
4078 						  "%s AS typacl, "
4079 						  "%s AS rtypacl, "
4080 						  "%s AS inittypacl, "
4081 						  "%s AS initrtypacl, "
4082 						  "(%s t.typowner) AS rolname, "
4083 						  "t.typinput::oid AS typinput, "
4084 					 "t.typoutput::oid AS typoutput, t.typelem, t.typrelid, "
4085 						  "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4086 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4087 						  "t.typtype, t.typisdefined, "
4088 						  "t.typname[0] = '_' AND t.typelem != 0 AND "
4089 						  "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4090 						  "FROM pg_type t "
4091 						  "LEFT JOIN pg_init_privs pip ON "
4092 						  "(t.oid = pip.objoid "
4093 						  "AND pip.classoid = 'pg_type'::regclass "
4094 						  "AND pip.objsubid = 0) ",
4095 						  acl_subquery->data,
4096 						  racl_subquery->data,
4097 						  initacl_subquery->data,
4098 						  initracl_subquery->data,
4099 						  username_subquery);
4100 
4101 		destroyPQExpBuffer(acl_subquery);
4102 		destroyPQExpBuffer(racl_subquery);
4103 		destroyPQExpBuffer(initacl_subquery);
4104 		destroyPQExpBuffer(initracl_subquery);
4105 	}
4106 	else if (fout->remoteVersion >= 90200)
4107 	{
4108 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4109 						  "typnamespace, typacl, NULL as rtypacl, "
4110 						  "NULL AS inittypacl, NULL AS initrtypacl, "
4111 						  "(%s typowner) AS rolname, "
4112 						  "typinput::oid AS typinput, "
4113 						  "typoutput::oid AS typoutput, typelem, typrelid, "
4114 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4115 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4116 						  "typtype, typisdefined, "
4117 						  "typname[0] = '_' AND typelem != 0 AND "
4118 						  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4119 						  "FROM pg_type",
4120 						  username_subquery);
4121 	}
4122 	else if (fout->remoteVersion >= 80300)
4123 	{
4124 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4125 						  "typnamespace, NULL AS typacl, NULL as rtypacl, "
4126 						  "NULL AS inittypacl, NULL AS initrtypacl, "
4127 						  "(%s typowner) AS rolname, "
4128 						  "typinput::oid AS typinput, "
4129 						  "typoutput::oid AS typoutput, typelem, typrelid, "
4130 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4131 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4132 						  "typtype, typisdefined, "
4133 						  "typname[0] = '_' AND typelem != 0 AND "
4134 						  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4135 						  "FROM pg_type",
4136 						  username_subquery);
4137 	}
4138 	else if (fout->remoteVersion >= 70300)
4139 	{
4140 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4141 						  "typnamespace, NULL AS typacl, NULL as rtypacl, "
4142 						  "NULL AS inittypacl, NULL AS initrtypacl, "
4143 						  "(%s typowner) AS rolname, "
4144 						  "typinput::oid AS typinput, "
4145 						  "typoutput::oid AS typoutput, typelem, typrelid, "
4146 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4147 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4148 						  "typtype, typisdefined, "
4149 						  "typname[0] = '_' AND typelem != 0 AS isarray "
4150 						  "FROM pg_type",
4151 						  username_subquery);
4152 	}
4153 	else if (fout->remoteVersion >= 70100)
4154 	{
4155 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4156 				  "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, "
4157 						  "NULL AS inittypacl, NULL AS initrtypacl, "
4158 						  "(%s typowner) AS rolname, "
4159 						  "typinput::oid AS typinput, "
4160 						  "typoutput::oid AS typoutput, typelem, typrelid, "
4161 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4162 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4163 						  "typtype, typisdefined, "
4164 						  "typname[0] = '_' AND typelem != 0 AS isarray "
4165 						  "FROM pg_type",
4166 						  username_subquery);
4167 	}
4168 	else
4169 	{
4170 		appendPQExpBuffer(query, "SELECT "
4171 		 "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
4172 						  "oid, typname, "
4173 				  "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, "
4174 						  "NULL AS inittypacl, NULL AS initrtypacl, "
4175 						  "(%s typowner) AS rolname, "
4176 						  "typinput::oid AS typinput, "
4177 						  "typoutput::oid AS typoutput, typelem, typrelid, "
4178 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4179 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4180 						  "typtype, typisdefined, "
4181 						  "typname[0] = '_' AND typelem != 0 AS isarray "
4182 						  "FROM pg_type",
4183 						  username_subquery);
4184 	}
4185 
4186 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4187 
4188 	ntups = PQntuples(res);
4189 
4190 	tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4191 
4192 	i_tableoid = PQfnumber(res, "tableoid");
4193 	i_oid = PQfnumber(res, "oid");
4194 	i_typname = PQfnumber(res, "typname");
4195 	i_typnamespace = PQfnumber(res, "typnamespace");
4196 	i_typacl = PQfnumber(res, "typacl");
4197 	i_rtypacl = PQfnumber(res, "rtypacl");
4198 	i_inittypacl = PQfnumber(res, "inittypacl");
4199 	i_initrtypacl = PQfnumber(res, "initrtypacl");
4200 	i_rolname = PQfnumber(res, "rolname");
4201 	i_typinput = PQfnumber(res, "typinput");
4202 	i_typoutput = PQfnumber(res, "typoutput");
4203 	i_typelem = PQfnumber(res, "typelem");
4204 	i_typrelid = PQfnumber(res, "typrelid");
4205 	i_typrelkind = PQfnumber(res, "typrelkind");
4206 	i_typtype = PQfnumber(res, "typtype");
4207 	i_typisdefined = PQfnumber(res, "typisdefined");
4208 	i_isarray = PQfnumber(res, "isarray");
4209 
4210 	for (i = 0; i < ntups; i++)
4211 	{
4212 		tyinfo[i].dobj.objType = DO_TYPE;
4213 		tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4214 		tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4215 		AssignDumpId(&tyinfo[i].dobj);
4216 		tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4217 		tyinfo[i].dobj.namespace =
4218 			findNamespace(fout,
4219 						  atooid(PQgetvalue(res, i, i_typnamespace)),
4220 						  tyinfo[i].dobj.catId.oid);
4221 		tyinfo[i].ftypname = NULL;	/* may get filled later */
4222 		tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4223 		tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4224 		tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4225 		tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4226 		tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4227 		tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4228 		tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4229 		tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4230 		tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4231 		tyinfo[i].shellType = NULL;
4232 
4233 		if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4234 			tyinfo[i].isDefined = true;
4235 		else
4236 			tyinfo[i].isDefined = false;
4237 
4238 		if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4239 			tyinfo[i].isArray = true;
4240 		else
4241 			tyinfo[i].isArray = false;
4242 
4243 		/* Decide whether we want to dump it */
4244 		selectDumpableType(&tyinfo[i], fout);
4245 
4246 		/* Do not try to dump ACL if no ACL exists. */
4247 		if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4248 			PQgetisnull(res, i, i_inittypacl) &&
4249 			PQgetisnull(res, i, i_initrtypacl))
4250 			tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4251 
4252 		/*
4253 		 * If it's a domain, fetch info about its constraints, if any
4254 		 */
4255 		tyinfo[i].nDomChecks = 0;
4256 		tyinfo[i].domChecks = NULL;
4257 		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4258 			tyinfo[i].typtype == TYPTYPE_DOMAIN)
4259 			getDomainConstraints(fout, &(tyinfo[i]));
4260 
4261 		/*
4262 		 * If it's a base type, make a DumpableObject representing a shell
4263 		 * definition of the type.  We will need to dump that ahead of the I/O
4264 		 * functions for the type.  Similarly, range types need a shell
4265 		 * definition in case they have a canonicalize function.
4266 		 *
4267 		 * Note: the shell type doesn't have a catId.  You might think it
4268 		 * should copy the base type's catId, but then it might capture the
4269 		 * pg_depend entries for the type, which we don't want.
4270 		 */
4271 		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4272 			(tyinfo[i].typtype == TYPTYPE_BASE ||
4273 			 tyinfo[i].typtype == TYPTYPE_RANGE))
4274 		{
4275 			stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4276 			stinfo->dobj.objType = DO_SHELL_TYPE;
4277 			stinfo->dobj.catId = nilCatalogId;
4278 			AssignDumpId(&stinfo->dobj);
4279 			stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4280 			stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4281 			stinfo->baseType = &(tyinfo[i]);
4282 			tyinfo[i].shellType = stinfo;
4283 
4284 			/*
4285 			 * Initially mark the shell type as not to be dumped.  We'll only
4286 			 * dump it if the I/O or canonicalize functions need to be dumped;
4287 			 * this is taken care of while sorting dependencies.
4288 			 */
4289 			stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4290 
4291 			/*
4292 			 * However, if dumping from pre-7.3, there will be no dependency
4293 			 * info so we have to fake it here.  We only need to worry about
4294 			 * typinput and typoutput since the other functions only exist
4295 			 * post-7.3.
4296 			 */
4297 			if (fout->remoteVersion < 70300)
4298 			{
4299 				Oid			typinput;
4300 				Oid			typoutput;
4301 				FuncInfo   *funcInfo;
4302 
4303 				typinput = atooid(PQgetvalue(res, i, i_typinput));
4304 				typoutput = atooid(PQgetvalue(res, i, i_typoutput));
4305 
4306 				funcInfo = findFuncByOid(typinput);
4307 				if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4308 				{
4309 					/* base type depends on function */
4310 					addObjectDependency(&tyinfo[i].dobj,
4311 										funcInfo->dobj.dumpId);
4312 					/* function depends on shell type */
4313 					addObjectDependency(&funcInfo->dobj,
4314 										stinfo->dobj.dumpId);
4315 					/* mark shell type as to be dumped */
4316 					stinfo->dobj.dump = DUMP_COMPONENT_ALL;
4317 				}
4318 
4319 				funcInfo = findFuncByOid(typoutput);
4320 				if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4321 				{
4322 					/* base type depends on function */
4323 					addObjectDependency(&tyinfo[i].dobj,
4324 										funcInfo->dobj.dumpId);
4325 					/* function depends on shell type */
4326 					addObjectDependency(&funcInfo->dobj,
4327 										stinfo->dobj.dumpId);
4328 					/* mark shell type as to be dumped */
4329 					stinfo->dobj.dump = DUMP_COMPONENT_ALL;
4330 				}
4331 			}
4332 		}
4333 
4334 		if (strlen(tyinfo[i].rolname) == 0)
4335 			write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
4336 					  tyinfo[i].dobj.name);
4337 	}
4338 
4339 	*numTypes = ntups;
4340 
4341 	PQclear(res);
4342 
4343 	destroyPQExpBuffer(query);
4344 
4345 	return tyinfo;
4346 }
4347 
4348 /*
4349  * getOperators:
4350  *	  read all operators in the system catalogs and return them in the
4351  * OprInfo* structure
4352  *
4353  *	numOprs is set to the number of operators read in
4354  */
4355 OprInfo *
getOperators(Archive * fout,int * numOprs)4356 getOperators(Archive *fout, int *numOprs)
4357 {
4358 	PGresult   *res;
4359 	int			ntups;
4360 	int			i;
4361 	PQExpBuffer query = createPQExpBuffer();
4362 	OprInfo    *oprinfo;
4363 	int			i_tableoid;
4364 	int			i_oid;
4365 	int			i_oprname;
4366 	int			i_oprnamespace;
4367 	int			i_rolname;
4368 	int			i_oprkind;
4369 	int			i_oprcode;
4370 
4371 	/*
4372 	 * find all operators, including builtin operators; we filter out
4373 	 * system-defined operators at dump-out time.
4374 	 */
4375 
4376 	if (fout->remoteVersion >= 70300)
4377 	{
4378 		appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4379 						  "oprnamespace, "
4380 						  "(%s oprowner) AS rolname, "
4381 						  "oprkind, "
4382 						  "oprcode::oid AS oprcode "
4383 						  "FROM pg_operator",
4384 						  username_subquery);
4385 	}
4386 	else if (fout->remoteVersion >= 70100)
4387 	{
4388 		appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4389 						  "0::oid AS oprnamespace, "
4390 						  "(%s oprowner) AS rolname, "
4391 						  "oprkind, "
4392 						  "oprcode::oid AS oprcode "
4393 						  "FROM pg_operator",
4394 						  username_subquery);
4395 	}
4396 	else
4397 	{
4398 		appendPQExpBuffer(query, "SELECT "
4399 						  "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
4400 						  "oid, oprname, "
4401 						  "0::oid AS oprnamespace, "
4402 						  "(%s oprowner) AS rolname, "
4403 						  "oprkind, "
4404 						  "oprcode::oid AS oprcode "
4405 						  "FROM pg_operator",
4406 						  username_subquery);
4407 	}
4408 
4409 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4410 
4411 	ntups = PQntuples(res);
4412 	*numOprs = ntups;
4413 
4414 	oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
4415 
4416 	i_tableoid = PQfnumber(res, "tableoid");
4417 	i_oid = PQfnumber(res, "oid");
4418 	i_oprname = PQfnumber(res, "oprname");
4419 	i_oprnamespace = PQfnumber(res, "oprnamespace");
4420 	i_rolname = PQfnumber(res, "rolname");
4421 	i_oprkind = PQfnumber(res, "oprkind");
4422 	i_oprcode = PQfnumber(res, "oprcode");
4423 
4424 	for (i = 0; i < ntups; i++)
4425 	{
4426 		oprinfo[i].dobj.objType = DO_OPERATOR;
4427 		oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4428 		oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4429 		AssignDumpId(&oprinfo[i].dobj);
4430 		oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
4431 		oprinfo[i].dobj.namespace =
4432 			findNamespace(fout,
4433 						  atooid(PQgetvalue(res, i, i_oprnamespace)),
4434 						  oprinfo[i].dobj.catId.oid);
4435 		oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4436 		oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
4437 		oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
4438 
4439 		/* Decide whether we want to dump it */
4440 		selectDumpableObject(&(oprinfo[i].dobj), fout);
4441 
4442 		/* Operators do not currently have ACLs. */
4443 		oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4444 
4445 		if (strlen(oprinfo[i].rolname) == 0)
4446 			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
4447 					  oprinfo[i].dobj.name);
4448 	}
4449 
4450 	PQclear(res);
4451 
4452 	destroyPQExpBuffer(query);
4453 
4454 	return oprinfo;
4455 }
4456 
4457 /*
4458  * getCollations:
4459  *	  read all collations in the system catalogs and return them in the
4460  * CollInfo* structure
4461  *
4462  *	numCollations is set to the number of collations read in
4463  */
4464 CollInfo *
getCollations(Archive * fout,int * numCollations)4465 getCollations(Archive *fout, int *numCollations)
4466 {
4467 	PGresult   *res;
4468 	int			ntups;
4469 	int			i;
4470 	PQExpBuffer query;
4471 	CollInfo   *collinfo;
4472 	int			i_tableoid;
4473 	int			i_oid;
4474 	int			i_collname;
4475 	int			i_collnamespace;
4476 	int			i_rolname;
4477 
4478 	/* Collations didn't exist pre-9.1 */
4479 	if (fout->remoteVersion < 90100)
4480 	{
4481 		*numCollations = 0;
4482 		return NULL;
4483 	}
4484 
4485 	query = createPQExpBuffer();
4486 
4487 	/*
4488 	 * find all collations, including builtin collations; we filter out
4489 	 * system-defined collations at dump-out time.
4490 	 */
4491 
4492 	appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
4493 					  "collnamespace, "
4494 					  "(%s collowner) AS rolname "
4495 					  "FROM pg_collation",
4496 					  username_subquery);
4497 
4498 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4499 
4500 	ntups = PQntuples(res);
4501 	*numCollations = ntups;
4502 
4503 	collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
4504 
4505 	i_tableoid = PQfnumber(res, "tableoid");
4506 	i_oid = PQfnumber(res, "oid");
4507 	i_collname = PQfnumber(res, "collname");
4508 	i_collnamespace = PQfnumber(res, "collnamespace");
4509 	i_rolname = PQfnumber(res, "rolname");
4510 
4511 	for (i = 0; i < ntups; i++)
4512 	{
4513 		collinfo[i].dobj.objType = DO_COLLATION;
4514 		collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4515 		collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4516 		AssignDumpId(&collinfo[i].dobj);
4517 		collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
4518 		collinfo[i].dobj.namespace =
4519 			findNamespace(fout,
4520 						  atooid(PQgetvalue(res, i, i_collnamespace)),
4521 						  collinfo[i].dobj.catId.oid);
4522 		collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4523 
4524 		/* Decide whether we want to dump it */
4525 		selectDumpableObject(&(collinfo[i].dobj), fout);
4526 
4527 		/* Collations do not currently have ACLs. */
4528 		collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4529 	}
4530 
4531 	PQclear(res);
4532 
4533 	destroyPQExpBuffer(query);
4534 
4535 	return collinfo;
4536 }
4537 
4538 /*
4539  * getConversions:
4540  *	  read all conversions in the system catalogs and return them in the
4541  * ConvInfo* structure
4542  *
4543  *	numConversions is set to the number of conversions read in
4544  */
4545 ConvInfo *
getConversions(Archive * fout,int * numConversions)4546 getConversions(Archive *fout, int *numConversions)
4547 {
4548 	PGresult   *res;
4549 	int			ntups;
4550 	int			i;
4551 	PQExpBuffer query;
4552 	ConvInfo   *convinfo;
4553 	int			i_tableoid;
4554 	int			i_oid;
4555 	int			i_conname;
4556 	int			i_connamespace;
4557 	int			i_rolname;
4558 
4559 	/* Conversions didn't exist pre-7.3 */
4560 	if (fout->remoteVersion < 70300)
4561 	{
4562 		*numConversions = 0;
4563 		return NULL;
4564 	}
4565 
4566 	query = createPQExpBuffer();
4567 
4568 	/*
4569 	 * find all conversions, including builtin conversions; we filter out
4570 	 * system-defined conversions at dump-out time.
4571 	 */
4572 
4573 	appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4574 					  "connamespace, "
4575 					  "(%s conowner) AS rolname "
4576 					  "FROM pg_conversion",
4577 					  username_subquery);
4578 
4579 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4580 
4581 	ntups = PQntuples(res);
4582 	*numConversions = ntups;
4583 
4584 	convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
4585 
4586 	i_tableoid = PQfnumber(res, "tableoid");
4587 	i_oid = PQfnumber(res, "oid");
4588 	i_conname = PQfnumber(res, "conname");
4589 	i_connamespace = PQfnumber(res, "connamespace");
4590 	i_rolname = PQfnumber(res, "rolname");
4591 
4592 	for (i = 0; i < ntups; i++)
4593 	{
4594 		convinfo[i].dobj.objType = DO_CONVERSION;
4595 		convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4596 		convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4597 		AssignDumpId(&convinfo[i].dobj);
4598 		convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
4599 		convinfo[i].dobj.namespace =
4600 			findNamespace(fout,
4601 						  atooid(PQgetvalue(res, i, i_connamespace)),
4602 						  convinfo[i].dobj.catId.oid);
4603 		convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4604 
4605 		/* Decide whether we want to dump it */
4606 		selectDumpableObject(&(convinfo[i].dobj), fout);
4607 
4608 		/* Conversions do not currently have ACLs. */
4609 		convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4610 	}
4611 
4612 	PQclear(res);
4613 
4614 	destroyPQExpBuffer(query);
4615 
4616 	return convinfo;
4617 }
4618 
4619 /*
4620  * getAccessMethods:
4621  *	  read all user-defined access methods in the system catalogs and return
4622  *	  them in the AccessMethodInfo* structure
4623  *
4624  *	numAccessMethods is set to the number of access methods read in
4625  */
4626 AccessMethodInfo *
getAccessMethods(Archive * fout,int * numAccessMethods)4627 getAccessMethods(Archive *fout, int *numAccessMethods)
4628 {
4629 	PGresult   *res;
4630 	int			ntups;
4631 	int			i;
4632 	PQExpBuffer query;
4633 	AccessMethodInfo *aminfo;
4634 	int			i_tableoid;
4635 	int			i_oid;
4636 	int			i_amname;
4637 	int			i_amhandler;
4638 	int			i_amtype;
4639 
4640 	/* Before 9.6, there are no user-defined access methods */
4641 	if (fout->remoteVersion < 90600)
4642 	{
4643 		*numAccessMethods = 0;
4644 		return NULL;
4645 	}
4646 
4647 	query = createPQExpBuffer();
4648 
4649 	/* Select all access methods from pg_am table */
4650 	appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
4651 					  "amhandler::pg_catalog.regproc AS amhandler "
4652 					  "FROM pg_am");
4653 
4654 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4655 
4656 	ntups = PQntuples(res);
4657 	*numAccessMethods = ntups;
4658 
4659 	aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
4660 
4661 	i_tableoid = PQfnumber(res, "tableoid");
4662 	i_oid = PQfnumber(res, "oid");
4663 	i_amname = PQfnumber(res, "amname");
4664 	i_amhandler = PQfnumber(res, "amhandler");
4665 	i_amtype = PQfnumber(res, "amtype");
4666 
4667 	for (i = 0; i < ntups; i++)
4668 	{
4669 		aminfo[i].dobj.objType = DO_ACCESS_METHOD;
4670 		aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4671 		aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4672 		AssignDumpId(&aminfo[i].dobj);
4673 		aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
4674 		aminfo[i].dobj.namespace = NULL;
4675 		aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
4676 		aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
4677 
4678 		/* Decide whether we want to dump it */
4679 		selectDumpableAccessMethod(&(aminfo[i]), fout);
4680 
4681 		/* Access methods do not currently have ACLs. */
4682 		aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4683 	}
4684 
4685 	PQclear(res);
4686 
4687 	destroyPQExpBuffer(query);
4688 
4689 	return aminfo;
4690 }
4691 
4692 
4693 /*
4694  * getOpclasses:
4695  *	  read all opclasses in the system catalogs and return them in the
4696  * OpclassInfo* structure
4697  *
4698  *	numOpclasses is set to the number of opclasses read in
4699  */
4700 OpclassInfo *
getOpclasses(Archive * fout,int * numOpclasses)4701 getOpclasses(Archive *fout, int *numOpclasses)
4702 {
4703 	PGresult   *res;
4704 	int			ntups;
4705 	int			i;
4706 	PQExpBuffer query = createPQExpBuffer();
4707 	OpclassInfo *opcinfo;
4708 	int			i_tableoid;
4709 	int			i_oid;
4710 	int			i_opcname;
4711 	int			i_opcnamespace;
4712 	int			i_rolname;
4713 
4714 	/*
4715 	 * find all opclasses, including builtin opclasses; we filter out
4716 	 * system-defined opclasses at dump-out time.
4717 	 */
4718 
4719 	if (fout->remoteVersion >= 70300)
4720 	{
4721 		appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
4722 						  "opcnamespace, "
4723 						  "(%s opcowner) AS rolname "
4724 						  "FROM pg_opclass",
4725 						  username_subquery);
4726 	}
4727 	else if (fout->remoteVersion >= 70100)
4728 	{
4729 		appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
4730 							 "0::oid AS opcnamespace, "
4731 							 "''::name AS rolname "
4732 							 "FROM pg_opclass");
4733 	}
4734 	else
4735 	{
4736 		appendPQExpBufferStr(query, "SELECT "
4737 							 "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
4738 							 "oid, opcname, "
4739 							 "0::oid AS opcnamespace, "
4740 							 "''::name AS rolname "
4741 							 "FROM pg_opclass");
4742 	}
4743 
4744 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4745 
4746 	ntups = PQntuples(res);
4747 	*numOpclasses = ntups;
4748 
4749 	opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
4750 
4751 	i_tableoid = PQfnumber(res, "tableoid");
4752 	i_oid = PQfnumber(res, "oid");
4753 	i_opcname = PQfnumber(res, "opcname");
4754 	i_opcnamespace = PQfnumber(res, "opcnamespace");
4755 	i_rolname = PQfnumber(res, "rolname");
4756 
4757 	for (i = 0; i < ntups; i++)
4758 	{
4759 		opcinfo[i].dobj.objType = DO_OPCLASS;
4760 		opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4761 		opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4762 		AssignDumpId(&opcinfo[i].dobj);
4763 		opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
4764 		opcinfo[i].dobj.namespace =
4765 			findNamespace(fout,
4766 						  atooid(PQgetvalue(res, i, i_opcnamespace)),
4767 						  opcinfo[i].dobj.catId.oid);
4768 		opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4769 
4770 		/* Decide whether we want to dump it */
4771 		selectDumpableObject(&(opcinfo[i].dobj), fout);
4772 
4773 		/* Op Classes do not currently have ACLs. */
4774 		opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4775 
4776 		if (fout->remoteVersion >= 70300)
4777 		{
4778 			if (strlen(opcinfo[i].rolname) == 0)
4779 				write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
4780 						  opcinfo[i].dobj.name);
4781 		}
4782 	}
4783 
4784 	PQclear(res);
4785 
4786 	destroyPQExpBuffer(query);
4787 
4788 	return opcinfo;
4789 }
4790 
4791 /*
4792  * getOpfamilies:
4793  *	  read all opfamilies in the system catalogs and return them in the
4794  * OpfamilyInfo* structure
4795  *
4796  *	numOpfamilies is set to the number of opfamilies read in
4797  */
4798 OpfamilyInfo *
getOpfamilies(Archive * fout,int * numOpfamilies)4799 getOpfamilies(Archive *fout, int *numOpfamilies)
4800 {
4801 	PGresult   *res;
4802 	int			ntups;
4803 	int			i;
4804 	PQExpBuffer query;
4805 	OpfamilyInfo *opfinfo;
4806 	int			i_tableoid;
4807 	int			i_oid;
4808 	int			i_opfname;
4809 	int			i_opfnamespace;
4810 	int			i_rolname;
4811 
4812 	/* Before 8.3, there is no separate concept of opfamilies */
4813 	if (fout->remoteVersion < 80300)
4814 	{
4815 		*numOpfamilies = 0;
4816 		return NULL;
4817 	}
4818 
4819 	query = createPQExpBuffer();
4820 
4821 	/*
4822 	 * find all opfamilies, including builtin opfamilies; we filter out
4823 	 * system-defined opfamilies at dump-out time.
4824 	 */
4825 
4826 	appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
4827 					  "opfnamespace, "
4828 					  "(%s opfowner) AS rolname "
4829 					  "FROM pg_opfamily",
4830 					  username_subquery);
4831 
4832 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4833 
4834 	ntups = PQntuples(res);
4835 	*numOpfamilies = ntups;
4836 
4837 	opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
4838 
4839 	i_tableoid = PQfnumber(res, "tableoid");
4840 	i_oid = PQfnumber(res, "oid");
4841 	i_opfname = PQfnumber(res, "opfname");
4842 	i_opfnamespace = PQfnumber(res, "opfnamespace");
4843 	i_rolname = PQfnumber(res, "rolname");
4844 
4845 	for (i = 0; i < ntups; i++)
4846 	{
4847 		opfinfo[i].dobj.objType = DO_OPFAMILY;
4848 		opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4849 		opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4850 		AssignDumpId(&opfinfo[i].dobj);
4851 		opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
4852 		opfinfo[i].dobj.namespace =
4853 			findNamespace(fout,
4854 						  atooid(PQgetvalue(res, i, i_opfnamespace)),
4855 						  opfinfo[i].dobj.catId.oid);
4856 		opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4857 
4858 		/* Decide whether we want to dump it */
4859 		selectDumpableObject(&(opfinfo[i].dobj), fout);
4860 
4861 		/* Extensions do not currently have ACLs. */
4862 		opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4863 
4864 		if (fout->remoteVersion >= 70300)
4865 		{
4866 			if (strlen(opfinfo[i].rolname) == 0)
4867 				write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
4868 						  opfinfo[i].dobj.name);
4869 		}
4870 	}
4871 
4872 	PQclear(res);
4873 
4874 	destroyPQExpBuffer(query);
4875 
4876 	return opfinfo;
4877 }
4878 
4879 /*
4880  * getAggregates:
4881  *	  read all the user-defined aggregates in the system catalogs and
4882  * return them in the AggInfo* structure
4883  *
4884  * numAggs is set to the number of aggregates read in
4885  */
4886 AggInfo *
getAggregates(Archive * fout,int * numAggs)4887 getAggregates(Archive *fout, int *numAggs)
4888 {
4889 	DumpOptions *dopt = fout->dopt;
4890 	PGresult   *res;
4891 	int			ntups;
4892 	int			i;
4893 	PQExpBuffer query = createPQExpBuffer();
4894 	AggInfo    *agginfo;
4895 	int			i_tableoid;
4896 	int			i_oid;
4897 	int			i_aggname;
4898 	int			i_aggnamespace;
4899 	int			i_pronargs;
4900 	int			i_proargtypes;
4901 	int			i_rolname;
4902 	int			i_aggacl;
4903 	int			i_raggacl;
4904 	int			i_initaggacl;
4905 	int			i_initraggacl;
4906 
4907 	/*
4908 	 * Find all interesting aggregates.  See comment in getFuncs() for the
4909 	 * rationale behind the filtering logic.
4910 	 */
4911 	if (fout->remoteVersion >= 90600)
4912 	{
4913 		PQExpBuffer acl_subquery = createPQExpBuffer();
4914 		PQExpBuffer racl_subquery = createPQExpBuffer();
4915 		PQExpBuffer initacl_subquery = createPQExpBuffer();
4916 		PQExpBuffer initracl_subquery = createPQExpBuffer();
4917 
4918 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4919 						initracl_subquery, "p.proacl", "p.proowner", "'f'",
4920 						dopt->binary_upgrade);
4921 
4922 		appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
4923 						  "p.proname AS aggname, "
4924 						  "p.pronamespace AS aggnamespace, "
4925 						  "p.pronargs, p.proargtypes, "
4926 						  "(%s p.proowner) AS rolname, "
4927 						  "%s AS aggacl, "
4928 						  "%s AS raggacl, "
4929 						  "%s AS initaggacl, "
4930 						  "%s AS initraggacl "
4931 						  "FROM pg_proc p "
4932 						  "LEFT JOIN pg_init_privs pip ON "
4933 						  "(p.oid = pip.objoid "
4934 						  "AND pip.classoid = 'pg_proc'::regclass "
4935 						  "AND pip.objsubid = 0) "
4936 						  "WHERE p.proisagg AND ("
4937 						  "p.pronamespace != "
4938 						  "(SELECT oid FROM pg_namespace "
4939 						  "WHERE nspname = 'pg_catalog') OR "
4940 						  "p.proacl IS DISTINCT FROM pip.initprivs",
4941 						  username_subquery,
4942 						  acl_subquery->data,
4943 						  racl_subquery->data,
4944 						  initacl_subquery->data,
4945 						  initracl_subquery->data);
4946 		if (dopt->binary_upgrade)
4947 			appendPQExpBufferStr(query,
4948 								 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4949 								 "classid = 'pg_proc'::regclass AND "
4950 								 "objid = p.oid AND "
4951 								 "refclassid = 'pg_extension'::regclass AND "
4952 								 "deptype = 'e')");
4953 		appendPQExpBufferChar(query, ')');
4954 
4955 		destroyPQExpBuffer(acl_subquery);
4956 		destroyPQExpBuffer(racl_subquery);
4957 		destroyPQExpBuffer(initacl_subquery);
4958 		destroyPQExpBuffer(initracl_subquery);
4959 	}
4960 	else if (fout->remoteVersion >= 80200)
4961 	{
4962 		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
4963 						  "pronamespace AS aggnamespace, "
4964 						  "pronargs, proargtypes, "
4965 						  "(%s proowner) AS rolname, "
4966 						  "proacl AS aggacl, "
4967 						  "NULL AS raggacl, "
4968 						  "NULL AS initaggacl, NULL AS initraggacl "
4969 						  "FROM pg_proc p "
4970 						  "WHERE proisagg AND ("
4971 						  "pronamespace != "
4972 						  "(SELECT oid FROM pg_namespace "
4973 						  "WHERE nspname = 'pg_catalog')",
4974 						  username_subquery);
4975 		if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
4976 			appendPQExpBufferStr(query,
4977 								 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4978 								 "classid = 'pg_proc'::regclass AND "
4979 								 "objid = p.oid AND "
4980 								 "refclassid = 'pg_extension'::regclass AND "
4981 								 "deptype = 'e')");
4982 		appendPQExpBufferChar(query, ')');
4983 	}
4984 	else if (fout->remoteVersion >= 70300)
4985 	{
4986 		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
4987 						  "pronamespace AS aggnamespace, "
4988 						  "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
4989 						  "proargtypes, "
4990 						  "(%s proowner) AS rolname, "
4991 						  "proacl AS aggacl, "
4992 						  "NULL AS raggacl, "
4993 						  "NULL AS initaggacl, NULL AS initraggacl "
4994 						  "FROM pg_proc "
4995 						  "WHERE proisagg "
4996 						  "AND pronamespace != "
4997 			   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
4998 						  username_subquery);
4999 	}
5000 	else if (fout->remoteVersion >= 70100)
5001 	{
5002 		appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
5003 						  "0::oid AS aggnamespace, "
5004 				  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
5005 						  "aggbasetype AS proargtypes, "
5006 						  "(%s aggowner) AS rolname, "
5007 						  "NULL AS aggacl, "
5008 						  "NULL AS raggacl, "
5009 						  "NULL AS initaggacl, NULL AS initraggacl "
5010 						  "FROM pg_aggregate "
5011 						  "where oid > '%u'::oid",
5012 						  username_subquery,
5013 						  g_last_builtin_oid);
5014 	}
5015 	else
5016 	{
5017 		appendPQExpBuffer(query, "SELECT "
5018 						  "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
5019 						  "oid, aggname, "
5020 						  "0::oid AS aggnamespace, "
5021 				  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
5022 						  "aggbasetype AS proargtypes, "
5023 						  "(%s aggowner) AS rolname, "
5024 						  "NULL AS aggacl, "
5025 						  "NULL AS raggacl, "
5026 						  "NULL AS initaggacl, NULL AS initraggacl "
5027 						  "FROM pg_aggregate "
5028 						  "where oid > '%u'::oid",
5029 						  username_subquery,
5030 						  g_last_builtin_oid);
5031 	}
5032 
5033 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5034 
5035 	ntups = PQntuples(res);
5036 	*numAggs = ntups;
5037 
5038 	agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5039 
5040 	i_tableoid = PQfnumber(res, "tableoid");
5041 	i_oid = PQfnumber(res, "oid");
5042 	i_aggname = PQfnumber(res, "aggname");
5043 	i_aggnamespace = PQfnumber(res, "aggnamespace");
5044 	i_pronargs = PQfnumber(res, "pronargs");
5045 	i_proargtypes = PQfnumber(res, "proargtypes");
5046 	i_rolname = PQfnumber(res, "rolname");
5047 	i_aggacl = PQfnumber(res, "aggacl");
5048 	i_raggacl = PQfnumber(res, "raggacl");
5049 	i_initaggacl = PQfnumber(res, "initaggacl");
5050 	i_initraggacl = PQfnumber(res, "initraggacl");
5051 
5052 	for (i = 0; i < ntups; i++)
5053 	{
5054 		agginfo[i].aggfn.dobj.objType = DO_AGG;
5055 		agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5056 		agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5057 		AssignDumpId(&agginfo[i].aggfn.dobj);
5058 		agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5059 		agginfo[i].aggfn.dobj.namespace =
5060 			findNamespace(fout,
5061 						  atooid(PQgetvalue(res, i, i_aggnamespace)),
5062 						  agginfo[i].aggfn.dobj.catId.oid);
5063 		agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5064 		if (strlen(agginfo[i].aggfn.rolname) == 0)
5065 			write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5066 					  agginfo[i].aggfn.dobj.name);
5067 		agginfo[i].aggfn.lang = InvalidOid;		/* not currently interesting */
5068 		agginfo[i].aggfn.prorettype = InvalidOid;		/* not saved */
5069 		agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5070 		agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5071 		agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5072 		agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5073 		agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5074 		if (agginfo[i].aggfn.nargs == 0)
5075 			agginfo[i].aggfn.argtypes = NULL;
5076 		else
5077 		{
5078 			agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5079 			if (fout->remoteVersion >= 70300)
5080 				parseOidArray(PQgetvalue(res, i, i_proargtypes),
5081 							  agginfo[i].aggfn.argtypes,
5082 							  agginfo[i].aggfn.nargs);
5083 			else
5084 				/* it's just aggbasetype */
5085 				agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
5086 		}
5087 
5088 		/* Decide whether we want to dump it */
5089 		selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5090 
5091 		/* Do not try to dump ACL if no ACL exists. */
5092 		if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5093 			PQgetisnull(res, i, i_initaggacl) &&
5094 			PQgetisnull(res, i, i_initraggacl))
5095 			agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5096 	}
5097 
5098 	PQclear(res);
5099 
5100 	destroyPQExpBuffer(query);
5101 
5102 	return agginfo;
5103 }
5104 
5105 /*
5106  * getFuncs:
5107  *	  read all the user-defined functions in the system catalogs and
5108  * return them in the FuncInfo* structure
5109  *
5110  * numFuncs is set to the number of functions read in
5111  */
5112 FuncInfo *
getFuncs(Archive * fout,int * numFuncs)5113 getFuncs(Archive *fout, int *numFuncs)
5114 {
5115 	DumpOptions *dopt = fout->dopt;
5116 	PGresult   *res;
5117 	int			ntups;
5118 	int			i;
5119 	PQExpBuffer query = createPQExpBuffer();
5120 	FuncInfo   *finfo;
5121 	int			i_tableoid;
5122 	int			i_oid;
5123 	int			i_proname;
5124 	int			i_pronamespace;
5125 	int			i_rolname;
5126 	int			i_prolang;
5127 	int			i_pronargs;
5128 	int			i_proargtypes;
5129 	int			i_prorettype;
5130 	int			i_proacl;
5131 	int			i_rproacl;
5132 	int			i_initproacl;
5133 	int			i_initrproacl;
5134 
5135 	/*
5136 	 * Find all interesting functions.  This is a bit complicated:
5137 	 *
5138 	 * 1. Always exclude aggregates; those are handled elsewhere.
5139 	 *
5140 	 * 2. Always exclude functions that are internally dependent on something
5141 	 * else, since presumably those will be created as a result of creating
5142 	 * the something else.  This currently acts only to suppress constructor
5143 	 * functions for range types (so we only need it in 9.2 and up).  Note
5144 	 * this is OK only because the constructors don't have any dependencies
5145 	 * the range type doesn't have; otherwise we might not get creation
5146 	 * ordering correct.
5147 	 *
5148 	 * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5149 	 * they're members of extensions and we are in binary-upgrade mode then
5150 	 * include them, since we want to dump extension members individually in
5151 	 * that mode.  Also, if they are used by casts or transforms then we need
5152 	 * to gather the information about them, though they won't be dumped if
5153 	 * they are built-in.  Also, in 9.6 and up, include functions in
5154 	 * pg_catalog if they have an ACL different from what's shown in
5155 	 * pg_init_privs.
5156 	 */
5157 	if (fout->remoteVersion >= 90600)
5158 	{
5159 		PQExpBuffer acl_subquery = createPQExpBuffer();
5160 		PQExpBuffer racl_subquery = createPQExpBuffer();
5161 		PQExpBuffer initacl_subquery = createPQExpBuffer();
5162 		PQExpBuffer initracl_subquery = createPQExpBuffer();
5163 
5164 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5165 						initracl_subquery, "p.proacl", "p.proowner", "'f'",
5166 						dopt->binary_upgrade);
5167 
5168 		appendPQExpBuffer(query,
5169 						  "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5170 						  "p.pronargs, p.proargtypes, p.prorettype, "
5171 						  "%s AS proacl, "
5172 						  "%s AS rproacl, "
5173 						  "%s AS initproacl, "
5174 						  "%s AS initrproacl, "
5175 						  "p.pronamespace, "
5176 						  "(%s p.proowner) AS rolname "
5177 						  "FROM pg_proc p "
5178 						  "LEFT JOIN pg_init_privs pip ON "
5179 						  "(p.oid = pip.objoid "
5180 						  "AND pip.classoid = 'pg_proc'::regclass "
5181 						  "AND pip.objsubid = 0) "
5182 						  "WHERE NOT proisagg"
5183 						  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5184 						  "WHERE classid = 'pg_proc'::regclass AND "
5185 						  "objid = p.oid AND deptype = 'i')"
5186 						  "\n  AND ("
5187 						  "\n  pronamespace != "
5188 						  "(SELECT oid FROM pg_namespace "
5189 						  "WHERE nspname = 'pg_catalog')"
5190 						  "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5191 						  "\n  WHERE pg_cast.oid > %u "
5192 						  "\n  AND p.oid = pg_cast.castfunc)"
5193 						  "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5194 						  "\n  WHERE pg_transform.oid > %u AND "
5195 						  "\n  (p.oid = pg_transform.trffromsql"
5196 						  "\n  OR p.oid = pg_transform.trftosql))",
5197 						  acl_subquery->data,
5198 						  racl_subquery->data,
5199 						  initacl_subquery->data,
5200 						  initracl_subquery->data,
5201 						  username_subquery,
5202 						  g_last_builtin_oid,
5203 						  g_last_builtin_oid);
5204 		if (dopt->binary_upgrade)
5205 			appendPQExpBufferStr(query,
5206 							   "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5207 								 "classid = 'pg_proc'::regclass AND "
5208 								 "objid = p.oid AND "
5209 								 "refclassid = 'pg_extension'::regclass AND "
5210 								 "deptype = 'e')");
5211 		appendPQExpBufferStr(query,
5212 						   "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5213 		appendPQExpBufferChar(query, ')');
5214 
5215 		destroyPQExpBuffer(acl_subquery);
5216 		destroyPQExpBuffer(racl_subquery);
5217 		destroyPQExpBuffer(initacl_subquery);
5218 		destroyPQExpBuffer(initracl_subquery);
5219 	}
5220 	else if (fout->remoteVersion >= 70300)
5221 	{
5222 		appendPQExpBuffer(query,
5223 						  "SELECT tableoid, oid, proname, prolang, "
5224 						  "pronargs, proargtypes, prorettype, proacl, "
5225 						  "NULL as rproacl, "
5226 						  "NULL as initproacl, NULL AS initrproacl, "
5227 						  "pronamespace, "
5228 						  "(%s proowner) AS rolname "
5229 						  "FROM pg_proc p "
5230 						  "WHERE NOT proisagg",
5231 						  username_subquery);
5232 		if (fout->remoteVersion >= 90200)
5233 			appendPQExpBufferStr(query,
5234 							   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5235 								 "WHERE classid = 'pg_proc'::regclass AND "
5236 								 "objid = p.oid AND deptype = 'i')");
5237 		appendPQExpBuffer(query,
5238 							 "\n  AND ("
5239 							 "\n  pronamespace != "
5240 							 "(SELECT oid FROM pg_namespace "
5241 							 "WHERE nspname = 'pg_catalog')"
5242 							 "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5243 							 "\n  WHERE pg_cast.oid > '%u'::oid"
5244 							 "\n  AND p.oid = pg_cast.castfunc)",
5245 							 g_last_builtin_oid);
5246 
5247 		if (fout->remoteVersion >= 90500)
5248 			appendPQExpBuffer(query,
5249 								 "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5250 								 "\n  WHERE pg_transform.oid > '%u'::oid"
5251 								 "\n  AND (p.oid = pg_transform.trffromsql"
5252 								 "\n  OR p.oid = pg_transform.trftosql))",
5253 								 g_last_builtin_oid);
5254 
5255 		if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5256 			appendPQExpBufferStr(query,
5257 							   "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5258 								 "classid = 'pg_proc'::regclass AND "
5259 								 "objid = p.oid AND "
5260 								 "refclassid = 'pg_extension'::regclass AND "
5261 								 "deptype = 'e')");
5262 		appendPQExpBufferChar(query, ')');
5263 	}
5264 	else if (fout->remoteVersion >= 70100)
5265 	{
5266 		appendPQExpBuffer(query,
5267 						  "SELECT tableoid, oid, proname, prolang, "
5268 						  "pronargs, proargtypes, prorettype, "
5269 						  "NULL AS proacl, "
5270 						  "NULL AS rproacl, "
5271 						  "NULL as initproacl, NULL AS initrproacl, "
5272 						  "0::oid AS pronamespace, "
5273 						  "(%s proowner) AS rolname "
5274 						  "FROM pg_proc "
5275 						  "WHERE pg_proc.oid > '%u'::oid",
5276 						  username_subquery,
5277 						  g_last_builtin_oid);
5278 	}
5279 	else
5280 	{
5281 		appendPQExpBuffer(query,
5282 						  "SELECT "
5283 						  "(SELECT oid FROM pg_class "
5284 						  " WHERE relname = 'pg_proc') AS tableoid, "
5285 						  "oid, proname, prolang, "
5286 						  "pronargs, proargtypes, prorettype, "
5287 						  "NULL AS proacl, "
5288 						  "NULL AS rproacl, "
5289 						  "NULL as initproacl, NULL AS initrproacl, "
5290 						  "0::oid AS pronamespace, "
5291 						  "(%s proowner) AS rolname "
5292 						  "FROM pg_proc "
5293 						  "where pg_proc.oid > '%u'::oid",
5294 						  username_subquery,
5295 						  g_last_builtin_oid);
5296 	}
5297 
5298 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5299 
5300 	ntups = PQntuples(res);
5301 
5302 	*numFuncs = ntups;
5303 
5304 	finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5305 
5306 	i_tableoid = PQfnumber(res, "tableoid");
5307 	i_oid = PQfnumber(res, "oid");
5308 	i_proname = PQfnumber(res, "proname");
5309 	i_pronamespace = PQfnumber(res, "pronamespace");
5310 	i_rolname = PQfnumber(res, "rolname");
5311 	i_prolang = PQfnumber(res, "prolang");
5312 	i_pronargs = PQfnumber(res, "pronargs");
5313 	i_proargtypes = PQfnumber(res, "proargtypes");
5314 	i_prorettype = PQfnumber(res, "prorettype");
5315 	i_proacl = PQfnumber(res, "proacl");
5316 	i_rproacl = PQfnumber(res, "rproacl");
5317 	i_initproacl = PQfnumber(res, "initproacl");
5318 	i_initrproacl = PQfnumber(res, "initrproacl");
5319 
5320 	for (i = 0; i < ntups; i++)
5321 	{
5322 		finfo[i].dobj.objType = DO_FUNC;
5323 		finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5324 		finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5325 		AssignDumpId(&finfo[i].dobj);
5326 		finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5327 		finfo[i].dobj.namespace =
5328 			findNamespace(fout,
5329 						  atooid(PQgetvalue(res, i, i_pronamespace)),
5330 						  finfo[i].dobj.catId.oid);
5331 		finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5332 		finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5333 		finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5334 		finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5335 		finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5336 		finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5337 		finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5338 		finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5339 		if (finfo[i].nargs == 0)
5340 			finfo[i].argtypes = NULL;
5341 		else
5342 		{
5343 			finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5344 			parseOidArray(PQgetvalue(res, i, i_proargtypes),
5345 						  finfo[i].argtypes, finfo[i].nargs);
5346 		}
5347 
5348 		/* Decide whether we want to dump it */
5349 		selectDumpableObject(&(finfo[i].dobj), fout);
5350 
5351 		/* Do not try to dump ACL if no ACL exists. */
5352 		if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5353 			PQgetisnull(res, i, i_initproacl) &&
5354 			PQgetisnull(res, i, i_initrproacl))
5355 			finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5356 
5357 		if (strlen(finfo[i].rolname) == 0)
5358 			write_msg(NULL,
5359 				 "WARNING: owner of function \"%s\" appears to be invalid\n",
5360 					  finfo[i].dobj.name);
5361 	}
5362 
5363 	PQclear(res);
5364 
5365 	destroyPQExpBuffer(query);
5366 
5367 	return finfo;
5368 }
5369 
5370 /*
5371  * getTables
5372  *	  read all the tables (no indexes)
5373  * in the system catalogs return them in the TableInfo* structure
5374  *
5375  * numTables is set to the number of tables read in
5376  */
5377 TableInfo *
getTables(Archive * fout,int * numTables)5378 getTables(Archive *fout, int *numTables)
5379 {
5380 	DumpOptions *dopt = fout->dopt;
5381 	PGresult   *res;
5382 	int			ntups;
5383 	int			i;
5384 	PQExpBuffer query = createPQExpBuffer();
5385 	TableInfo  *tblinfo;
5386 	int			i_reltableoid;
5387 	int			i_reloid;
5388 	int			i_relname;
5389 	int			i_relnamespace;
5390 	int			i_relkind;
5391 	int			i_relacl;
5392 	int			i_rrelacl;
5393 	int			i_initrelacl;
5394 	int			i_initrrelacl;
5395 	int			i_rolname;
5396 	int			i_relchecks;
5397 	int			i_relhastriggers;
5398 	int			i_relhasindex;
5399 	int			i_relhasrules;
5400 	int			i_relrowsec;
5401 	int			i_relforcerowsec;
5402 	int			i_relhasoids;
5403 	int			i_relfrozenxid;
5404 	int			i_relminmxid;
5405 	int			i_toastoid;
5406 	int			i_toastfrozenxid;
5407 	int			i_toastminmxid;
5408 	int			i_relpersistence;
5409 	int			i_relispopulated;
5410 	int			i_relreplident;
5411 	int			i_owning_tab;
5412 	int			i_owning_col;
5413 	int			i_reltablespace;
5414 	int			i_reloptions;
5415 	int			i_checkoption;
5416 	int			i_toastreloptions;
5417 	int			i_reloftype;
5418 	int			i_relpages;
5419 	int			i_changed_acl;
5420 
5421 	/*
5422 	 * Find all the tables and table-like objects.
5423 	 *
5424 	 * We include system catalogs, so that we can work if a user table is
5425 	 * defined to inherit from a system catalog (pretty weird, but...)
5426 	 *
5427 	 * We ignore relations that are not ordinary tables, sequences, views,
5428 	 * materialized views, composite types, or foreign tables.
5429 	 *
5430 	 * Composite-type table entries won't be dumped as such, but we have to
5431 	 * make a DumpableObject for them so that we can track dependencies of the
5432 	 * composite type (pg_depend entries for columns of the composite type
5433 	 * link to the pg_class entry not the pg_type entry).
5434 	 *
5435 	 * Note: in this phase we should collect only a minimal amount of
5436 	 * information about each table, basically just enough to decide if it is
5437 	 * interesting. We must fetch all tables in this phase because otherwise
5438 	 * we cannot correctly identify inherited columns, owned sequences, etc.
5439 	 */
5440 
5441 	if (fout->remoteVersion >= 90600)
5442 	{
5443 		PQExpBuffer acl_subquery = createPQExpBuffer();
5444 		PQExpBuffer racl_subquery = createPQExpBuffer();
5445 		PQExpBuffer initacl_subquery = createPQExpBuffer();
5446 		PQExpBuffer initracl_subquery = createPQExpBuffer();
5447 
5448 		PQExpBuffer attacl_subquery = createPQExpBuffer();
5449 		PQExpBuffer attracl_subquery = createPQExpBuffer();
5450 		PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5451 		PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5452 
5453 		/*
5454 		 * Left join to pick up dependency info linking sequences to their
5455 		 * owning column, if any (note this dependency is AUTO as of 8.2)
5456 		 *
5457 		 * Left join to detect if any privileges are still as-set-at-init, in
5458 		 * which case we won't dump out ACL commands for those.
5459 		 */
5460 
5461 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5462 						initracl_subquery, "c.relacl", "c.relowner",
5463 				 "CASE WHEN c.relkind = 'S' THEN 's' ELSE 'r' END::\"char\"",
5464 						dopt->binary_upgrade);
5465 
5466 		buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
5467 					  attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
5468 						dopt->binary_upgrade);
5469 
5470 		appendPQExpBuffer(query,
5471 						  "SELECT c.tableoid, c.oid, c.relname, "
5472 						  "%s AS relacl, %s as rrelacl, "
5473 						  "%s AS initrelacl, %s as initrrelacl, "
5474 						  "c.relkind, c.relnamespace, "
5475 						  "(%s c.relowner) AS rolname, "
5476 						  "c.relchecks, c.relhastriggers, "
5477 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
5478 						  "c.relrowsecurity, c.relforcerowsecurity, "
5479 						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5480 						  "tc.relfrozenxid AS tfrozenxid, "
5481 						  "tc.relminmxid AS tminmxid, "
5482 						  "c.relpersistence, c.relispopulated, "
5483 						  "c.relreplident, c.relpages, "
5484 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5485 						  "d.refobjid AS owning_tab, "
5486 						  "d.refobjsubid AS owning_col, "
5487 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5488 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5489 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5490 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5491 						  "tc.reloptions AS toast_reloptions, "
5492 						  "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
5493 						  "(c.oid = pip.objoid "
5494 						  "AND pip.classoid = 'pg_class'::regclass "
5495 						  "AND pip.objsubid = at.attnum)"
5496 						  "WHERE at.attrelid = c.oid AND ("
5497 						  "%s IS NOT NULL "
5498 						  "OR %s IS NOT NULL "
5499 						  "OR %s IS NOT NULL "
5500 						  "OR %s IS NOT NULL"
5501 						  "))"
5502 						  "AS changed_acl "
5503 						  "FROM pg_class c "
5504 						  "LEFT JOIN pg_depend d ON "
5505 						  "(c.relkind = '%c' AND "
5506 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
5507 						  "d.objsubid = 0 AND "
5508 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
5509 					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5510 						  "LEFT JOIN pg_init_privs pip ON "
5511 						  "(c.oid = pip.objoid "
5512 						  "AND pip.classoid = 'pg_class'::regclass "
5513 						  "AND pip.objsubid = 0) "
5514 				   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
5515 						  "ORDER BY c.oid",
5516 						  acl_subquery->data,
5517 						  racl_subquery->data,
5518 						  initacl_subquery->data,
5519 						  initracl_subquery->data,
5520 						  username_subquery,
5521 						  attacl_subquery->data,
5522 						  attracl_subquery->data,
5523 						  attinitacl_subquery->data,
5524 						  attinitracl_subquery->data,
5525 						  RELKIND_SEQUENCE,
5526 						  RELKIND_RELATION, RELKIND_SEQUENCE,
5527 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5528 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
5529 
5530 		destroyPQExpBuffer(acl_subquery);
5531 		destroyPQExpBuffer(racl_subquery);
5532 		destroyPQExpBuffer(initacl_subquery);
5533 		destroyPQExpBuffer(initracl_subquery);
5534 
5535 		destroyPQExpBuffer(attacl_subquery);
5536 		destroyPQExpBuffer(attracl_subquery);
5537 		destroyPQExpBuffer(attinitacl_subquery);
5538 		destroyPQExpBuffer(attinitracl_subquery);
5539 	}
5540 	else if (fout->remoteVersion >= 90500)
5541 	{
5542 		/*
5543 		 * Left join to pick up dependency info linking sequences to their
5544 		 * owning column, if any (note this dependency is AUTO as of 8.2)
5545 		 */
5546 		appendPQExpBuffer(query,
5547 						  "SELECT c.tableoid, c.oid, c.relname, "
5548 						  "c.relacl, NULL as rrelacl, "
5549 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5550 						  "c.relkind, "
5551 						  "c.relnamespace, "
5552 						  "(%s c.relowner) AS rolname, "
5553 						  "c.relchecks, c.relhastriggers, "
5554 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
5555 						  "c.relrowsecurity, c.relforcerowsecurity, "
5556 						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5557 						  "tc.relfrozenxid AS tfrozenxid, "
5558 						  "tc.relminmxid AS tminmxid, "
5559 						  "c.relpersistence, c.relispopulated, "
5560 						  "c.relreplident, c.relpages, "
5561 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5562 						  "d.refobjid AS owning_tab, "
5563 						  "d.refobjsubid AS owning_col, "
5564 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5565 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5566 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5567 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5568 						  "tc.reloptions AS toast_reloptions, "
5569 						  "NULL AS changed_acl "
5570 						  "FROM pg_class c "
5571 						  "LEFT JOIN pg_depend d ON "
5572 						  "(c.relkind = '%c' AND "
5573 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
5574 						  "d.objsubid = 0 AND "
5575 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
5576 					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5577 				   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
5578 						  "ORDER BY c.oid",
5579 						  username_subquery,
5580 						  RELKIND_SEQUENCE,
5581 						  RELKIND_RELATION, RELKIND_SEQUENCE,
5582 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5583 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
5584 	}
5585 	else if (fout->remoteVersion >= 90400)
5586 	{
5587 		/*
5588 		 * Left join to pick up dependency info linking sequences to their
5589 		 * owning column, if any (note this dependency is AUTO as of 8.2)
5590 		 */
5591 		appendPQExpBuffer(query,
5592 						  "SELECT c.tableoid, c.oid, c.relname, "
5593 						  "c.relacl, NULL as rrelacl, "
5594 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5595 						  "c.relkind, "
5596 						  "c.relnamespace, "
5597 						  "(%s c.relowner) AS rolname, "
5598 						  "c.relchecks, c.relhastriggers, "
5599 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
5600 						  "'f'::bool AS relrowsecurity, "
5601 						  "'f'::bool AS relforcerowsecurity, "
5602 						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5603 						  "tc.relfrozenxid AS tfrozenxid, "
5604 						  "tc.relminmxid AS tminmxid, "
5605 						  "c.relpersistence, c.relispopulated, "
5606 						  "c.relreplident, c.relpages, "
5607 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5608 						  "d.refobjid AS owning_tab, "
5609 						  "d.refobjsubid AS owning_col, "
5610 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5611 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5612 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5613 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5614 						  "tc.reloptions AS toast_reloptions, "
5615 						  "NULL AS changed_acl "
5616 						  "FROM pg_class c "
5617 						  "LEFT JOIN pg_depend d ON "
5618 						  "(c.relkind = '%c' AND "
5619 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
5620 						  "d.objsubid = 0 AND "
5621 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
5622 					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5623 				   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
5624 						  "ORDER BY c.oid",
5625 						  username_subquery,
5626 						  RELKIND_SEQUENCE,
5627 						  RELKIND_RELATION, RELKIND_SEQUENCE,
5628 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5629 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
5630 	}
5631 	else if (fout->remoteVersion >= 90300)
5632 	{
5633 		/*
5634 		 * Left join to pick up dependency info linking sequences to their
5635 		 * owning column, if any (note this dependency is AUTO as of 8.2)
5636 		 */
5637 		appendPQExpBuffer(query,
5638 						  "SELECT c.tableoid, c.oid, c.relname, "
5639 						  "c.relacl, NULL as rrelacl, "
5640 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5641 						  "c.relkind, "
5642 						  "c.relnamespace, "
5643 						  "(%s c.relowner) AS rolname, "
5644 						  "c.relchecks, c.relhastriggers, "
5645 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
5646 						  "'f'::bool AS relrowsecurity, "
5647 						  "'f'::bool AS relforcerowsecurity, "
5648 						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5649 						  "tc.relfrozenxid AS tfrozenxid, "
5650 						  "tc.relminmxid AS tminmxid, "
5651 						  "c.relpersistence, c.relispopulated, "
5652 						  "'d' AS relreplident, c.relpages, "
5653 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5654 						  "d.refobjid AS owning_tab, "
5655 						  "d.refobjsubid AS owning_col, "
5656 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5657 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5658 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5659 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5660 						  "tc.reloptions AS toast_reloptions, "
5661 						  "NULL AS changed_acl "
5662 						  "FROM pg_class c "
5663 						  "LEFT JOIN pg_depend d ON "
5664 						  "(c.relkind = '%c' AND "
5665 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
5666 						  "d.objsubid = 0 AND "
5667 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
5668 					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5669 				   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
5670 						  "ORDER BY c.oid",
5671 						  username_subquery,
5672 						  RELKIND_SEQUENCE,
5673 						  RELKIND_RELATION, RELKIND_SEQUENCE,
5674 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5675 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
5676 	}
5677 	else if (fout->remoteVersion >= 90100)
5678 	{
5679 		/*
5680 		 * Left join to pick up dependency info linking sequences to their
5681 		 * owning column, if any (note this dependency is AUTO as of 8.2)
5682 		 */
5683 		appendPQExpBuffer(query,
5684 						  "SELECT c.tableoid, c.oid, c.relname, "
5685 						  "c.relacl, NULL as rrelacl, "
5686 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5687 						  "c.relkind, "
5688 						  "c.relnamespace, "
5689 						  "(%s c.relowner) AS rolname, "
5690 						  "c.relchecks, c.relhastriggers, "
5691 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
5692 						  "'f'::bool AS relrowsecurity, "
5693 						  "'f'::bool AS relforcerowsecurity, "
5694 						  "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
5695 						  "tc.relfrozenxid AS tfrozenxid, "
5696 						  "0 AS tminmxid, "
5697 						  "c.relpersistence, 't' as relispopulated, "
5698 						  "'d' AS relreplident, c.relpages, "
5699 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5700 						  "d.refobjid AS owning_tab, "
5701 						  "d.refobjsubid AS owning_col, "
5702 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5703 						  "c.reloptions AS reloptions, "
5704 						  "tc.reloptions AS toast_reloptions, "
5705 						  "NULL AS changed_acl "
5706 						  "FROM pg_class c "
5707 						  "LEFT JOIN pg_depend d ON "
5708 						  "(c.relkind = '%c' AND "
5709 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
5710 						  "d.objsubid = 0 AND "
5711 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
5712 					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5713 				   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
5714 						  "ORDER BY c.oid",
5715 						  username_subquery,
5716 						  RELKIND_SEQUENCE,
5717 						  RELKIND_RELATION, RELKIND_SEQUENCE,
5718 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5719 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
5720 	}
5721 	else if (fout->remoteVersion >= 90000)
5722 	{
5723 		/*
5724 		 * Left join to pick up dependency info linking sequences to their
5725 		 * owning column, if any (note this dependency is AUTO as of 8.2)
5726 		 */
5727 		appendPQExpBuffer(query,
5728 						  "SELECT c.tableoid, c.oid, c.relname, "
5729 						  "c.relacl, NULL as rrelacl, "
5730 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5731 						  "c.relkind, "
5732 						  "c.relnamespace, "
5733 						  "(%s c.relowner) AS rolname, "
5734 						  "c.relchecks, c.relhastriggers, "
5735 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
5736 						  "'f'::bool AS relrowsecurity, "
5737 						  "'f'::bool AS relforcerowsecurity, "
5738 						  "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
5739 						  "tc.relfrozenxid AS tfrozenxid, "
5740 						  "0 AS tminmxid, "
5741 						  "'p' AS relpersistence, 't' as relispopulated, "
5742 						  "'d' AS relreplident, c.relpages, "
5743 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5744 						  "d.refobjid AS owning_tab, "
5745 						  "d.refobjsubid AS owning_col, "
5746 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5747 						  "c.reloptions AS reloptions, "
5748 						  "tc.reloptions AS toast_reloptions, "
5749 						  "NULL AS changed_acl "
5750 						  "FROM pg_class c "
5751 						  "LEFT JOIN pg_depend d ON "
5752 						  "(c.relkind = '%c' AND "
5753 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
5754 						  "d.objsubid = 0 AND "
5755 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
5756 					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5757 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
5758 						  "ORDER BY c.oid",
5759 						  username_subquery,
5760 						  RELKIND_SEQUENCE,
5761 						  RELKIND_RELATION, RELKIND_SEQUENCE,
5762 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
5763 	}
5764 	else if (fout->remoteVersion >= 80400)
5765 	{
5766 		/*
5767 		 * Left join to pick up dependency info linking sequences to their
5768 		 * owning column, if any (note this dependency is AUTO as of 8.2)
5769 		 */
5770 		appendPQExpBuffer(query,
5771 						  "SELECT c.tableoid, c.oid, c.relname, "
5772 						  "c.relacl, NULL as rrelacl, "
5773 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5774 						  "c.relkind, "
5775 						  "c.relnamespace, "
5776 						  "(%s c.relowner) AS rolname, "
5777 						  "c.relchecks, c.relhastriggers, "
5778 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
5779 						  "'f'::bool AS relrowsecurity, "
5780 						  "'f'::bool AS relforcerowsecurity, "
5781 						  "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
5782 						  "tc.relfrozenxid AS tfrozenxid, "
5783 						  "0 AS tminmxid, "
5784 						  "'p' AS relpersistence, 't' as relispopulated, "
5785 						  "'d' AS relreplident, c.relpages, "
5786 						  "NULL AS reloftype, "
5787 						  "d.refobjid AS owning_tab, "
5788 						  "d.refobjsubid AS owning_col, "
5789 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5790 						  "c.reloptions AS reloptions, "
5791 						  "tc.reloptions AS toast_reloptions, "
5792 						  "NULL AS changed_acl "
5793 						  "FROM pg_class c "
5794 						  "LEFT JOIN pg_depend d ON "
5795 						  "(c.relkind = '%c' AND "
5796 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
5797 						  "d.objsubid = 0 AND "
5798 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
5799 					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5800 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
5801 						  "ORDER BY c.oid",
5802 						  username_subquery,
5803 						  RELKIND_SEQUENCE,
5804 						  RELKIND_RELATION, RELKIND_SEQUENCE,
5805 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
5806 	}
5807 	else if (fout->remoteVersion >= 80200)
5808 	{
5809 		/*
5810 		 * Left join to pick up dependency info linking sequences to their
5811 		 * owning column, if any (note this dependency is AUTO as of 8.2)
5812 		 */
5813 		appendPQExpBuffer(query,
5814 						  "SELECT c.tableoid, c.oid, c.relname, "
5815 						  "c.relacl, NULL as rrelacl, "
5816 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5817 						  "c.relkind, "
5818 						  "c.relnamespace, "
5819 						  "(%s c.relowner) AS rolname, "
5820 					  "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
5821 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
5822 						  "'f'::bool AS relrowsecurity, "
5823 						  "'f'::bool AS relforcerowsecurity, "
5824 						  "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
5825 						  "tc.relfrozenxid AS tfrozenxid, "
5826 						  "0 AS tminmxid, "
5827 						  "'p' AS relpersistence, 't' as relispopulated, "
5828 						  "'d' AS relreplident, c.relpages, "
5829 						  "NULL AS reloftype, "
5830 						  "d.refobjid AS owning_tab, "
5831 						  "d.refobjsubid AS owning_col, "
5832 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5833 						  "c.reloptions AS reloptions, "
5834 						  "NULL AS toast_reloptions, "
5835 						  "NULL AS changed_acl "
5836 						  "FROM pg_class c "
5837 						  "LEFT JOIN pg_depend d ON "
5838 						  "(c.relkind = '%c' AND "
5839 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
5840 						  "d.objsubid = 0 AND "
5841 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
5842 					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5843 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
5844 						  "ORDER BY c.oid",
5845 						  username_subquery,
5846 						  RELKIND_SEQUENCE,
5847 						  RELKIND_RELATION, RELKIND_SEQUENCE,
5848 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
5849 	}
5850 	else if (fout->remoteVersion >= 80000)
5851 	{
5852 		/*
5853 		 * Left join to pick up dependency info linking sequences to their
5854 		 * owning column, if any
5855 		 */
5856 		appendPQExpBuffer(query,
5857 						  "SELECT c.tableoid, c.oid, relname, "
5858 						  "relacl, NULL as rrelacl, "
5859 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5860 						  "relkind, relnamespace, "
5861 						  "(%s relowner) AS rolname, "
5862 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
5863 						  "relhasindex, relhasrules, relhasoids, "
5864 						  "'f'::bool AS relrowsecurity, "
5865 						  "'f'::bool AS relforcerowsecurity, "
5866 						  "0 AS relfrozenxid, 0 AS relminmxid,"
5867 						  "0 AS toid, "
5868 						  "0 AS tfrozenxid, 0 AS tminmxid,"
5869 						  "'p' AS relpersistence, 't' as relispopulated, "
5870 						  "'d' AS relreplident, relpages, "
5871 						  "NULL AS reloftype, "
5872 						  "d.refobjid AS owning_tab, "
5873 						  "d.refobjsubid AS owning_col, "
5874 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5875 						  "NULL AS reloptions, "
5876 						  "NULL AS toast_reloptions, "
5877 						  "NULL AS changed_acl "
5878 						  "FROM pg_class c "
5879 						  "LEFT JOIN pg_depend d ON "
5880 						  "(c.relkind = '%c' AND "
5881 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
5882 						  "d.objsubid = 0 AND "
5883 						  "d.refclassid = c.tableoid AND d.deptype = 'i') "
5884 						  "WHERE relkind in ('%c', '%c', '%c', '%c') "
5885 						  "ORDER BY c.oid",
5886 						  username_subquery,
5887 						  RELKIND_SEQUENCE,
5888 						  RELKIND_RELATION, RELKIND_SEQUENCE,
5889 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
5890 	}
5891 	else if (fout->remoteVersion >= 70300)
5892 	{
5893 		/*
5894 		 * Left join to pick up dependency info linking sequences to their
5895 		 * owning column, if any
5896 		 */
5897 		appendPQExpBuffer(query,
5898 						  "SELECT c.tableoid, c.oid, relname, "
5899 						  "relacl, NULL as rrelacl, "
5900 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5901 						  "relkind, relnamespace, "
5902 						  "(%s relowner) AS rolname, "
5903 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
5904 						  "relhasindex, relhasrules, relhasoids, "
5905 						  "'f'::bool AS relrowsecurity, "
5906 						  "'f'::bool AS relforcerowsecurity, "
5907 						  "0 AS relfrozenxid, 0 AS relminmxid,"
5908 						  "0 AS toid, "
5909 						  "0 AS tfrozenxid, 0 AS tminmxid,"
5910 						  "'p' AS relpersistence, 't' as relispopulated, "
5911 						  "'d' AS relreplident, relpages, "
5912 						  "NULL AS reloftype, "
5913 						  "d.refobjid AS owning_tab, "
5914 						  "d.refobjsubid AS owning_col, "
5915 						  "NULL AS reltablespace, "
5916 						  "NULL AS reloptions, "
5917 						  "NULL AS toast_reloptions, "
5918 						  "NULL AS changed_acl "
5919 						  "FROM pg_class c "
5920 						  "LEFT JOIN pg_depend d ON "
5921 						  "(c.relkind = '%c' AND "
5922 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
5923 						  "d.objsubid = 0 AND "
5924 						  "d.refclassid = c.tableoid AND d.deptype = 'i') "
5925 						  "WHERE relkind IN ('%c', '%c', '%c', '%c') "
5926 						  "ORDER BY c.oid",
5927 						  username_subquery,
5928 						  RELKIND_SEQUENCE,
5929 						  RELKIND_RELATION, RELKIND_SEQUENCE,
5930 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
5931 	}
5932 	else if (fout->remoteVersion >= 70200)
5933 	{
5934 		appendPQExpBuffer(query,
5935 						  "SELECT tableoid, oid, relname, relacl, "
5936 						  "NULL as rrelacl, "
5937 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5938 						  "relkind, "
5939 						  "0::oid AS relnamespace, "
5940 						  "(%s relowner) AS rolname, "
5941 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
5942 						  "relhasindex, relhasrules, relhasoids, "
5943 						  "'f'::bool AS relrowsecurity, "
5944 						  "'f'::bool AS relforcerowsecurity, "
5945 						  "0 AS relfrozenxid, 0 AS relminmxid,"
5946 						  "0 AS toid, "
5947 						  "0 AS tfrozenxid, 0 AS tminmxid,"
5948 						  "'p' AS relpersistence, 't' as relispopulated, "
5949 						  "'d' AS relreplident, relpages, "
5950 						  "NULL AS reloftype, "
5951 						  "NULL::oid AS owning_tab, "
5952 						  "NULL::int4 AS owning_col, "
5953 						  "NULL AS reltablespace, "
5954 						  "NULL AS reloptions, "
5955 						  "NULL AS toast_reloptions, "
5956 						  "NULL AS changed_acl "
5957 						  "FROM pg_class "
5958 						  "WHERE relkind IN ('%c', '%c', '%c') "
5959 						  "ORDER BY oid",
5960 						  username_subquery,
5961 						  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
5962 	}
5963 	else if (fout->remoteVersion >= 70100)
5964 	{
5965 		/* all tables have oids in 7.1 */
5966 		appendPQExpBuffer(query,
5967 						  "SELECT tableoid, oid, relname, relacl, "
5968 						  "NULL as rrelacl, "
5969 						  "NULL AS initrelacl, NULL AS initrrelacl, "
5970 						  "relkind, "
5971 						  "0::oid AS relnamespace, "
5972 						  "(%s relowner) AS rolname, "
5973 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
5974 						  "relhasindex, relhasrules, "
5975 						  "'t'::bool AS relhasoids, "
5976 						  "'f'::bool AS relrowsecurity, "
5977 						  "'f'::bool AS relforcerowsecurity, "
5978 						  "0 AS relfrozenxid, 0 AS relminmxid,"
5979 						  "0 AS toid, "
5980 						  "0 AS tfrozenxid, 0 AS tminmxid,"
5981 						  "'p' AS relpersistence, 't' as relispopulated, "
5982 						  "'d' AS relreplident, relpages, "
5983 						  "NULL AS reloftype, "
5984 						  "NULL::oid AS owning_tab, "
5985 						  "NULL::int4 AS owning_col, "
5986 						  "NULL AS reltablespace, "
5987 						  "NULL AS reloptions, "
5988 						  "NULL AS toast_reloptions, "
5989 						  "NULL AS changed_acl "
5990 						  "FROM pg_class "
5991 						  "WHERE relkind IN ('%c', '%c', '%c') "
5992 						  "ORDER BY oid",
5993 						  username_subquery,
5994 						  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
5995 	}
5996 	else
5997 	{
5998 		/*
5999 		 * Before 7.1, view relkind was not set to 'v', so we must check if we
6000 		 * have a view by looking for a rule in pg_rewrite.
6001 		 */
6002 		appendPQExpBuffer(query,
6003 						  "SELECT "
6004 		"(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
6005 						  "oid, relname, relacl, NULL as rrelacl, "
6006 						  "NULL AS initrelacl, NULL AS initrrelacl, "
6007 						  "CASE WHEN relhasrules and relkind = 'r' "
6008 					  "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
6009 					  "             r.ev_class = c.oid AND r.ev_type = '1') "
6010 						  "THEN '%c'::\"char\" "
6011 						  "ELSE relkind END AS relkind,"
6012 						  "0::oid AS relnamespace, "
6013 						  "(%s relowner) AS rolname, "
6014 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
6015 						  "relhasindex, relhasrules, "
6016 						  "'t'::bool AS relhasoids, "
6017 						  "'f'::bool AS relrowsecurity, "
6018 						  "'f'::bool AS relforcerowsecurity, "
6019 						  "0 AS relfrozenxid, 0 AS relminmxid,"
6020 						  "0 AS toid, "
6021 						  "0 AS tfrozenxid, 0 AS tminmxid,"
6022 						  "'p' AS relpersistence, 't' as relispopulated, "
6023 						  "'d' AS relreplident, 0 AS relpages, "
6024 						  "NULL AS reloftype, "
6025 						  "NULL::oid AS owning_tab, "
6026 						  "NULL::int4 AS owning_col, "
6027 						  "NULL AS reltablespace, "
6028 						  "NULL AS reloptions, "
6029 						  "NULL AS toast_reloptions, "
6030 						  "NULL AS changed_acl "
6031 						  "FROM pg_class c "
6032 						  "WHERE relkind IN ('%c', '%c') "
6033 						  "ORDER BY oid",
6034 						  RELKIND_VIEW,
6035 						  username_subquery,
6036 						  RELKIND_RELATION, RELKIND_SEQUENCE);
6037 	}
6038 
6039 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6040 
6041 	ntups = PQntuples(res);
6042 
6043 	*numTables = ntups;
6044 
6045 	/*
6046 	 * Extract data from result and lock dumpable tables.  We do the locking
6047 	 * before anything else, to minimize the window wherein a table could
6048 	 * disappear under us.
6049 	 *
6050 	 * Note that we have to save info about all tables here, even when dumping
6051 	 * only one, because we don't yet know which tables might be inheritance
6052 	 * ancestors of the target table.
6053 	 */
6054 	tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6055 
6056 	i_reltableoid = PQfnumber(res, "tableoid");
6057 	i_reloid = PQfnumber(res, "oid");
6058 	i_relname = PQfnumber(res, "relname");
6059 	i_relnamespace = PQfnumber(res, "relnamespace");
6060 	i_relacl = PQfnumber(res, "relacl");
6061 	i_rrelacl = PQfnumber(res, "rrelacl");
6062 	i_initrelacl = PQfnumber(res, "initrelacl");
6063 	i_initrrelacl = PQfnumber(res, "initrrelacl");
6064 	i_relkind = PQfnumber(res, "relkind");
6065 	i_rolname = PQfnumber(res, "rolname");
6066 	i_relchecks = PQfnumber(res, "relchecks");
6067 	i_relhastriggers = PQfnumber(res, "relhastriggers");
6068 	i_relhasindex = PQfnumber(res, "relhasindex");
6069 	i_relhasrules = PQfnumber(res, "relhasrules");
6070 	i_relrowsec = PQfnumber(res, "relrowsecurity");
6071 	i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6072 	i_relhasoids = PQfnumber(res, "relhasoids");
6073 	i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6074 	i_relminmxid = PQfnumber(res, "relminmxid");
6075 	i_toastoid = PQfnumber(res, "toid");
6076 	i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6077 	i_toastminmxid = PQfnumber(res, "tminmxid");
6078 	i_relpersistence = PQfnumber(res, "relpersistence");
6079 	i_relispopulated = PQfnumber(res, "relispopulated");
6080 	i_relreplident = PQfnumber(res, "relreplident");
6081 	i_relpages = PQfnumber(res, "relpages");
6082 	i_owning_tab = PQfnumber(res, "owning_tab");
6083 	i_owning_col = PQfnumber(res, "owning_col");
6084 	i_reltablespace = PQfnumber(res, "reltablespace");
6085 	i_reloptions = PQfnumber(res, "reloptions");
6086 	i_checkoption = PQfnumber(res, "checkoption");
6087 	i_toastreloptions = PQfnumber(res, "toast_reloptions");
6088 	i_reloftype = PQfnumber(res, "reloftype");
6089 	i_changed_acl = PQfnumber(res, "changed_acl");
6090 
6091 	if (dopt->lockWaitTimeout && fout->remoteVersion >= 70300)
6092 	{
6093 		/*
6094 		 * Arrange to fail instead of waiting forever for a table lock.
6095 		 *
6096 		 * NB: this coding assumes that the only queries issued within the
6097 		 * following loop are LOCK TABLEs; else the timeout may be undesirably
6098 		 * applied to other things too.
6099 		 */
6100 		resetPQExpBuffer(query);
6101 		appendPQExpBufferStr(query, "SET statement_timeout = ");
6102 		appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6103 		ExecuteSqlStatement(fout, query->data);
6104 	}
6105 
6106 	for (i = 0; i < ntups; i++)
6107 	{
6108 		tblinfo[i].dobj.objType = DO_TABLE;
6109 		tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6110 		tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6111 		AssignDumpId(&tblinfo[i].dobj);
6112 		tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6113 		tblinfo[i].dobj.namespace =
6114 			findNamespace(fout,
6115 						  atooid(PQgetvalue(res, i, i_relnamespace)),
6116 						  tblinfo[i].dobj.catId.oid);
6117 		tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6118 		tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6119 		tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6120 		tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6121 		tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6122 		tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6123 		tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6124 		tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6125 		tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6126 		tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6127 		tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6128 		tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6129 		tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6130 		tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6131 		tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6132 		tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6133 		tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6134 		tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6135 		tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6136 		tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6137 		tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6138 		if (PQgetisnull(res, i, i_reloftype))
6139 			tblinfo[i].reloftype = NULL;
6140 		else
6141 			tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6142 		tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6143 		if (PQgetisnull(res, i, i_owning_tab))
6144 		{
6145 			tblinfo[i].owning_tab = InvalidOid;
6146 			tblinfo[i].owning_col = 0;
6147 		}
6148 		else
6149 		{
6150 			tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6151 			tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6152 		}
6153 		tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6154 		tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6155 		if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6156 			tblinfo[i].checkoption = NULL;
6157 		else
6158 			tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6159 		tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6160 
6161 		/* other fields were zeroed above */
6162 
6163 		/*
6164 		 * Decide whether we want to dump this table.
6165 		 */
6166 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6167 			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6168 		else
6169 			selectDumpableTable(&tblinfo[i], fout);
6170 
6171 		/*
6172 		 * If the table-level and all column-level ACLs for this table are
6173 		 * unchanged, then we don't need to worry about including the ACLs for
6174 		 * this table.  If any column-level ACLs have been changed, the
6175 		 * 'changed_acl' column from the query will indicate that.
6176 		 *
6177 		 * This can result in a significant performance improvement in cases
6178 		 * where we are only looking to dump out the ACL (eg: pg_catalog).
6179 		 */
6180 		if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6181 			PQgetisnull(res, i, i_initrelacl) &&
6182 			PQgetisnull(res, i, i_initrrelacl) &&
6183 			strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6184 			tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6185 
6186 		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6187 		tblinfo[i].dummy_view = false;	/* might get set during sort */
6188 		tblinfo[i].postponed_def = false;		/* might get set during sort */
6189 
6190 		/*
6191 		 * Read-lock target tables to make sure they aren't DROPPED or altered
6192 		 * in schema before we get around to dumping them.
6193 		 *
6194 		 * Note that we don't explicitly lock parents of the target tables; we
6195 		 * assume our lock on the child is enough to prevent schema
6196 		 * alterations to parent tables.
6197 		 *
6198 		 * NOTE: it'd be kinda nice to lock other relations too, not only
6199 		 * plain tables, but the backend doesn't presently allow that.
6200 		 *
6201 		 * We only need to lock the table for certain components; see
6202 		 * pg_dump.h
6203 		 */
6204 		if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION &&
6205 			(tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6206 		{
6207 			resetPQExpBuffer(query);
6208 			appendPQExpBuffer(query,
6209 							  "LOCK TABLE %s IN ACCESS SHARE MODE",
6210 							  fmtQualifiedDumpable(&tblinfo[i]));
6211 			ExecuteSqlStatement(fout, query->data);
6212 		}
6213 
6214 		/* Emit notice if join for owner failed */
6215 		if (strlen(tblinfo[i].rolname) == 0)
6216 			write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
6217 					  tblinfo[i].dobj.name);
6218 	}
6219 
6220 	if (dopt->lockWaitTimeout && fout->remoteVersion >= 70300)
6221 	{
6222 		ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6223 	}
6224 
6225 	PQclear(res);
6226 
6227 	destroyPQExpBuffer(query);
6228 
6229 	return tblinfo;
6230 }
6231 
6232 /*
6233  * getOwnedSeqs
6234  *	  identify owned sequences and mark them as dumpable if owning table is
6235  *
6236  * We used to do this in getTables(), but it's better to do it after the
6237  * index used by findTableByOid() has been set up.
6238  */
6239 void
getOwnedSeqs(Archive * fout,TableInfo tblinfo[],int numTables)6240 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6241 {
6242 	int			i;
6243 
6244 	/*
6245 	 * Force sequences that are "owned" by table columns to be dumped whenever
6246 	 * their owning table is being dumped.
6247 	 */
6248 	for (i = 0; i < numTables; i++)
6249 	{
6250 		TableInfo  *seqinfo = &tblinfo[i];
6251 		TableInfo  *owning_tab;
6252 
6253 		if (!OidIsValid(seqinfo->owning_tab))
6254 			continue;			/* not an owned sequence */
6255 
6256 		owning_tab = findTableByOid(seqinfo->owning_tab);
6257 		if (owning_tab == NULL)
6258 			exit_horribly(NULL, "failed sanity check, parent table OID %u of sequence OID %u not found\n",
6259 						  seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6260 
6261 		/*
6262 		 * We need to dump the components that are being dumped for the table
6263 		 * and any components which the sequence is explicitly marked with.
6264 		 *
6265 		 * We can't simply use the set of components which are being dumped
6266 		 * for the table as the table might be in an extension (and only the
6267 		 * non-extension components, eg: ACLs if changed, security labels, and
6268 		 * policies, are being dumped) while the sequence is not (and
6269 		 * therefore the definition and other components should also be
6270 		 * dumped).
6271 		 *
6272 		 * If the sequence is part of the extension then it should be properly
6273 		 * marked by checkExtensionMembership() and this will be a no-op as
6274 		 * the table will be equivalently marked.
6275 		 */
6276 		seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6277 
6278 		if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6279 			seqinfo->interesting = true;
6280 	}
6281 }
6282 
6283 /*
6284  * getInherits
6285  *	  read all the inheritance information
6286  * from the system catalogs return them in the InhInfo* structure
6287  *
6288  * numInherits is set to the number of pairs read in
6289  */
6290 InhInfo *
getInherits(Archive * fout,int * numInherits)6291 getInherits(Archive *fout, int *numInherits)
6292 {
6293 	PGresult   *res;
6294 	int			ntups;
6295 	int			i;
6296 	PQExpBuffer query = createPQExpBuffer();
6297 	InhInfo    *inhinfo;
6298 	int			i_inhrelid;
6299 	int			i_inhparent;
6300 
6301 	/* find all the inheritance information */
6302 
6303 	appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6304 
6305 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6306 
6307 	ntups = PQntuples(res);
6308 
6309 	*numInherits = ntups;
6310 
6311 	inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6312 
6313 	i_inhrelid = PQfnumber(res, "inhrelid");
6314 	i_inhparent = PQfnumber(res, "inhparent");
6315 
6316 	for (i = 0; i < ntups; i++)
6317 	{
6318 		inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6319 		inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6320 	}
6321 
6322 	PQclear(res);
6323 
6324 	destroyPQExpBuffer(query);
6325 
6326 	return inhinfo;
6327 }
6328 
6329 /*
6330  * getIndexes
6331  *	  get information about every index on a dumpable table
6332  *
6333  * Note: index data is not returned directly to the caller, but it
6334  * does get entered into the DumpableObject tables.
6335  */
6336 void
getIndexes(Archive * fout,TableInfo tblinfo[],int numTables)6337 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6338 {
6339 	int			i,
6340 				j;
6341 	PQExpBuffer query = createPQExpBuffer();
6342 	PGresult   *res;
6343 	IndxInfo   *indxinfo;
6344 	ConstraintInfo *constrinfo;
6345 	int			i_tableoid,
6346 				i_oid,
6347 				i_indexname,
6348 				i_indexdef,
6349 				i_indnkeys,
6350 				i_indkey,
6351 				i_indisclustered,
6352 				i_indisreplident,
6353 				i_contype,
6354 				i_conname,
6355 				i_condeferrable,
6356 				i_condeferred,
6357 				i_contableoid,
6358 				i_conoid,
6359 				i_condef,
6360 				i_tablespace,
6361 				i_indreloptions,
6362 				i_relpages;
6363 	int			ntups;
6364 
6365 	for (i = 0; i < numTables; i++)
6366 	{
6367 		TableInfo  *tbinfo = &tblinfo[i];
6368 
6369 		/* Only plain tables and materialized views have indexes. */
6370 		if (tbinfo->relkind != RELKIND_RELATION &&
6371 			tbinfo->relkind != RELKIND_MATVIEW)
6372 			continue;
6373 		if (!tbinfo->hasindex)
6374 			continue;
6375 
6376 		/* Ignore indexes of tables whose definitions are not to be dumped */
6377 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
6378 			continue;
6379 
6380 		if (g_verbose)
6381 			write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
6382 					  tbinfo->dobj.namespace->dobj.name,
6383 					  tbinfo->dobj.name);
6384 
6385 		/*
6386 		 * The point of the messy-looking outer join is to find a constraint
6387 		 * that is related by an internal dependency link to the index. If we
6388 		 * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6389 		 * assume an index won't have more than one internal dependency.
6390 		 *
6391 		 * As of 9.0 we don't need to look at pg_depend but can check for a
6392 		 * match to pg_constraint.conindid.  The check on conrelid is
6393 		 * redundant but useful because that column is indexed while conindid
6394 		 * is not.
6395 		 */
6396 		resetPQExpBuffer(query);
6397 		if (fout->remoteVersion >= 90400)
6398 		{
6399 			/*
6400 			 * the test on indisready is necessary in 9.2, and harmless in
6401 			 * earlier/later versions
6402 			 */
6403 			appendPQExpBuffer(query,
6404 							  "SELECT t.tableoid, t.oid, "
6405 							  "t.relname AS indexname, "
6406 					 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6407 							  "t.relnatts AS indnkeys, "
6408 							  "i.indkey, i.indisclustered, "
6409 							  "i.indisreplident, t.relpages, "
6410 							  "c.contype, c.conname, "
6411 							  "c.condeferrable, c.condeferred, "
6412 							  "c.tableoid AS contableoid, "
6413 							  "c.oid AS conoid, "
6414 				  "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6415 							  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6416 							  "t.reloptions AS indreloptions "
6417 							  "FROM pg_catalog.pg_index i "
6418 					  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6419 							  "LEFT JOIN pg_catalog.pg_constraint c "
6420 							  "ON (i.indrelid = c.conrelid AND "
6421 							  "i.indexrelid = c.conindid AND "
6422 							  "c.contype IN ('p','u','x')) "
6423 							  "WHERE i.indrelid = '%u'::pg_catalog.oid "
6424 							  "AND i.indisvalid AND i.indisready "
6425 							  "ORDER BY indexname",
6426 							  tbinfo->dobj.catId.oid);
6427 		}
6428 		else if (fout->remoteVersion >= 90000)
6429 		{
6430 			/*
6431 			 * the test on indisready is necessary in 9.2, and harmless in
6432 			 * earlier/later versions
6433 			 */
6434 			appendPQExpBuffer(query,
6435 							  "SELECT t.tableoid, t.oid, "
6436 							  "t.relname AS indexname, "
6437 					 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6438 							  "t.relnatts AS indnkeys, "
6439 							  "i.indkey, i.indisclustered, "
6440 							  "false AS indisreplident, t.relpages, "
6441 							  "c.contype, c.conname, "
6442 							  "c.condeferrable, c.condeferred, "
6443 							  "c.tableoid AS contableoid, "
6444 							  "c.oid AS conoid, "
6445 				  "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6446 							  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6447 							  "t.reloptions AS indreloptions "
6448 							  "FROM pg_catalog.pg_index i "
6449 					  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6450 							  "LEFT JOIN pg_catalog.pg_constraint c "
6451 							  "ON (i.indrelid = c.conrelid AND "
6452 							  "i.indexrelid = c.conindid AND "
6453 							  "c.contype IN ('p','u','x')) "
6454 							  "WHERE i.indrelid = '%u'::pg_catalog.oid "
6455 							  "AND i.indisvalid AND i.indisready "
6456 							  "ORDER BY indexname",
6457 							  tbinfo->dobj.catId.oid);
6458 		}
6459 		else if (fout->remoteVersion >= 80200)
6460 		{
6461 			appendPQExpBuffer(query,
6462 							  "SELECT t.tableoid, t.oid, "
6463 							  "t.relname AS indexname, "
6464 					 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6465 							  "t.relnatts AS indnkeys, "
6466 							  "i.indkey, i.indisclustered, "
6467 							  "false AS indisreplident, t.relpages, "
6468 							  "c.contype, c.conname, "
6469 							  "c.condeferrable, c.condeferred, "
6470 							  "c.tableoid AS contableoid, "
6471 							  "c.oid AS conoid, "
6472 							  "null AS condef, "
6473 							  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6474 							  "t.reloptions AS indreloptions "
6475 							  "FROM pg_catalog.pg_index i "
6476 					  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6477 							  "LEFT JOIN pg_catalog.pg_depend d "
6478 							  "ON (d.classid = t.tableoid "
6479 							  "AND d.objid = t.oid "
6480 							  "AND d.deptype = 'i') "
6481 							  "LEFT JOIN pg_catalog.pg_constraint c "
6482 							  "ON (d.refclassid = c.tableoid "
6483 							  "AND d.refobjid = c.oid) "
6484 							  "WHERE i.indrelid = '%u'::pg_catalog.oid "
6485 							  "AND i.indisvalid "
6486 							  "ORDER BY indexname",
6487 							  tbinfo->dobj.catId.oid);
6488 		}
6489 		else if (fout->remoteVersion >= 80000)
6490 		{
6491 			appendPQExpBuffer(query,
6492 							  "SELECT t.tableoid, t.oid, "
6493 							  "t.relname AS indexname, "
6494 					 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6495 							  "t.relnatts AS indnkeys, "
6496 							  "i.indkey, i.indisclustered, "
6497 							  "false AS indisreplident, t.relpages, "
6498 							  "c.contype, c.conname, "
6499 							  "c.condeferrable, c.condeferred, "
6500 							  "c.tableoid AS contableoid, "
6501 							  "c.oid AS conoid, "
6502 							  "null AS condef, "
6503 							  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6504 							  "null AS indreloptions "
6505 							  "FROM pg_catalog.pg_index i "
6506 					  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6507 							  "LEFT JOIN pg_catalog.pg_depend d "
6508 							  "ON (d.classid = t.tableoid "
6509 							  "AND d.objid = t.oid "
6510 							  "AND d.deptype = 'i') "
6511 							  "LEFT JOIN pg_catalog.pg_constraint c "
6512 							  "ON (d.refclassid = c.tableoid "
6513 							  "AND d.refobjid = c.oid) "
6514 							  "WHERE i.indrelid = '%u'::pg_catalog.oid "
6515 							  "ORDER BY indexname",
6516 							  tbinfo->dobj.catId.oid);
6517 		}
6518 		else if (fout->remoteVersion >= 70300)
6519 		{
6520 			appendPQExpBuffer(query,
6521 							  "SELECT t.tableoid, t.oid, "
6522 							  "t.relname AS indexname, "
6523 					 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6524 							  "t.relnatts AS indnkeys, "
6525 							  "i.indkey, i.indisclustered, "
6526 							  "false AS indisreplident, t.relpages, "
6527 							  "c.contype, c.conname, "
6528 							  "c.condeferrable, c.condeferred, "
6529 							  "c.tableoid AS contableoid, "
6530 							  "c.oid AS conoid, "
6531 							  "null AS condef, "
6532 							  "NULL AS tablespace, "
6533 							  "null AS indreloptions "
6534 							  "FROM pg_catalog.pg_index i "
6535 					  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6536 							  "LEFT JOIN pg_catalog.pg_depend d "
6537 							  "ON (d.classid = t.tableoid "
6538 							  "AND d.objid = t.oid "
6539 							  "AND d.deptype = 'i') "
6540 							  "LEFT JOIN pg_catalog.pg_constraint c "
6541 							  "ON (d.refclassid = c.tableoid "
6542 							  "AND d.refobjid = c.oid) "
6543 							  "WHERE i.indrelid = '%u'::pg_catalog.oid "
6544 							  "ORDER BY indexname",
6545 							  tbinfo->dobj.catId.oid);
6546 		}
6547 		else if (fout->remoteVersion >= 70100)
6548 		{
6549 			appendPQExpBuffer(query,
6550 							  "SELECT t.tableoid, t.oid, "
6551 							  "t.relname AS indexname, "
6552 							  "pg_get_indexdef(i.indexrelid) AS indexdef, "
6553 							  "t.relnatts AS indnkeys, "
6554 							  "i.indkey, false AS indisclustered, "
6555 							  "false AS indisreplident, t.relpages, "
6556 							  "CASE WHEN i.indisprimary THEN 'p'::char "
6557 							  "ELSE '0'::char END AS contype, "
6558 							  "t.relname AS conname, "
6559 							  "false AS condeferrable, "
6560 							  "false AS condeferred, "
6561 							  "0::oid AS contableoid, "
6562 							  "t.oid AS conoid, "
6563 							  "null AS condef, "
6564 							  "NULL AS tablespace, "
6565 							  "null AS indreloptions "
6566 							  "FROM pg_index i, pg_class t "
6567 							  "WHERE t.oid = i.indexrelid "
6568 							  "AND i.indrelid = '%u'::oid "
6569 							  "ORDER BY indexname",
6570 							  tbinfo->dobj.catId.oid);
6571 		}
6572 		else
6573 		{
6574 			appendPQExpBuffer(query,
6575 							  "SELECT "
6576 							  "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
6577 							  "t.oid, "
6578 							  "t.relname AS indexname, "
6579 							  "pg_get_indexdef(i.indexrelid) AS indexdef, "
6580 							  "t.relnatts AS indnkeys, "
6581 							  "i.indkey, false AS indisclustered, "
6582 							  "false AS indisreplident, t.relpages, "
6583 							  "CASE WHEN i.indisprimary THEN 'p'::char "
6584 							  "ELSE '0'::char END AS contype, "
6585 							  "t.relname AS conname, "
6586 							  "false AS condeferrable, "
6587 							  "false AS condeferred, "
6588 							  "0::oid AS contableoid, "
6589 							  "t.oid AS conoid, "
6590 							  "null AS condef, "
6591 							  "NULL AS tablespace, "
6592 							  "null AS indreloptions "
6593 							  "FROM pg_index i, pg_class t "
6594 							  "WHERE t.oid = i.indexrelid "
6595 							  "AND i.indrelid = '%u'::oid "
6596 							  "ORDER BY indexname",
6597 							  tbinfo->dobj.catId.oid);
6598 		}
6599 
6600 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6601 
6602 		ntups = PQntuples(res);
6603 
6604 		i_tableoid = PQfnumber(res, "tableoid");
6605 		i_oid = PQfnumber(res, "oid");
6606 		i_indexname = PQfnumber(res, "indexname");
6607 		i_indexdef = PQfnumber(res, "indexdef");
6608 		i_indnkeys = PQfnumber(res, "indnkeys");
6609 		i_indkey = PQfnumber(res, "indkey");
6610 		i_indisclustered = PQfnumber(res, "indisclustered");
6611 		i_indisreplident = PQfnumber(res, "indisreplident");
6612 		i_relpages = PQfnumber(res, "relpages");
6613 		i_contype = PQfnumber(res, "contype");
6614 		i_conname = PQfnumber(res, "conname");
6615 		i_condeferrable = PQfnumber(res, "condeferrable");
6616 		i_condeferred = PQfnumber(res, "condeferred");
6617 		i_contableoid = PQfnumber(res, "contableoid");
6618 		i_conoid = PQfnumber(res, "conoid");
6619 		i_condef = PQfnumber(res, "condef");
6620 		i_tablespace = PQfnumber(res, "tablespace");
6621 		i_indreloptions = PQfnumber(res, "indreloptions");
6622 
6623 		indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
6624 		constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
6625 
6626 		for (j = 0; j < ntups; j++)
6627 		{
6628 			char		contype;
6629 
6630 			indxinfo[j].dobj.objType = DO_INDEX;
6631 			indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
6632 			indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
6633 			AssignDumpId(&indxinfo[j].dobj);
6634 			indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
6635 			indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6636 			indxinfo[j].indextable = tbinfo;
6637 			indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
6638 			indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
6639 			indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
6640 			indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
6641 
6642 			/*
6643 			 * In pre-7.4 releases, indkeys may contain more entries than
6644 			 * indnkeys says (since indnkeys will be 1 for a functional
6645 			 * index).  We don't actually care about this case since we don't
6646 			 * examine indkeys except for indexes associated with PRIMARY and
6647 			 * UNIQUE constraints, which are never functional indexes. But we
6648 			 * have to allocate enough space to keep parseOidArray from
6649 			 * complaining.
6650 			 */
6651 			indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
6652 			parseOidArray(PQgetvalue(res, j, i_indkey),
6653 						  indxinfo[j].indkeys, INDEX_MAX_KEYS);
6654 			indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
6655 			indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
6656 			indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
6657 			contype = *(PQgetvalue(res, j, i_contype));
6658 
6659 			if (contype == 'p' || contype == 'u' || contype == 'x')
6660 			{
6661 				/*
6662 				 * If we found a constraint matching the index, create an
6663 				 * entry for it.
6664 				 *
6665 				 * In a pre-7.3 database, we take this path iff the index was
6666 				 * marked indisprimary.
6667 				 */
6668 				constrinfo[j].dobj.objType = DO_CONSTRAINT;
6669 				constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
6670 				constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
6671 				AssignDumpId(&constrinfo[j].dobj);
6672 				constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
6673 				constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6674 				constrinfo[j].contable = tbinfo;
6675 				constrinfo[j].condomain = NULL;
6676 				constrinfo[j].contype = contype;
6677 				if (contype == 'x')
6678 					constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
6679 				else
6680 					constrinfo[j].condef = NULL;
6681 				constrinfo[j].confrelid = InvalidOid;
6682 				constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
6683 				constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
6684 				constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
6685 				constrinfo[j].conislocal = true;
6686 				constrinfo[j].separate = true;
6687 
6688 				indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
6689 
6690 				/* If pre-7.3 DB, better make sure table comes first */
6691 				addObjectDependency(&constrinfo[j].dobj,
6692 									tbinfo->dobj.dumpId);
6693 			}
6694 			else
6695 			{
6696 				/* Plain secondary index */
6697 				indxinfo[j].indexconstraint = 0;
6698 			}
6699 		}
6700 
6701 		PQclear(res);
6702 	}
6703 
6704 	destroyPQExpBuffer(query);
6705 }
6706 
6707 /*
6708  * getConstraints
6709  *
6710  * Get info about constraints on dumpable tables.
6711  *
6712  * Currently handles foreign keys only.
6713  * Unique and primary key constraints are handled with indexes,
6714  * while check constraints are processed in getTableAttrs().
6715  */
6716 void
getConstraints(Archive * fout,TableInfo tblinfo[],int numTables)6717 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
6718 {
6719 	int			i,
6720 				j;
6721 	ConstraintInfo *constrinfo;
6722 	PQExpBuffer query;
6723 	PGresult   *res;
6724 	int			i_contableoid,
6725 				i_conoid,
6726 				i_conname,
6727 				i_confrelid,
6728 				i_condef;
6729 	int			ntups;
6730 
6731 	/* pg_constraint was created in 7.3, so nothing to do if older */
6732 	if (fout->remoteVersion < 70300)
6733 		return;
6734 
6735 	query = createPQExpBuffer();
6736 
6737 	for (i = 0; i < numTables; i++)
6738 	{
6739 		TableInfo  *tbinfo = &tblinfo[i];
6740 
6741 		if (!tbinfo->hastriggers ||
6742 			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
6743 			continue;
6744 
6745 		if (g_verbose)
6746 			write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
6747 					  tbinfo->dobj.namespace->dobj.name,
6748 					  tbinfo->dobj.name);
6749 
6750 		resetPQExpBuffer(query);
6751 		appendPQExpBuffer(query,
6752 						  "SELECT tableoid, oid, conname, confrelid, "
6753 						  "pg_catalog.pg_get_constraintdef(oid) AS condef "
6754 						  "FROM pg_catalog.pg_constraint "
6755 						  "WHERE conrelid = '%u'::pg_catalog.oid "
6756 						  "AND contype = 'f'",
6757 						  tbinfo->dobj.catId.oid);
6758 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6759 
6760 		ntups = PQntuples(res);
6761 
6762 		i_contableoid = PQfnumber(res, "tableoid");
6763 		i_conoid = PQfnumber(res, "oid");
6764 		i_conname = PQfnumber(res, "conname");
6765 		i_confrelid = PQfnumber(res, "confrelid");
6766 		i_condef = PQfnumber(res, "condef");
6767 
6768 		constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
6769 
6770 		for (j = 0; j < ntups; j++)
6771 		{
6772 			constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
6773 			constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
6774 			constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
6775 			AssignDumpId(&constrinfo[j].dobj);
6776 			constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
6777 			constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6778 			constrinfo[j].contable = tbinfo;
6779 			constrinfo[j].condomain = NULL;
6780 			constrinfo[j].contype = 'f';
6781 			constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
6782 			constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
6783 			constrinfo[j].conindex = 0;
6784 			constrinfo[j].condeferrable = false;
6785 			constrinfo[j].condeferred = false;
6786 			constrinfo[j].conislocal = true;
6787 			constrinfo[j].separate = true;
6788 		}
6789 
6790 		PQclear(res);
6791 	}
6792 
6793 	destroyPQExpBuffer(query);
6794 }
6795 
6796 /*
6797  * getDomainConstraints
6798  *
6799  * Get info about constraints on a domain.
6800  */
6801 static void
getDomainConstraints(Archive * fout,TypeInfo * tyinfo)6802 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
6803 {
6804 	int			i;
6805 	ConstraintInfo *constrinfo;
6806 	PQExpBuffer query;
6807 	PGresult   *res;
6808 	int			i_tableoid,
6809 				i_oid,
6810 				i_conname,
6811 				i_consrc;
6812 	int			ntups;
6813 
6814 	/* pg_constraint was created in 7.3, so nothing to do if older */
6815 	if (fout->remoteVersion < 70300)
6816 		return;
6817 
6818 	query = createPQExpBuffer();
6819 
6820 	if (fout->remoteVersion >= 90100)
6821 		appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
6822 						  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6823 						  "convalidated "
6824 						  "FROM pg_catalog.pg_constraint "
6825 						  "WHERE contypid = '%u'::pg_catalog.oid "
6826 						  "ORDER BY conname",
6827 						  tyinfo->dobj.catId.oid);
6828 
6829 	else if (fout->remoteVersion >= 70400)
6830 		appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
6831 						  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6832 						  "true as convalidated "
6833 						  "FROM pg_catalog.pg_constraint "
6834 						  "WHERE contypid = '%u'::pg_catalog.oid "
6835 						  "ORDER BY conname",
6836 						  tyinfo->dobj.catId.oid);
6837 	else
6838 		appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
6839 						  "'CHECK (' || consrc || ')' AS consrc, "
6840 						  "true as convalidated "
6841 						  "FROM pg_catalog.pg_constraint "
6842 						  "WHERE contypid = '%u'::pg_catalog.oid "
6843 						  "ORDER BY conname",
6844 						  tyinfo->dobj.catId.oid);
6845 
6846 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6847 
6848 	ntups = PQntuples(res);
6849 
6850 	i_tableoid = PQfnumber(res, "tableoid");
6851 	i_oid = PQfnumber(res, "oid");
6852 	i_conname = PQfnumber(res, "conname");
6853 	i_consrc = PQfnumber(res, "consrc");
6854 
6855 	constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
6856 
6857 	tyinfo->nDomChecks = ntups;
6858 	tyinfo->domChecks = constrinfo;
6859 
6860 	for (i = 0; i < ntups; i++)
6861 	{
6862 		bool		validated = PQgetvalue(res, i, 4)[0] == 't';
6863 
6864 		constrinfo[i].dobj.objType = DO_CONSTRAINT;
6865 		constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6866 		constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6867 		AssignDumpId(&constrinfo[i].dobj);
6868 		constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
6869 		constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
6870 		constrinfo[i].contable = NULL;
6871 		constrinfo[i].condomain = tyinfo;
6872 		constrinfo[i].contype = 'c';
6873 		constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
6874 		constrinfo[i].confrelid = InvalidOid;
6875 		constrinfo[i].conindex = 0;
6876 		constrinfo[i].condeferrable = false;
6877 		constrinfo[i].condeferred = false;
6878 		constrinfo[i].conislocal = true;
6879 
6880 		constrinfo[i].separate = !validated;
6881 
6882 		/*
6883 		 * Make the domain depend on the constraint, ensuring it won't be
6884 		 * output till any constraint dependencies are OK.  If the constraint
6885 		 * has not been validated, it's going to be dumped after the domain
6886 		 * anyway, so this doesn't matter.
6887 		 */
6888 		if (validated)
6889 			addObjectDependency(&tyinfo->dobj,
6890 								constrinfo[i].dobj.dumpId);
6891 	}
6892 
6893 	PQclear(res);
6894 
6895 	destroyPQExpBuffer(query);
6896 }
6897 
6898 /*
6899  * getRules
6900  *	  get basic information about every rule in the system
6901  *
6902  * numRules is set to the number of rules read in
6903  */
6904 RuleInfo *
getRules(Archive * fout,int * numRules)6905 getRules(Archive *fout, int *numRules)
6906 {
6907 	PGresult   *res;
6908 	int			ntups;
6909 	int			i;
6910 	PQExpBuffer query = createPQExpBuffer();
6911 	RuleInfo   *ruleinfo;
6912 	int			i_tableoid;
6913 	int			i_oid;
6914 	int			i_rulename;
6915 	int			i_ruletable;
6916 	int			i_ev_type;
6917 	int			i_is_instead;
6918 	int			i_ev_enabled;
6919 
6920 	if (fout->remoteVersion >= 80300)
6921 	{
6922 		appendPQExpBufferStr(query, "SELECT "
6923 							 "tableoid, oid, rulename, "
6924 							 "ev_class AS ruletable, ev_type, is_instead, "
6925 							 "ev_enabled "
6926 							 "FROM pg_rewrite "
6927 							 "ORDER BY oid");
6928 	}
6929 	else if (fout->remoteVersion >= 70100)
6930 	{
6931 		appendPQExpBufferStr(query, "SELECT "
6932 							 "tableoid, oid, rulename, "
6933 							 "ev_class AS ruletable, ev_type, is_instead, "
6934 							 "'O'::char AS ev_enabled "
6935 							 "FROM pg_rewrite "
6936 							 "ORDER BY oid");
6937 	}
6938 	else
6939 	{
6940 		appendPQExpBufferStr(query, "SELECT "
6941 							 "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
6942 							 "oid, rulename, "
6943 							 "ev_class AS ruletable, ev_type, is_instead, "
6944 							 "'O'::char AS ev_enabled "
6945 							 "FROM pg_rewrite "
6946 							 "ORDER BY oid");
6947 	}
6948 
6949 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6950 
6951 	ntups = PQntuples(res);
6952 
6953 	*numRules = ntups;
6954 
6955 	ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
6956 
6957 	i_tableoid = PQfnumber(res, "tableoid");
6958 	i_oid = PQfnumber(res, "oid");
6959 	i_rulename = PQfnumber(res, "rulename");
6960 	i_ruletable = PQfnumber(res, "ruletable");
6961 	i_ev_type = PQfnumber(res, "ev_type");
6962 	i_is_instead = PQfnumber(res, "is_instead");
6963 	i_ev_enabled = PQfnumber(res, "ev_enabled");
6964 
6965 	for (i = 0; i < ntups; i++)
6966 	{
6967 		Oid			ruletableoid;
6968 
6969 		ruleinfo[i].dobj.objType = DO_RULE;
6970 		ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6971 		ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6972 		AssignDumpId(&ruleinfo[i].dobj);
6973 		ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
6974 		ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
6975 		ruleinfo[i].ruletable = findTableByOid(ruletableoid);
6976 		if (ruleinfo[i].ruletable == NULL)
6977 			exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
6978 						  ruletableoid, ruleinfo[i].dobj.catId.oid);
6979 		ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
6980 		ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
6981 		ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
6982 		ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
6983 		ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
6984 		if (ruleinfo[i].ruletable)
6985 		{
6986 			/*
6987 			 * If the table is a view or materialized view, force its ON
6988 			 * SELECT rule to be sorted before the view itself --- this
6989 			 * ensures that any dependencies for the rule affect the table's
6990 			 * positioning. Other rules are forced to appear after their
6991 			 * table.
6992 			 */
6993 			if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
6994 				 ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
6995 				ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
6996 			{
6997 				addObjectDependency(&ruleinfo[i].ruletable->dobj,
6998 									ruleinfo[i].dobj.dumpId);
6999 				/* We'll merge the rule into CREATE VIEW, if possible */
7000 				ruleinfo[i].separate = false;
7001 			}
7002 			else
7003 			{
7004 				addObjectDependency(&ruleinfo[i].dobj,
7005 									ruleinfo[i].ruletable->dobj.dumpId);
7006 				ruleinfo[i].separate = true;
7007 			}
7008 		}
7009 		else
7010 			ruleinfo[i].separate = true;
7011 	}
7012 
7013 	PQclear(res);
7014 
7015 	destroyPQExpBuffer(query);
7016 
7017 	return ruleinfo;
7018 }
7019 
7020 /*
7021  * getTriggers
7022  *	  get information about every trigger on a dumpable table
7023  *
7024  * Note: trigger data is not returned directly to the caller, but it
7025  * does get entered into the DumpableObject tables.
7026  */
7027 void
getTriggers(Archive * fout,TableInfo tblinfo[],int numTables)7028 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7029 {
7030 	int			i,
7031 				j;
7032 	PQExpBuffer query = createPQExpBuffer();
7033 	PGresult   *res;
7034 	TriggerInfo *tginfo;
7035 	int			i_tableoid,
7036 				i_oid,
7037 				i_tgname,
7038 				i_tgfname,
7039 				i_tgtype,
7040 				i_tgnargs,
7041 				i_tgargs,
7042 				i_tgisconstraint,
7043 				i_tgconstrname,
7044 				i_tgconstrrelid,
7045 				i_tgconstrrelname,
7046 				i_tgenabled,
7047 				i_tgdeferrable,
7048 				i_tginitdeferred,
7049 				i_tgdef;
7050 	int			ntups;
7051 
7052 	for (i = 0; i < numTables; i++)
7053 	{
7054 		TableInfo  *tbinfo = &tblinfo[i];
7055 
7056 		if (!tbinfo->hastriggers ||
7057 			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7058 			continue;
7059 
7060 		if (g_verbose)
7061 			write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
7062 					  tbinfo->dobj.namespace->dobj.name,
7063 					  tbinfo->dobj.name);
7064 
7065 		resetPQExpBuffer(query);
7066 		if (fout->remoteVersion >= 90000)
7067 		{
7068 			/*
7069 			 * NB: think not to use pretty=true in pg_get_triggerdef.  It
7070 			 * could result in non-forward-compatible dumps of WHEN clauses
7071 			 * due to under-parenthesization.
7072 			 */
7073 			appendPQExpBuffer(query,
7074 							  "SELECT tgname, "
7075 							  "tgfoid::pg_catalog.regproc AS tgfname, "
7076 						"pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7077 							  "tgenabled, tableoid, oid "
7078 							  "FROM pg_catalog.pg_trigger t "
7079 							  "WHERE tgrelid = '%u'::pg_catalog.oid "
7080 							  "AND NOT tgisinternal",
7081 							  tbinfo->dobj.catId.oid);
7082 		}
7083 		else if (fout->remoteVersion >= 80300)
7084 		{
7085 			/*
7086 			 * We ignore triggers that are tied to a foreign-key constraint
7087 			 */
7088 			appendPQExpBuffer(query,
7089 							  "SELECT tgname, "
7090 							  "tgfoid::pg_catalog.regproc AS tgfname, "
7091 							  "tgtype, tgnargs, tgargs, tgenabled, "
7092 							  "tgisconstraint, tgconstrname, tgdeferrable, "
7093 							  "tgconstrrelid, tginitdeferred, tableoid, oid, "
7094 					 "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7095 							  "FROM pg_catalog.pg_trigger t "
7096 							  "WHERE tgrelid = '%u'::pg_catalog.oid "
7097 							  "AND tgconstraint = 0",
7098 							  tbinfo->dobj.catId.oid);
7099 		}
7100 		else if (fout->remoteVersion >= 70300)
7101 		{
7102 			/*
7103 			 * We ignore triggers that are tied to a foreign-key constraint,
7104 			 * but in these versions we have to grovel through pg_constraint
7105 			 * to find out
7106 			 */
7107 			appendPQExpBuffer(query,
7108 							  "SELECT tgname, "
7109 							  "tgfoid::pg_catalog.regproc AS tgfname, "
7110 							  "tgtype, tgnargs, tgargs, tgenabled, "
7111 							  "tgisconstraint, tgconstrname, tgdeferrable, "
7112 							  "tgconstrrelid, tginitdeferred, tableoid, oid, "
7113 					 "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7114 							  "FROM pg_catalog.pg_trigger t "
7115 							  "WHERE tgrelid = '%u'::pg_catalog.oid "
7116 							  "AND (NOT tgisconstraint "
7117 							  " OR NOT EXISTS"
7118 							  "  (SELECT 1 FROM pg_catalog.pg_depend d "
7119 							  "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7120 							  "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7121 							  tbinfo->dobj.catId.oid);
7122 		}
7123 		else if (fout->remoteVersion >= 70100)
7124 		{
7125 			appendPQExpBuffer(query,
7126 							  "SELECT tgname, tgfoid::regproc AS tgfname, "
7127 							  "tgtype, tgnargs, tgargs, tgenabled, "
7128 							  "tgisconstraint, tgconstrname, tgdeferrable, "
7129 							  "tgconstrrelid, tginitdeferred, tableoid, oid, "
7130 				  "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
7131 							  "		AS tgconstrrelname "
7132 							  "FROM pg_trigger "
7133 							  "WHERE tgrelid = '%u'::oid",
7134 							  tbinfo->dobj.catId.oid);
7135 		}
7136 		else
7137 		{
7138 			appendPQExpBuffer(query,
7139 							  "SELECT tgname, tgfoid::regproc AS tgfname, "
7140 							  "tgtype, tgnargs, tgargs, tgenabled, "
7141 							  "tgisconstraint, tgconstrname, tgdeferrable, "
7142 							  "tgconstrrelid, tginitdeferred, "
7143 							  "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
7144 							  "oid, "
7145 				  "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
7146 							  "		AS tgconstrrelname "
7147 							  "FROM pg_trigger "
7148 							  "WHERE tgrelid = '%u'::oid",
7149 							  tbinfo->dobj.catId.oid);
7150 		}
7151 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7152 
7153 		ntups = PQntuples(res);
7154 
7155 		i_tableoid = PQfnumber(res, "tableoid");
7156 		i_oid = PQfnumber(res, "oid");
7157 		i_tgname = PQfnumber(res, "tgname");
7158 		i_tgfname = PQfnumber(res, "tgfname");
7159 		i_tgtype = PQfnumber(res, "tgtype");
7160 		i_tgnargs = PQfnumber(res, "tgnargs");
7161 		i_tgargs = PQfnumber(res, "tgargs");
7162 		i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7163 		i_tgconstrname = PQfnumber(res, "tgconstrname");
7164 		i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7165 		i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7166 		i_tgenabled = PQfnumber(res, "tgenabled");
7167 		i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7168 		i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7169 		i_tgdef = PQfnumber(res, "tgdef");
7170 
7171 		tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7172 
7173 		tbinfo->numTriggers = ntups;
7174 		tbinfo->triggers = tginfo;
7175 
7176 		for (j = 0; j < ntups; j++)
7177 		{
7178 			tginfo[j].dobj.objType = DO_TRIGGER;
7179 			tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7180 			tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7181 			AssignDumpId(&tginfo[j].dobj);
7182 			tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7183 			tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7184 			tginfo[j].tgtable = tbinfo;
7185 			tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7186 			if (i_tgdef >= 0)
7187 			{
7188 				tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7189 
7190 				/* remaining fields are not valid if we have tgdef */
7191 				tginfo[j].tgfname = NULL;
7192 				tginfo[j].tgtype = 0;
7193 				tginfo[j].tgnargs = 0;
7194 				tginfo[j].tgargs = NULL;
7195 				tginfo[j].tgisconstraint = false;
7196 				tginfo[j].tgdeferrable = false;
7197 				tginfo[j].tginitdeferred = false;
7198 				tginfo[j].tgconstrname = NULL;
7199 				tginfo[j].tgconstrrelid = InvalidOid;
7200 				tginfo[j].tgconstrrelname = NULL;
7201 			}
7202 			else
7203 			{
7204 				tginfo[j].tgdef = NULL;
7205 
7206 				tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7207 				tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7208 				tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7209 				tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7210 				tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7211 				tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7212 				tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7213 
7214 				if (tginfo[j].tgisconstraint)
7215 				{
7216 					tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7217 					tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7218 					if (OidIsValid(tginfo[j].tgconstrrelid))
7219 					{
7220 						if (PQgetisnull(res, j, i_tgconstrrelname))
7221 							exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
7222 										  tginfo[j].dobj.name,
7223 										  tbinfo->dobj.name,
7224 										  tginfo[j].tgconstrrelid);
7225 						tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7226 					}
7227 					else
7228 						tginfo[j].tgconstrrelname = NULL;
7229 				}
7230 				else
7231 				{
7232 					tginfo[j].tgconstrname = NULL;
7233 					tginfo[j].tgconstrrelid = InvalidOid;
7234 					tginfo[j].tgconstrrelname = NULL;
7235 				}
7236 			}
7237 		}
7238 
7239 		PQclear(res);
7240 	}
7241 
7242 	destroyPQExpBuffer(query);
7243 }
7244 
7245 /*
7246  * getEventTriggers
7247  *	  get information about event triggers
7248  */
7249 EventTriggerInfo *
getEventTriggers(Archive * fout,int * numEventTriggers)7250 getEventTriggers(Archive *fout, int *numEventTriggers)
7251 {
7252 	int			i;
7253 	PQExpBuffer query;
7254 	PGresult   *res;
7255 	EventTriggerInfo *evtinfo;
7256 	int			i_tableoid,
7257 				i_oid,
7258 				i_evtname,
7259 				i_evtevent,
7260 				i_evtowner,
7261 				i_evttags,
7262 				i_evtfname,
7263 				i_evtenabled;
7264 	int			ntups;
7265 
7266 	/* Before 9.3, there are no event triggers */
7267 	if (fout->remoteVersion < 90300)
7268 	{
7269 		*numEventTriggers = 0;
7270 		return NULL;
7271 	}
7272 
7273 	query = createPQExpBuffer();
7274 
7275 	appendPQExpBuffer(query,
7276 					  "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7277 					  "evtevent, (%s evtowner) AS evtowner, "
7278 					  "array_to_string(array("
7279 					  "select quote_literal(x) "
7280 					  " from unnest(evttags) as t(x)), ', ') as evttags, "
7281 					  "e.evtfoid::regproc as evtfname "
7282 					  "FROM pg_event_trigger e "
7283 					  "ORDER BY e.oid",
7284 					  username_subquery);
7285 
7286 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7287 
7288 	ntups = PQntuples(res);
7289 
7290 	*numEventTriggers = ntups;
7291 
7292 	evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7293 
7294 	i_tableoid = PQfnumber(res, "tableoid");
7295 	i_oid = PQfnumber(res, "oid");
7296 	i_evtname = PQfnumber(res, "evtname");
7297 	i_evtevent = PQfnumber(res, "evtevent");
7298 	i_evtowner = PQfnumber(res, "evtowner");
7299 	i_evttags = PQfnumber(res, "evttags");
7300 	i_evtfname = PQfnumber(res, "evtfname");
7301 	i_evtenabled = PQfnumber(res, "evtenabled");
7302 
7303 	for (i = 0; i < ntups; i++)
7304 	{
7305 		evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7306 		evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7307 		evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7308 		AssignDumpId(&evtinfo[i].dobj);
7309 		evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7310 		evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7311 		evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7312 		evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7313 		evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7314 		evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7315 		evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7316 
7317 		/* Decide whether we want to dump it */
7318 		selectDumpableObject(&(evtinfo[i].dobj), fout);
7319 
7320 		/* Event Triggers do not currently have ACLs. */
7321 		evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7322 	}
7323 
7324 	PQclear(res);
7325 
7326 	destroyPQExpBuffer(query);
7327 
7328 	return evtinfo;
7329 }
7330 
7331 /*
7332  * getProcLangs
7333  *	  get basic information about every procedural language in the system
7334  *
7335  * numProcLangs is set to the number of langs read in
7336  *
7337  * NB: this must run after getFuncs() because we assume we can do
7338  * findFuncByOid().
7339  */
7340 ProcLangInfo *
getProcLangs(Archive * fout,int * numProcLangs)7341 getProcLangs(Archive *fout, int *numProcLangs)
7342 {
7343 	DumpOptions *dopt = fout->dopt;
7344 	PGresult   *res;
7345 	int			ntups;
7346 	int			i;
7347 	PQExpBuffer query = createPQExpBuffer();
7348 	ProcLangInfo *planginfo;
7349 	int			i_tableoid;
7350 	int			i_oid;
7351 	int			i_lanname;
7352 	int			i_lanpltrusted;
7353 	int			i_lanplcallfoid;
7354 	int			i_laninline;
7355 	int			i_lanvalidator;
7356 	int			i_lanacl;
7357 	int			i_rlanacl;
7358 	int			i_initlanacl;
7359 	int			i_initrlanacl;
7360 	int			i_lanowner;
7361 
7362 	if (fout->remoteVersion >= 90600)
7363 	{
7364 		PQExpBuffer acl_subquery = createPQExpBuffer();
7365 		PQExpBuffer racl_subquery = createPQExpBuffer();
7366 		PQExpBuffer initacl_subquery = createPQExpBuffer();
7367 		PQExpBuffer initracl_subquery = createPQExpBuffer();
7368 
7369 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7370 						initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7371 						dopt->binary_upgrade);
7372 
7373 		/* pg_language has a laninline column */
7374 		appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7375 						  "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7376 						  "l.laninline, l.lanvalidator, "
7377 						  "%s AS lanacl, "
7378 						  "%s AS rlanacl, "
7379 						  "%s AS initlanacl, "
7380 						  "%s AS initrlanacl, "
7381 						  "(%s l.lanowner) AS lanowner "
7382 						  "FROM pg_language l "
7383 						  "LEFT JOIN pg_init_privs pip ON "
7384 						  "(l.oid = pip.objoid "
7385 						  "AND pip.classoid = 'pg_language'::regclass "
7386 						  "AND pip.objsubid = 0) "
7387 						  "WHERE l.lanispl "
7388 						  "ORDER BY l.oid",
7389 						  acl_subquery->data,
7390 						  racl_subquery->data,
7391 						  initacl_subquery->data,
7392 						  initracl_subquery->data,
7393 						  username_subquery);
7394 
7395 		destroyPQExpBuffer(acl_subquery);
7396 		destroyPQExpBuffer(racl_subquery);
7397 		destroyPQExpBuffer(initacl_subquery);
7398 		destroyPQExpBuffer(initracl_subquery);
7399 	}
7400 	else if (fout->remoteVersion >= 90000)
7401 	{
7402 		/* pg_language has a laninline column */
7403 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
7404 						  "lanname, lanpltrusted, lanplcallfoid, "
7405 						  "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7406 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7407 						  "(%s lanowner) AS lanowner "
7408 						  "FROM pg_language "
7409 						  "WHERE lanispl "
7410 						  "ORDER BY oid",
7411 						  username_subquery);
7412 	}
7413 	else if (fout->remoteVersion >= 80300)
7414 	{
7415 		/* pg_language has a lanowner column */
7416 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
7417 						  "lanname, lanpltrusted, lanplcallfoid, "
7418 						  "0 AS laninline, lanvalidator, lanacl, "
7419 						  "NULL AS rlanacl, "
7420 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7421 						  "(%s lanowner) AS lanowner "
7422 						  "FROM pg_language "
7423 						  "WHERE lanispl "
7424 						  "ORDER BY oid",
7425 						  username_subquery);
7426 	}
7427 	else if (fout->remoteVersion >= 80100)
7428 	{
7429 		/* Languages are owned by the bootstrap superuser, OID 10 */
7430 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
7431 						  "lanname, lanpltrusted, lanplcallfoid, "
7432 						  "0 AS laninline, lanvalidator, lanacl, "
7433 						  "NULL AS rlanacl, "
7434 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7435 						  "(%s '10') AS lanowner "
7436 						  "FROM pg_language "
7437 						  "WHERE lanispl "
7438 						  "ORDER BY oid",
7439 						  username_subquery);
7440 	}
7441 	else if (fout->remoteVersion >= 70400)
7442 	{
7443 		/* Languages are owned by the bootstrap superuser, sysid 1 */
7444 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
7445 						  "lanname, lanpltrusted, lanplcallfoid, "
7446 						  "0 AS laninline, lanvalidator, lanacl, "
7447 						  "NULL AS rlanacl, "
7448 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7449 						  "(%s '1') AS lanowner "
7450 						  "FROM pg_language "
7451 						  "WHERE lanispl "
7452 						  "ORDER BY oid",
7453 						  username_subquery);
7454 	}
7455 	else if (fout->remoteVersion >= 70300)
7456 	{
7457 		/* No clear notion of an owner at all before 7.4 ... */
7458 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
7459 						  "lanname, lanpltrusted, lanplcallfoid, "
7460 						  "0 AS laninline, lanvalidator, lanacl, "
7461 						  "NULL AS rlanacl, "
7462 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7463 						  "NULL AS lanowner "
7464 						  "FROM pg_language "
7465 						  "WHERE lanispl "
7466 						  "ORDER BY oid");
7467 	}
7468 	else if (fout->remoteVersion >= 70100)
7469 	{
7470 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
7471 						  "lanname, lanpltrusted, lanplcallfoid, "
7472 						"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
7473 						  "NULL AS rlanacl, "
7474 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7475 						  "NULL AS lanowner "
7476 						  "FROM pg_language "
7477 						  "WHERE lanispl "
7478 						  "ORDER BY oid");
7479 	}
7480 	else
7481 	{
7482 		appendPQExpBuffer(query, "SELECT "
7483 						  "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
7484 						  "oid, "
7485 						  "lanname, lanpltrusted, lanplcallfoid, "
7486 						"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
7487 						  "NULL AS rlanacl, "
7488 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7489 						  "NULL AS lanowner "
7490 						  "FROM pg_language "
7491 						  "WHERE lanispl "
7492 						  "ORDER BY oid");
7493 	}
7494 
7495 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7496 
7497 	ntups = PQntuples(res);
7498 
7499 	*numProcLangs = ntups;
7500 
7501 	planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7502 
7503 	i_tableoid = PQfnumber(res, "tableoid");
7504 	i_oid = PQfnumber(res, "oid");
7505 	i_lanname = PQfnumber(res, "lanname");
7506 	i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7507 	i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7508 	i_laninline = PQfnumber(res, "laninline");
7509 	i_lanvalidator = PQfnumber(res, "lanvalidator");
7510 	i_lanacl = PQfnumber(res, "lanacl");
7511 	i_rlanacl = PQfnumber(res, "rlanacl");
7512 	i_initlanacl = PQfnumber(res, "initlanacl");
7513 	i_initrlanacl = PQfnumber(res, "initrlanacl");
7514 	i_lanowner = PQfnumber(res, "lanowner");
7515 
7516 	for (i = 0; i < ntups; i++)
7517 	{
7518 		planginfo[i].dobj.objType = DO_PROCLANG;
7519 		planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7520 		planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7521 		AssignDumpId(&planginfo[i].dobj);
7522 
7523 		planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7524 		planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7525 		planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7526 		planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7527 		planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7528 		planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7529 		planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7530 		planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7531 		planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7532 		planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7533 
7534 		/* Decide whether we want to dump it */
7535 		selectDumpableProcLang(&(planginfo[i]), fout);
7536 
7537 		/* Do not try to dump ACL if no ACL exists. */
7538 		if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7539 			PQgetisnull(res, i, i_initlanacl) &&
7540 			PQgetisnull(res, i, i_initrlanacl))
7541 			planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7542 
7543 		if (fout->remoteVersion < 70300)
7544 		{
7545 			/*
7546 			 * We need to make a dependency to ensure the function will be
7547 			 * dumped first.  (In 7.3 and later the regular dependency
7548 			 * mechanism will handle this for us.)
7549 			 */
7550 			FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
7551 
7552 			if (funcInfo)
7553 				addObjectDependency(&planginfo[i].dobj,
7554 									funcInfo->dobj.dumpId);
7555 		}
7556 	}
7557 
7558 	PQclear(res);
7559 
7560 	destroyPQExpBuffer(query);
7561 
7562 	return planginfo;
7563 }
7564 
7565 /*
7566  * getCasts
7567  *	  get basic information about every cast in the system
7568  *
7569  * numCasts is set to the number of casts read in
7570  */
7571 CastInfo *
getCasts(Archive * fout,int * numCasts)7572 getCasts(Archive *fout, int *numCasts)
7573 {
7574 	PGresult   *res;
7575 	int			ntups;
7576 	int			i;
7577 	PQExpBuffer query = createPQExpBuffer();
7578 	CastInfo   *castinfo;
7579 	int			i_tableoid;
7580 	int			i_oid;
7581 	int			i_castsource;
7582 	int			i_casttarget;
7583 	int			i_castfunc;
7584 	int			i_castcontext;
7585 	int			i_castmethod;
7586 
7587 	if (fout->remoteVersion >= 80400)
7588 	{
7589 		appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7590 							 "castsource, casttarget, castfunc, castcontext, "
7591 							 "castmethod "
7592 							 "FROM pg_cast ORDER BY 3,4");
7593 	}
7594 	else if (fout->remoteVersion >= 70300)
7595 	{
7596 		appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7597 							 "castsource, casttarget, castfunc, castcontext, "
7598 				"CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
7599 							 "FROM pg_cast ORDER BY 3,4");
7600 	}
7601 	else
7602 	{
7603 		appendPQExpBufferStr(query, "SELECT 0 AS tableoid, p.oid, "
7604 							 "t1.oid AS castsource, t2.oid AS casttarget, "
7605 							 "p.oid AS castfunc, 'e' AS castcontext, "
7606 							 "'f' AS castmethod "
7607 							 "FROM pg_type t1, pg_type t2, pg_proc p "
7608 							 "WHERE p.pronargs = 1 AND "
7609 							 "p.proargtypes[0] = t1.oid AND "
7610 						  "p.prorettype = t2.oid AND p.proname = t2.typname "
7611 							 "ORDER BY 3,4");
7612 	}
7613 
7614 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7615 
7616 	ntups = PQntuples(res);
7617 
7618 	*numCasts = ntups;
7619 
7620 	castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
7621 
7622 	i_tableoid = PQfnumber(res, "tableoid");
7623 	i_oid = PQfnumber(res, "oid");
7624 	i_castsource = PQfnumber(res, "castsource");
7625 	i_casttarget = PQfnumber(res, "casttarget");
7626 	i_castfunc = PQfnumber(res, "castfunc");
7627 	i_castcontext = PQfnumber(res, "castcontext");
7628 	i_castmethod = PQfnumber(res, "castmethod");
7629 
7630 	for (i = 0; i < ntups; i++)
7631 	{
7632 		PQExpBufferData namebuf;
7633 		TypeInfo   *sTypeInfo;
7634 		TypeInfo   *tTypeInfo;
7635 
7636 		castinfo[i].dobj.objType = DO_CAST;
7637 		castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7638 		castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7639 		AssignDumpId(&castinfo[i].dobj);
7640 		castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
7641 		castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
7642 		castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
7643 		castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
7644 		castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
7645 
7646 		/*
7647 		 * Try to name cast as concatenation of typnames.  This is only used
7648 		 * for purposes of sorting.  If we fail to find either type, the name
7649 		 * will be an empty string.
7650 		 */
7651 		initPQExpBuffer(&namebuf);
7652 		sTypeInfo = findTypeByOid(castinfo[i].castsource);
7653 		tTypeInfo = findTypeByOid(castinfo[i].casttarget);
7654 		if (sTypeInfo && tTypeInfo)
7655 			appendPQExpBuffer(&namebuf, "%s %s",
7656 							  sTypeInfo->dobj.name, tTypeInfo->dobj.name);
7657 		castinfo[i].dobj.name = namebuf.data;
7658 
7659 		if (fout->remoteVersion < 70300 &&
7660 			OidIsValid(castinfo[i].castfunc))
7661 		{
7662 			/*
7663 			 * We need to make a dependency to ensure the function will be
7664 			 * dumped first.  (In 7.3 and later the regular dependency
7665 			 * mechanism handles this for us.)
7666 			 */
7667 			FuncInfo   *funcInfo;
7668 
7669 			funcInfo = findFuncByOid(castinfo[i].castfunc);
7670 			if (funcInfo)
7671 				addObjectDependency(&castinfo[i].dobj,
7672 									funcInfo->dobj.dumpId);
7673 		}
7674 
7675 		/* Decide whether we want to dump it */
7676 		selectDumpableCast(&(castinfo[i]), fout);
7677 
7678 		/* Casts do not currently have ACLs. */
7679 		castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7680 	}
7681 
7682 	PQclear(res);
7683 
7684 	destroyPQExpBuffer(query);
7685 
7686 	return castinfo;
7687 }
7688 
7689 static char *
get_language_name(Archive * fout,Oid langid)7690 get_language_name(Archive *fout, Oid langid)
7691 {
7692 	PQExpBuffer query;
7693 	PGresult   *res;
7694 	char	   *lanname;
7695 
7696 	query = createPQExpBuffer();
7697 	appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
7698 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
7699 	lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
7700 	destroyPQExpBuffer(query);
7701 	PQclear(res);
7702 
7703 	return lanname;
7704 }
7705 
7706 /*
7707  * getTransforms
7708  *	  get basic information about every transform in the system
7709  *
7710  * numTransforms is set to the number of transforms read in
7711  */
7712 TransformInfo *
getTransforms(Archive * fout,int * numTransforms)7713 getTransforms(Archive *fout, int *numTransforms)
7714 {
7715 	PGresult   *res;
7716 	int			ntups;
7717 	int			i;
7718 	PQExpBuffer query;
7719 	TransformInfo *transforminfo;
7720 	int			i_tableoid;
7721 	int			i_oid;
7722 	int			i_trftype;
7723 	int			i_trflang;
7724 	int			i_trffromsql;
7725 	int			i_trftosql;
7726 
7727 	/* Transforms didn't exist pre-9.5 */
7728 	if (fout->remoteVersion < 90500)
7729 	{
7730 		*numTransforms = 0;
7731 		return NULL;
7732 	}
7733 
7734 	query = createPQExpBuffer();
7735 
7736 	appendPQExpBuffer(query, "SELECT tableoid, oid, "
7737 					  "trftype, trflang, trffromsql::oid, trftosql::oid "
7738 					  "FROM pg_transform "
7739 					  "ORDER BY 3,4");
7740 
7741 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7742 
7743 	ntups = PQntuples(res);
7744 
7745 	*numTransforms = ntups;
7746 
7747 	transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
7748 
7749 	i_tableoid = PQfnumber(res, "tableoid");
7750 	i_oid = PQfnumber(res, "oid");
7751 	i_trftype = PQfnumber(res, "trftype");
7752 	i_trflang = PQfnumber(res, "trflang");
7753 	i_trffromsql = PQfnumber(res, "trffromsql");
7754 	i_trftosql = PQfnumber(res, "trftosql");
7755 
7756 	for (i = 0; i < ntups; i++)
7757 	{
7758 		PQExpBufferData namebuf;
7759 		TypeInfo   *typeInfo;
7760 		char	   *lanname;
7761 
7762 		transforminfo[i].dobj.objType = DO_TRANSFORM;
7763 		transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7764 		transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7765 		AssignDumpId(&transforminfo[i].dobj);
7766 		transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
7767 		transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
7768 		transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
7769 		transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
7770 
7771 		/*
7772 		 * Try to name transform as concatenation of type and language name.
7773 		 * This is only used for purposes of sorting.  If we fail to find
7774 		 * either, the name will be an empty string.
7775 		 */
7776 		initPQExpBuffer(&namebuf);
7777 		typeInfo = findTypeByOid(transforminfo[i].trftype);
7778 		lanname = get_language_name(fout, transforminfo[i].trflang);
7779 		if (typeInfo && lanname)
7780 			appendPQExpBuffer(&namebuf, "%s %s",
7781 							  typeInfo->dobj.name, lanname);
7782 		transforminfo[i].dobj.name = namebuf.data;
7783 		free(lanname);
7784 
7785 		/* Decide whether we want to dump it */
7786 		selectDumpableObject(&(transforminfo[i].dobj), fout);
7787 	}
7788 
7789 	PQclear(res);
7790 
7791 	destroyPQExpBuffer(query);
7792 
7793 	return transforminfo;
7794 }
7795 
7796 /*
7797  * getTableAttrs -
7798  *	  for each interesting table, read info about its attributes
7799  *	  (names, types, default values, CHECK constraints, etc)
7800  *
7801  * This is implemented in a very inefficient way right now, looping
7802  * through the tblinfo and doing a join per table to find the attrs and their
7803  * types.  However, because we want type names and so forth to be named
7804  * relative to the schema of each table, we couldn't do it in just one
7805  * query.  (Maybe one query per schema?)
7806  *
7807  *	modifies tblinfo
7808  */
7809 void
getTableAttrs(Archive * fout,TableInfo * tblinfo,int numTables)7810 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
7811 {
7812 	DumpOptions *dopt = fout->dopt;
7813 	int			i,
7814 				j;
7815 	PQExpBuffer q = createPQExpBuffer();
7816 	int			i_attnum;
7817 	int			i_attname;
7818 	int			i_atttypname;
7819 	int			i_atttypmod;
7820 	int			i_attstattarget;
7821 	int			i_attstorage;
7822 	int			i_typstorage;
7823 	int			i_attnotnull;
7824 	int			i_atthasdef;
7825 	int			i_attisdropped;
7826 	int			i_attlen;
7827 	int			i_attalign;
7828 	int			i_attislocal;
7829 	int			i_attoptions;
7830 	int			i_attcollation;
7831 	int			i_attfdwoptions;
7832 	PGresult   *res;
7833 	int			ntups;
7834 	bool		hasdefaults;
7835 
7836 	for (i = 0; i < numTables; i++)
7837 	{
7838 		TableInfo  *tbinfo = &tblinfo[i];
7839 
7840 		/* Don't bother to collect info for sequences */
7841 		if (tbinfo->relkind == RELKIND_SEQUENCE)
7842 			continue;
7843 
7844 		/* Don't bother with uninteresting tables, either */
7845 		if (!tbinfo->interesting)
7846 			continue;
7847 
7848 		/* find all the user attributes and their types */
7849 
7850 		/*
7851 		 * we must read the attribute names in attribute number order! because
7852 		 * we will use the attnum to index into the attnames array later.  We
7853 		 * actually ask to order by "attrelid, attnum" because (at least up to
7854 		 * 7.3) the planner is not smart enough to realize it needn't re-sort
7855 		 * the output of an indexscan on pg_attribute_relid_attnum_index.
7856 		 */
7857 		if (g_verbose)
7858 			write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
7859 					  tbinfo->dobj.namespace->dobj.name,
7860 					  tbinfo->dobj.name);
7861 
7862 		resetPQExpBuffer(q);
7863 
7864 		if (fout->remoteVersion >= 90200)
7865 		{
7866 			/*
7867 			 * attfdwoptions is new in 9.2.
7868 			 */
7869 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
7870 							  "a.attstattarget, a.attstorage, t.typstorage, "
7871 							  "a.attnotnull, a.atthasdef, a.attisdropped, "
7872 							  "a.attlen, a.attalign, a.attislocal, "
7873 				  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
7874 						"array_to_string(a.attoptions, ', ') AS attoptions, "
7875 							  "CASE WHEN a.attcollation <> t.typcollation "
7876 						   "THEN a.attcollation ELSE 0 END AS attcollation, "
7877 							  "pg_catalog.array_to_string(ARRAY("
7878 							  "SELECT pg_catalog.quote_ident(option_name) || "
7879 							  "' ' || pg_catalog.quote_literal(option_value) "
7880 						"FROM pg_catalog.pg_options_to_table(attfdwoptions) "
7881 							  "ORDER BY option_name"
7882 							  "), E',\n    ') AS attfdwoptions "
7883 			 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
7884 							  "ON a.atttypid = t.oid "
7885 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
7886 							  "AND a.attnum > 0::pg_catalog.int2 "
7887 							  "ORDER BY a.attrelid, a.attnum",
7888 							  tbinfo->dobj.catId.oid);
7889 		}
7890 		else if (fout->remoteVersion >= 90100)
7891 		{
7892 			/*
7893 			 * attcollation is new in 9.1.  Since we only want to dump COLLATE
7894 			 * clauses for attributes whose collation is different from their
7895 			 * type's default, we use a CASE here to suppress uninteresting
7896 			 * attcollations cheaply.
7897 			 */
7898 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
7899 							  "a.attstattarget, a.attstorage, t.typstorage, "
7900 							  "a.attnotnull, a.atthasdef, a.attisdropped, "
7901 							  "a.attlen, a.attalign, a.attislocal, "
7902 				  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
7903 						"array_to_string(a.attoptions, ', ') AS attoptions, "
7904 							  "CASE WHEN a.attcollation <> t.typcollation "
7905 						   "THEN a.attcollation ELSE 0 END AS attcollation, "
7906 							  "NULL AS attfdwoptions "
7907 			 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
7908 							  "ON a.atttypid = t.oid "
7909 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
7910 							  "AND a.attnum > 0::pg_catalog.int2 "
7911 							  "ORDER BY a.attrelid, a.attnum",
7912 							  tbinfo->dobj.catId.oid);
7913 		}
7914 		else if (fout->remoteVersion >= 90000)
7915 		{
7916 			/* attoptions is new in 9.0 */
7917 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
7918 							  "a.attstattarget, a.attstorage, t.typstorage, "
7919 							  "a.attnotnull, a.atthasdef, a.attisdropped, "
7920 							  "a.attlen, a.attalign, a.attislocal, "
7921 				  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
7922 						"array_to_string(a.attoptions, ', ') AS attoptions, "
7923 							  "0 AS attcollation, "
7924 							  "NULL AS attfdwoptions "
7925 			 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
7926 							  "ON a.atttypid = t.oid "
7927 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
7928 							  "AND a.attnum > 0::pg_catalog.int2 "
7929 							  "ORDER BY a.attrelid, a.attnum",
7930 							  tbinfo->dobj.catId.oid);
7931 		}
7932 		else if (fout->remoteVersion >= 70300)
7933 		{
7934 			/* need left join here to not fail on dropped columns ... */
7935 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
7936 							  "a.attstattarget, a.attstorage, t.typstorage, "
7937 							  "a.attnotnull, a.atthasdef, a.attisdropped, "
7938 							  "a.attlen, a.attalign, a.attislocal, "
7939 				  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
7940 							  "'' AS attoptions, 0 AS attcollation, "
7941 							  "NULL AS attfdwoptions "
7942 			 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
7943 							  "ON a.atttypid = t.oid "
7944 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
7945 							  "AND a.attnum > 0::pg_catalog.int2 "
7946 							  "ORDER BY a.attrelid, a.attnum",
7947 							  tbinfo->dobj.catId.oid);
7948 		}
7949 		else if (fout->remoteVersion >= 70100)
7950 		{
7951 			/*
7952 			 * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
7953 			 * we don't dump it because we can't tell whether it's been
7954 			 * explicitly set or was just a default.
7955 			 *
7956 			 * attislocal doesn't exist before 7.3, either; in older databases
7957 			 * we assume it's TRUE, else we'd fail to dump non-inherited atts.
7958 			 */
7959 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
7960 							  "-1 AS attstattarget, a.attstorage, "
7961 							  "t.typstorage, a.attnotnull, a.atthasdef, "
7962 							  "false AS attisdropped, a.attlen, "
7963 							  "a.attalign, true AS attislocal, "
7964 							  "format_type(t.oid,a.atttypmod) AS atttypname, "
7965 							  "'' AS attoptions, 0 AS attcollation, "
7966 							  "NULL AS attfdwoptions "
7967 							  "FROM pg_attribute a LEFT JOIN pg_type t "
7968 							  "ON a.atttypid = t.oid "
7969 							  "WHERE a.attrelid = '%u'::oid "
7970 							  "AND a.attnum > 0::int2 "
7971 							  "ORDER BY a.attrelid, a.attnum",
7972 							  tbinfo->dobj.catId.oid);
7973 		}
7974 		else
7975 		{
7976 			/* format_type not available before 7.1 */
7977 			appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
7978 							  "-1 AS attstattarget, "
7979 							  "attstorage, attstorage AS typstorage, "
7980 							  "attnotnull, atthasdef, false AS attisdropped, "
7981 							  "attlen, attalign, "
7982 							  "true AS attislocal, "
7983 							  "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
7984 							  "'' AS attoptions, 0 AS attcollation, "
7985 							  "NULL AS attfdwoptions "
7986 							  "FROM pg_attribute a "
7987 							  "WHERE attrelid = '%u'::oid "
7988 							  "AND attnum > 0::int2 "
7989 							  "ORDER BY attrelid, attnum",
7990 							  tbinfo->dobj.catId.oid);
7991 		}
7992 
7993 		res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
7994 
7995 		ntups = PQntuples(res);
7996 
7997 		i_attnum = PQfnumber(res, "attnum");
7998 		i_attname = PQfnumber(res, "attname");
7999 		i_atttypname = PQfnumber(res, "atttypname");
8000 		i_atttypmod = PQfnumber(res, "atttypmod");
8001 		i_attstattarget = PQfnumber(res, "attstattarget");
8002 		i_attstorage = PQfnumber(res, "attstorage");
8003 		i_typstorage = PQfnumber(res, "typstorage");
8004 		i_attnotnull = PQfnumber(res, "attnotnull");
8005 		i_atthasdef = PQfnumber(res, "atthasdef");
8006 		i_attisdropped = PQfnumber(res, "attisdropped");
8007 		i_attlen = PQfnumber(res, "attlen");
8008 		i_attalign = PQfnumber(res, "attalign");
8009 		i_attislocal = PQfnumber(res, "attislocal");
8010 		i_attoptions = PQfnumber(res, "attoptions");
8011 		i_attcollation = PQfnumber(res, "attcollation");
8012 		i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8013 
8014 		tbinfo->numatts = ntups;
8015 		tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8016 		tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8017 		tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8018 		tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8019 		tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8020 		tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8021 		tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8022 		tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8023 		tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8024 		tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8025 		tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8026 		tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8027 		tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8028 		tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8029 		tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8030 		tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8031 		hasdefaults = false;
8032 
8033 		for (j = 0; j < ntups; j++)
8034 		{
8035 			if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8036 				exit_horribly(NULL,
8037 							  "invalid column numbering in table \"%s\"\n",
8038 							  tbinfo->dobj.name);
8039 			tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8040 			tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8041 			tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8042 			tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8043 			tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8044 			tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8045 			tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8046 			tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8047 			tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8048 			tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8049 			tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8050 			tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8051 			tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8052 			tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8053 			tbinfo->attrdefs[j] = NULL; /* fix below */
8054 			if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8055 				hasdefaults = true;
8056 			/* these flags will be set in flagInhAttrs() */
8057 			tbinfo->inhNotNull[j] = false;
8058 		}
8059 
8060 		PQclear(res);
8061 
8062 		/*
8063 		 * Get info about column defaults
8064 		 */
8065 		if (hasdefaults)
8066 		{
8067 			AttrDefInfo *attrdefs;
8068 			int			numDefaults;
8069 
8070 			if (g_verbose)
8071 				write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
8072 						  tbinfo->dobj.namespace->dobj.name,
8073 						  tbinfo->dobj.name);
8074 
8075 			resetPQExpBuffer(q);
8076 			if (fout->remoteVersion >= 70300)
8077 			{
8078 				appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8079 						   "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8080 								  "FROM pg_catalog.pg_attrdef "
8081 								  "WHERE adrelid = '%u'::pg_catalog.oid",
8082 								  tbinfo->dobj.catId.oid);
8083 			}
8084 			else if (fout->remoteVersion >= 70200)
8085 			{
8086 				/* 7.2 did not have OIDs in pg_attrdef */
8087 				appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
8088 								  "pg_get_expr(adbin, adrelid) AS adsrc "
8089 								  "FROM pg_attrdef "
8090 								  "WHERE adrelid = '%u'::oid",
8091 								  tbinfo->dobj.catId.oid);
8092 			}
8093 			else if (fout->remoteVersion >= 70100)
8094 			{
8095 				/* no pg_get_expr, so must rely on adsrc */
8096 				appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
8097 								  "FROM pg_attrdef "
8098 								  "WHERE adrelid = '%u'::oid",
8099 								  tbinfo->dobj.catId.oid);
8100 			}
8101 			else
8102 			{
8103 				/* no pg_get_expr, no tableoid either */
8104 				appendPQExpBuffer(q, "SELECT "
8105 								  "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
8106 								  "oid, adnum, adsrc "
8107 								  "FROM pg_attrdef "
8108 								  "WHERE adrelid = '%u'::oid",
8109 								  tbinfo->dobj.catId.oid);
8110 			}
8111 			res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8112 
8113 			numDefaults = PQntuples(res);
8114 			attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8115 
8116 			for (j = 0; j < numDefaults; j++)
8117 			{
8118 				int			adnum;
8119 
8120 				adnum = atoi(PQgetvalue(res, j, 2));
8121 
8122 				if (adnum <= 0 || adnum > ntups)
8123 					exit_horribly(NULL,
8124 								  "invalid adnum value %d for table \"%s\"\n",
8125 								  adnum, tbinfo->dobj.name);
8126 
8127 				/*
8128 				 * dropped columns shouldn't have defaults, but just in case,
8129 				 * ignore 'em
8130 				 */
8131 				if (tbinfo->attisdropped[adnum - 1])
8132 					continue;
8133 
8134 				attrdefs[j].dobj.objType = DO_ATTRDEF;
8135 				attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8136 				attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8137 				AssignDumpId(&attrdefs[j].dobj);
8138 				attrdefs[j].adtable = tbinfo;
8139 				attrdefs[j].adnum = adnum;
8140 				attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8141 
8142 				attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8143 				attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8144 
8145 				attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8146 
8147 				/*
8148 				 * Defaults on a VIEW must always be dumped as separate ALTER
8149 				 * TABLE commands.  Defaults on regular tables are dumped as
8150 				 * part of the CREATE TABLE if possible, which it won't be if
8151 				 * the column is not going to be emitted explicitly.
8152 				 */
8153 				if (tbinfo->relkind == RELKIND_VIEW)
8154 				{
8155 					attrdefs[j].separate = true;
8156 					/* needed in case pre-7.3 DB: */
8157 					addObjectDependency(&attrdefs[j].dobj,
8158 										tbinfo->dobj.dumpId);
8159 				}
8160 				else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8161 				{
8162 					/* column will be suppressed, print default separately */
8163 					attrdefs[j].separate = true;
8164 					/* needed in case pre-7.3 DB: */
8165 					addObjectDependency(&attrdefs[j].dobj,
8166 										tbinfo->dobj.dumpId);
8167 				}
8168 				else
8169 				{
8170 					attrdefs[j].separate = false;
8171 
8172 					/*
8173 					 * Mark the default as needing to appear before the table,
8174 					 * so that any dependencies it has must be emitted before
8175 					 * the CREATE TABLE.  If this is not possible, we'll
8176 					 * change to "separate" mode while sorting dependencies.
8177 					 */
8178 					addObjectDependency(&tbinfo->dobj,
8179 										attrdefs[j].dobj.dumpId);
8180 				}
8181 
8182 				tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8183 			}
8184 			PQclear(res);
8185 		}
8186 
8187 		/*
8188 		 * Get info about table CHECK constraints
8189 		 */
8190 		if (tbinfo->ncheck > 0)
8191 		{
8192 			ConstraintInfo *constrs;
8193 			int			numConstrs;
8194 
8195 			if (g_verbose)
8196 				write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
8197 						  tbinfo->dobj.namespace->dobj.name,
8198 						  tbinfo->dobj.name);
8199 
8200 			resetPQExpBuffer(q);
8201 			if (fout->remoteVersion >= 90200)
8202 			{
8203 				/*
8204 				 * convalidated is new in 9.2 (actually, it is there in 9.1,
8205 				 * but it wasn't ever false for check constraints until 9.2).
8206 				 */
8207 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8208 						   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8209 								  "conislocal, convalidated "
8210 								  "FROM pg_catalog.pg_constraint "
8211 								  "WHERE conrelid = '%u'::pg_catalog.oid "
8212 								  "   AND contype = 'c' "
8213 								  "ORDER BY conname",
8214 								  tbinfo->dobj.catId.oid);
8215 			}
8216 			else if (fout->remoteVersion >= 80400)
8217 			{
8218 				/* conislocal is new in 8.4 */
8219 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8220 						   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8221 								  "conislocal, true AS convalidated "
8222 								  "FROM pg_catalog.pg_constraint "
8223 								  "WHERE conrelid = '%u'::pg_catalog.oid "
8224 								  "   AND contype = 'c' "
8225 								  "ORDER BY conname",
8226 								  tbinfo->dobj.catId.oid);
8227 			}
8228 			else if (fout->remoteVersion >= 70400)
8229 			{
8230 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8231 						   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8232 								  "true AS conislocal, true AS convalidated "
8233 								  "FROM pg_catalog.pg_constraint "
8234 								  "WHERE conrelid = '%u'::pg_catalog.oid "
8235 								  "   AND contype = 'c' "
8236 								  "ORDER BY conname",
8237 								  tbinfo->dobj.catId.oid);
8238 			}
8239 			else if (fout->remoteVersion >= 70300)
8240 			{
8241 				/* no pg_get_constraintdef, must use consrc */
8242 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8243 								  "'CHECK (' || consrc || ')' AS consrc, "
8244 								  "true AS conislocal, true AS convalidated "
8245 								  "FROM pg_catalog.pg_constraint "
8246 								  "WHERE conrelid = '%u'::pg_catalog.oid "
8247 								  "   AND contype = 'c' "
8248 								  "ORDER BY conname",
8249 								  tbinfo->dobj.catId.oid);
8250 			}
8251 			else if (fout->remoteVersion >= 70200)
8252 			{
8253 				/* 7.2 did not have OIDs in pg_relcheck */
8254 				appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
8255 								  "rcname AS conname, "
8256 								  "'CHECK (' || rcsrc || ')' AS consrc, "
8257 								  "true AS conislocal, true AS convalidated "
8258 								  "FROM pg_relcheck "
8259 								  "WHERE rcrelid = '%u'::oid "
8260 								  "ORDER BY rcname",
8261 								  tbinfo->dobj.catId.oid);
8262 			}
8263 			else if (fout->remoteVersion >= 70100)
8264 			{
8265 				appendPQExpBuffer(q, "SELECT tableoid, oid, "
8266 								  "rcname AS conname, "
8267 								  "'CHECK (' || rcsrc || ')' AS consrc, "
8268 								  "true AS conislocal, true AS convalidated "
8269 								  "FROM pg_relcheck "
8270 								  "WHERE rcrelid = '%u'::oid "
8271 								  "ORDER BY rcname",
8272 								  tbinfo->dobj.catId.oid);
8273 			}
8274 			else
8275 			{
8276 				/* no tableoid in 7.0 */
8277 				appendPQExpBuffer(q, "SELECT "
8278 								  "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
8279 								  "oid, rcname AS conname, "
8280 								  "'CHECK (' || rcsrc || ')' AS consrc, "
8281 								  "true AS conislocal, true AS convalidated "
8282 								  "FROM pg_relcheck "
8283 								  "WHERE rcrelid = '%u'::oid "
8284 								  "ORDER BY rcname",
8285 								  tbinfo->dobj.catId.oid);
8286 			}
8287 			res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8288 
8289 			numConstrs = PQntuples(res);
8290 			if (numConstrs != tbinfo->ncheck)
8291 			{
8292 				write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
8293 										 "expected %d check constraints on table \"%s\" but found %d\n",
8294 										 tbinfo->ncheck),
8295 						  tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8296 				write_msg(NULL, "(The system catalogs might be corrupted.)\n");
8297 				exit_nicely(1);
8298 			}
8299 
8300 			constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8301 			tbinfo->checkexprs = constrs;
8302 
8303 			for (j = 0; j < numConstrs; j++)
8304 			{
8305 				bool		validated = PQgetvalue(res, j, 5)[0] == 't';
8306 
8307 				constrs[j].dobj.objType = DO_CONSTRAINT;
8308 				constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8309 				constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8310 				AssignDumpId(&constrs[j].dobj);
8311 				constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8312 				constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8313 				constrs[j].contable = tbinfo;
8314 				constrs[j].condomain = NULL;
8315 				constrs[j].contype = 'c';
8316 				constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8317 				constrs[j].confrelid = InvalidOid;
8318 				constrs[j].conindex = 0;
8319 				constrs[j].condeferrable = false;
8320 				constrs[j].condeferred = false;
8321 				constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8322 
8323 				/*
8324 				 * An unvalidated constraint needs to be dumped separately, so
8325 				 * that potentially-violating existing data is loaded before
8326 				 * the constraint.
8327 				 */
8328 				constrs[j].separate = !validated;
8329 
8330 				constrs[j].dobj.dump = tbinfo->dobj.dump;
8331 
8332 				/*
8333 				 * Mark the constraint as needing to appear before the table
8334 				 * --- this is so that any other dependencies of the
8335 				 * constraint will be emitted before we try to create the
8336 				 * table.  If the constraint is to be dumped separately, it
8337 				 * will be dumped after data is loaded anyway, so don't do it.
8338 				 * (There's an automatic dependency in the opposite direction
8339 				 * anyway, so don't need to add one manually here.)
8340 				 */
8341 				if (!constrs[j].separate)
8342 					addObjectDependency(&tbinfo->dobj,
8343 										constrs[j].dobj.dumpId);
8344 
8345 				/*
8346 				 * If the constraint is inherited, this will be detected later
8347 				 * (in pre-8.4 databases).  We also detect later if the
8348 				 * constraint must be split out from the table definition.
8349 				 */
8350 			}
8351 			PQclear(res);
8352 		}
8353 	}
8354 
8355 	destroyPQExpBuffer(q);
8356 }
8357 
8358 /*
8359  * Test whether a column should be printed as part of table's CREATE TABLE.
8360  * Column number is zero-based.
8361  *
8362  * Normally this is always true, but it's false for dropped columns, as well
8363  * as those that were inherited without any local definition.  (If we print
8364  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8365  * However, in binary_upgrade mode, we must print all such columns anyway and
8366  * fix the attislocal/attisdropped state later, so as to keep control of the
8367  * physical column order.
8368  *
8369  * This function exists because there are scattered nonobvious places that
8370  * must be kept in sync with this decision.
8371  */
8372 bool
shouldPrintColumn(DumpOptions * dopt,TableInfo * tbinfo,int colno)8373 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8374 {
8375 	if (dopt->binary_upgrade)
8376 		return true;
8377 	return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
8378 }
8379 
8380 
8381 /*
8382  * getTSParsers:
8383  *	  read all text search parsers in the system catalogs and return them
8384  *	  in the TSParserInfo* structure
8385  *
8386  *	numTSParsers is set to the number of parsers read in
8387  */
8388 TSParserInfo *
getTSParsers(Archive * fout,int * numTSParsers)8389 getTSParsers(Archive *fout, int *numTSParsers)
8390 {
8391 	PGresult   *res;
8392 	int			ntups;
8393 	int			i;
8394 	PQExpBuffer query;
8395 	TSParserInfo *prsinfo;
8396 	int			i_tableoid;
8397 	int			i_oid;
8398 	int			i_prsname;
8399 	int			i_prsnamespace;
8400 	int			i_prsstart;
8401 	int			i_prstoken;
8402 	int			i_prsend;
8403 	int			i_prsheadline;
8404 	int			i_prslextype;
8405 
8406 	/* Before 8.3, there is no built-in text search support */
8407 	if (fout->remoteVersion < 80300)
8408 	{
8409 		*numTSParsers = 0;
8410 		return NULL;
8411 	}
8412 
8413 	query = createPQExpBuffer();
8414 
8415 	/*
8416 	 * find all text search objects, including builtin ones; we filter out
8417 	 * system-defined objects at dump-out time.
8418 	 */
8419 
8420 	appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8421 						 "prsstart::oid, prstoken::oid, "
8422 						 "prsend::oid, prsheadline::oid, prslextype::oid "
8423 						 "FROM pg_ts_parser");
8424 
8425 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8426 
8427 	ntups = PQntuples(res);
8428 	*numTSParsers = ntups;
8429 
8430 	prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8431 
8432 	i_tableoid = PQfnumber(res, "tableoid");
8433 	i_oid = PQfnumber(res, "oid");
8434 	i_prsname = PQfnumber(res, "prsname");
8435 	i_prsnamespace = PQfnumber(res, "prsnamespace");
8436 	i_prsstart = PQfnumber(res, "prsstart");
8437 	i_prstoken = PQfnumber(res, "prstoken");
8438 	i_prsend = PQfnumber(res, "prsend");
8439 	i_prsheadline = PQfnumber(res, "prsheadline");
8440 	i_prslextype = PQfnumber(res, "prslextype");
8441 
8442 	for (i = 0; i < ntups; i++)
8443 	{
8444 		prsinfo[i].dobj.objType = DO_TSPARSER;
8445 		prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8446 		prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8447 		AssignDumpId(&prsinfo[i].dobj);
8448 		prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8449 		prsinfo[i].dobj.namespace =
8450 			findNamespace(fout,
8451 						  atooid(PQgetvalue(res, i, i_prsnamespace)),
8452 						  prsinfo[i].dobj.catId.oid);
8453 		prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8454 		prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8455 		prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8456 		prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8457 		prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8458 
8459 		/* Decide whether we want to dump it */
8460 		selectDumpableObject(&(prsinfo[i].dobj), fout);
8461 
8462 		/* Text Search Parsers do not currently have ACLs. */
8463 		prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8464 	}
8465 
8466 	PQclear(res);
8467 
8468 	destroyPQExpBuffer(query);
8469 
8470 	return prsinfo;
8471 }
8472 
8473 /*
8474  * getTSDictionaries:
8475  *	  read all text search dictionaries in the system catalogs and return them
8476  *	  in the TSDictInfo* structure
8477  *
8478  *	numTSDicts is set to the number of dictionaries read in
8479  */
8480 TSDictInfo *
getTSDictionaries(Archive * fout,int * numTSDicts)8481 getTSDictionaries(Archive *fout, int *numTSDicts)
8482 {
8483 	PGresult   *res;
8484 	int			ntups;
8485 	int			i;
8486 	PQExpBuffer query;
8487 	TSDictInfo *dictinfo;
8488 	int			i_tableoid;
8489 	int			i_oid;
8490 	int			i_dictname;
8491 	int			i_dictnamespace;
8492 	int			i_rolname;
8493 	int			i_dicttemplate;
8494 	int			i_dictinitoption;
8495 
8496 	/* Before 8.3, there is no built-in text search support */
8497 	if (fout->remoteVersion < 80300)
8498 	{
8499 		*numTSDicts = 0;
8500 		return NULL;
8501 	}
8502 
8503 	query = createPQExpBuffer();
8504 
8505 	appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8506 					  "dictnamespace, (%s dictowner) AS rolname, "
8507 					  "dicttemplate, dictinitoption "
8508 					  "FROM pg_ts_dict",
8509 					  username_subquery);
8510 
8511 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8512 
8513 	ntups = PQntuples(res);
8514 	*numTSDicts = ntups;
8515 
8516 	dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8517 
8518 	i_tableoid = PQfnumber(res, "tableoid");
8519 	i_oid = PQfnumber(res, "oid");
8520 	i_dictname = PQfnumber(res, "dictname");
8521 	i_dictnamespace = PQfnumber(res, "dictnamespace");
8522 	i_rolname = PQfnumber(res, "rolname");
8523 	i_dictinitoption = PQfnumber(res, "dictinitoption");
8524 	i_dicttemplate = PQfnumber(res, "dicttemplate");
8525 
8526 	for (i = 0; i < ntups; i++)
8527 	{
8528 		dictinfo[i].dobj.objType = DO_TSDICT;
8529 		dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8530 		dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8531 		AssignDumpId(&dictinfo[i].dobj);
8532 		dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8533 		dictinfo[i].dobj.namespace =
8534 			findNamespace(fout,
8535 						  atooid(PQgetvalue(res, i, i_dictnamespace)),
8536 						  dictinfo[i].dobj.catId.oid);
8537 		dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8538 		dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8539 		if (PQgetisnull(res, i, i_dictinitoption))
8540 			dictinfo[i].dictinitoption = NULL;
8541 		else
8542 			dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8543 
8544 		/* Decide whether we want to dump it */
8545 		selectDumpableObject(&(dictinfo[i].dobj), fout);
8546 
8547 		/* Text Search Dictionaries do not currently have ACLs. */
8548 		dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8549 	}
8550 
8551 	PQclear(res);
8552 
8553 	destroyPQExpBuffer(query);
8554 
8555 	return dictinfo;
8556 }
8557 
8558 /*
8559  * getTSTemplates:
8560  *	  read all text search templates in the system catalogs and return them
8561  *	  in the TSTemplateInfo* structure
8562  *
8563  *	numTSTemplates is set to the number of templates read in
8564  */
8565 TSTemplateInfo *
getTSTemplates(Archive * fout,int * numTSTemplates)8566 getTSTemplates(Archive *fout, int *numTSTemplates)
8567 {
8568 	PGresult   *res;
8569 	int			ntups;
8570 	int			i;
8571 	PQExpBuffer query;
8572 	TSTemplateInfo *tmplinfo;
8573 	int			i_tableoid;
8574 	int			i_oid;
8575 	int			i_tmplname;
8576 	int			i_tmplnamespace;
8577 	int			i_tmplinit;
8578 	int			i_tmpllexize;
8579 
8580 	/* Before 8.3, there is no built-in text search support */
8581 	if (fout->remoteVersion < 80300)
8582 	{
8583 		*numTSTemplates = 0;
8584 		return NULL;
8585 	}
8586 
8587 	query = createPQExpBuffer();
8588 
8589 	appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8590 						 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8591 						 "FROM pg_ts_template");
8592 
8593 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8594 
8595 	ntups = PQntuples(res);
8596 	*numTSTemplates = ntups;
8597 
8598 	tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8599 
8600 	i_tableoid = PQfnumber(res, "tableoid");
8601 	i_oid = PQfnumber(res, "oid");
8602 	i_tmplname = PQfnumber(res, "tmplname");
8603 	i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8604 	i_tmplinit = PQfnumber(res, "tmplinit");
8605 	i_tmpllexize = PQfnumber(res, "tmpllexize");
8606 
8607 	for (i = 0; i < ntups; i++)
8608 	{
8609 		tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8610 		tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8611 		tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8612 		AssignDumpId(&tmplinfo[i].dobj);
8613 		tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8614 		tmplinfo[i].dobj.namespace =
8615 			findNamespace(fout,
8616 						  atooid(PQgetvalue(res, i, i_tmplnamespace)),
8617 						  tmplinfo[i].dobj.catId.oid);
8618 		tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8619 		tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8620 
8621 		/* Decide whether we want to dump it */
8622 		selectDumpableObject(&(tmplinfo[i].dobj), fout);
8623 
8624 		/* Text Search Templates do not currently have ACLs. */
8625 		tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8626 	}
8627 
8628 	PQclear(res);
8629 
8630 	destroyPQExpBuffer(query);
8631 
8632 	return tmplinfo;
8633 }
8634 
8635 /*
8636  * getTSConfigurations:
8637  *	  read all text search configurations in the system catalogs and return
8638  *	  them in the TSConfigInfo* structure
8639  *
8640  *	numTSConfigs is set to the number of configurations read in
8641  */
8642 TSConfigInfo *
getTSConfigurations(Archive * fout,int * numTSConfigs)8643 getTSConfigurations(Archive *fout, int *numTSConfigs)
8644 {
8645 	PGresult   *res;
8646 	int			ntups;
8647 	int			i;
8648 	PQExpBuffer query;
8649 	TSConfigInfo *cfginfo;
8650 	int			i_tableoid;
8651 	int			i_oid;
8652 	int			i_cfgname;
8653 	int			i_cfgnamespace;
8654 	int			i_rolname;
8655 	int			i_cfgparser;
8656 
8657 	/* Before 8.3, there is no built-in text search support */
8658 	if (fout->remoteVersion < 80300)
8659 	{
8660 		*numTSConfigs = 0;
8661 		return NULL;
8662 	}
8663 
8664 	query = createPQExpBuffer();
8665 
8666 	appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8667 					  "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8668 					  "FROM pg_ts_config",
8669 					  username_subquery);
8670 
8671 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8672 
8673 	ntups = PQntuples(res);
8674 	*numTSConfigs = ntups;
8675 
8676 	cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8677 
8678 	i_tableoid = PQfnumber(res, "tableoid");
8679 	i_oid = PQfnumber(res, "oid");
8680 	i_cfgname = PQfnumber(res, "cfgname");
8681 	i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8682 	i_rolname = PQfnumber(res, "rolname");
8683 	i_cfgparser = PQfnumber(res, "cfgparser");
8684 
8685 	for (i = 0; i < ntups; i++)
8686 	{
8687 		cfginfo[i].dobj.objType = DO_TSCONFIG;
8688 		cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8689 		cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8690 		AssignDumpId(&cfginfo[i].dobj);
8691 		cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8692 		cfginfo[i].dobj.namespace =
8693 			findNamespace(fout,
8694 						  atooid(PQgetvalue(res, i, i_cfgnamespace)),
8695 						  cfginfo[i].dobj.catId.oid);
8696 		cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8697 		cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8698 
8699 		/* Decide whether we want to dump it */
8700 		selectDumpableObject(&(cfginfo[i].dobj), fout);
8701 
8702 		/* Text Search Configurations do not currently have ACLs. */
8703 		cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8704 	}
8705 
8706 	PQclear(res);
8707 
8708 	destroyPQExpBuffer(query);
8709 
8710 	return cfginfo;
8711 }
8712 
8713 /*
8714  * getForeignDataWrappers:
8715  *	  read all foreign-data wrappers in the system catalogs and return
8716  *	  them in the FdwInfo* structure
8717  *
8718  *	numForeignDataWrappers is set to the number of fdws read in
8719  */
8720 FdwInfo *
getForeignDataWrappers(Archive * fout,int * numForeignDataWrappers)8721 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8722 {
8723 	DumpOptions *dopt = fout->dopt;
8724 	PGresult   *res;
8725 	int			ntups;
8726 	int			i;
8727 	PQExpBuffer query;
8728 	FdwInfo    *fdwinfo;
8729 	int			i_tableoid;
8730 	int			i_oid;
8731 	int			i_fdwname;
8732 	int			i_rolname;
8733 	int			i_fdwhandler;
8734 	int			i_fdwvalidator;
8735 	int			i_fdwacl;
8736 	int			i_rfdwacl;
8737 	int			i_initfdwacl;
8738 	int			i_initrfdwacl;
8739 	int			i_fdwoptions;
8740 
8741 	/* Before 8.4, there are no foreign-data wrappers */
8742 	if (fout->remoteVersion < 80400)
8743 	{
8744 		*numForeignDataWrappers = 0;
8745 		return NULL;
8746 	}
8747 
8748 	query = createPQExpBuffer();
8749 
8750 	if (fout->remoteVersion >= 90600)
8751 	{
8752 		PQExpBuffer acl_subquery = createPQExpBuffer();
8753 		PQExpBuffer racl_subquery = createPQExpBuffer();
8754 		PQExpBuffer initacl_subquery = createPQExpBuffer();
8755 		PQExpBuffer initracl_subquery = createPQExpBuffer();
8756 
8757 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8758 						initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
8759 						dopt->binary_upgrade);
8760 
8761 		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
8762 						  "(%s f.fdwowner) AS rolname, "
8763 						  "f.fdwhandler::pg_catalog.regproc, "
8764 						  "f.fdwvalidator::pg_catalog.regproc, "
8765 						  "%s AS fdwacl, "
8766 						  "%s AS rfdwacl, "
8767 						  "%s AS initfdwacl, "
8768 						  "%s AS initrfdwacl, "
8769 						  "array_to_string(ARRAY("
8770 						  "SELECT quote_ident(option_name) || ' ' || "
8771 						  "quote_literal(option_value) "
8772 						  "FROM pg_options_to_table(f.fdwoptions) "
8773 						  "ORDER BY option_name"
8774 						  "), E',\n    ') AS fdwoptions "
8775 						  "FROM pg_foreign_data_wrapper f "
8776 						  "LEFT JOIN pg_init_privs pip ON "
8777 						  "(f.oid = pip.objoid "
8778 					"AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
8779 						  "AND pip.objsubid = 0) ",
8780 						  username_subquery,
8781 						  acl_subquery->data,
8782 						  racl_subquery->data,
8783 						  initacl_subquery->data,
8784 						  initracl_subquery->data);
8785 
8786 		destroyPQExpBuffer(acl_subquery);
8787 		destroyPQExpBuffer(racl_subquery);
8788 		destroyPQExpBuffer(initacl_subquery);
8789 		destroyPQExpBuffer(initracl_subquery);
8790 	}
8791 	else if (fout->remoteVersion >= 90100)
8792 	{
8793 		appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8794 						  "(%s fdwowner) AS rolname, "
8795 						  "fdwhandler::pg_catalog.regproc, "
8796 						  "fdwvalidator::pg_catalog.regproc, fdwacl, "
8797 						  "NULL as rfdwacl, "
8798 						  "NULL as initfdwacl, NULL AS initrfdwacl, "
8799 						  "array_to_string(ARRAY("
8800 						  "SELECT quote_ident(option_name) || ' ' || "
8801 						  "quote_literal(option_value) "
8802 						  "FROM pg_options_to_table(fdwoptions) "
8803 						  "ORDER BY option_name"
8804 						  "), E',\n    ') AS fdwoptions "
8805 						  "FROM pg_foreign_data_wrapper",
8806 						  username_subquery);
8807 	}
8808 	else
8809 	{
8810 		appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8811 						  "(%s fdwowner) AS rolname, "
8812 						  "'-' AS fdwhandler, "
8813 						  "fdwvalidator::pg_catalog.regproc, fdwacl, "
8814 						  "NULL as rfdwacl, "
8815 						  "NULL as initfdwacl, NULL AS initrfdwacl, "
8816 						  "array_to_string(ARRAY("
8817 						  "SELECT quote_ident(option_name) || ' ' || "
8818 						  "quote_literal(option_value) "
8819 						  "FROM pg_options_to_table(fdwoptions) "
8820 						  "ORDER BY option_name"
8821 						  "), E',\n    ') AS fdwoptions "
8822 						  "FROM pg_foreign_data_wrapper",
8823 						  username_subquery);
8824 	}
8825 
8826 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8827 
8828 	ntups = PQntuples(res);
8829 	*numForeignDataWrappers = ntups;
8830 
8831 	fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
8832 
8833 	i_tableoid = PQfnumber(res, "tableoid");
8834 	i_oid = PQfnumber(res, "oid");
8835 	i_fdwname = PQfnumber(res, "fdwname");
8836 	i_rolname = PQfnumber(res, "rolname");
8837 	i_fdwhandler = PQfnumber(res, "fdwhandler");
8838 	i_fdwvalidator = PQfnumber(res, "fdwvalidator");
8839 	i_fdwacl = PQfnumber(res, "fdwacl");
8840 	i_rfdwacl = PQfnumber(res, "rfdwacl");
8841 	i_initfdwacl = PQfnumber(res, "initfdwacl");
8842 	i_initrfdwacl = PQfnumber(res, "initrfdwacl");
8843 	i_fdwoptions = PQfnumber(res, "fdwoptions");
8844 
8845 	for (i = 0; i < ntups; i++)
8846 	{
8847 		fdwinfo[i].dobj.objType = DO_FDW;
8848 		fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8849 		fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8850 		AssignDumpId(&fdwinfo[i].dobj);
8851 		fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
8852 		fdwinfo[i].dobj.namespace = NULL;
8853 		fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8854 		fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
8855 		fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
8856 		fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
8857 		fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
8858 		fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
8859 		fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
8860 		fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
8861 
8862 		/* Decide whether we want to dump it */
8863 		selectDumpableObject(&(fdwinfo[i].dobj), fout);
8864 
8865 		/* Do not try to dump ACL if no ACL exists. */
8866 		if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
8867 			PQgetisnull(res, i, i_initfdwacl) &&
8868 			PQgetisnull(res, i, i_initrfdwacl))
8869 			fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8870 	}
8871 
8872 	PQclear(res);
8873 
8874 	destroyPQExpBuffer(query);
8875 
8876 	return fdwinfo;
8877 }
8878 
8879 /*
8880  * getForeignServers:
8881  *	  read all foreign servers in the system catalogs and return
8882  *	  them in the ForeignServerInfo * structure
8883  *
8884  *	numForeignServers is set to the number of servers read in
8885  */
8886 ForeignServerInfo *
getForeignServers(Archive * fout,int * numForeignServers)8887 getForeignServers(Archive *fout, int *numForeignServers)
8888 {
8889 	DumpOptions *dopt = fout->dopt;
8890 	PGresult   *res;
8891 	int			ntups;
8892 	int			i;
8893 	PQExpBuffer query;
8894 	ForeignServerInfo *srvinfo;
8895 	int			i_tableoid;
8896 	int			i_oid;
8897 	int			i_srvname;
8898 	int			i_rolname;
8899 	int			i_srvfdw;
8900 	int			i_srvtype;
8901 	int			i_srvversion;
8902 	int			i_srvacl;
8903 	int			i_rsrvacl;
8904 	int			i_initsrvacl;
8905 	int			i_initrsrvacl;
8906 	int			i_srvoptions;
8907 
8908 	/* Before 8.4, there are no foreign servers */
8909 	if (fout->remoteVersion < 80400)
8910 	{
8911 		*numForeignServers = 0;
8912 		return NULL;
8913 	}
8914 
8915 	query = createPQExpBuffer();
8916 
8917 	if (fout->remoteVersion >= 90600)
8918 	{
8919 		PQExpBuffer acl_subquery = createPQExpBuffer();
8920 		PQExpBuffer racl_subquery = createPQExpBuffer();
8921 		PQExpBuffer initacl_subquery = createPQExpBuffer();
8922 		PQExpBuffer initracl_subquery = createPQExpBuffer();
8923 
8924 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8925 						initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
8926 						dopt->binary_upgrade);
8927 
8928 		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
8929 						  "(%s f.srvowner) AS rolname, "
8930 						  "f.srvfdw, f.srvtype, f.srvversion, "
8931 						  "%s AS srvacl, "
8932 						  "%s AS rsrvacl, "
8933 						  "%s AS initsrvacl, "
8934 						  "%s AS initrsrvacl, "
8935 						  "array_to_string(ARRAY("
8936 						  "SELECT quote_ident(option_name) || ' ' || "
8937 						  "quote_literal(option_value) "
8938 						  "FROM pg_options_to_table(f.srvoptions) "
8939 						  "ORDER BY option_name"
8940 						  "), E',\n    ') AS srvoptions "
8941 						  "FROM pg_foreign_server f "
8942 						  "LEFT JOIN pg_init_privs pip "
8943 						  "ON (f.oid = pip.objoid "
8944 						  "AND pip.classoid = 'pg_foreign_server'::regclass "
8945 						  "AND pip.objsubid = 0) ",
8946 						  username_subquery,
8947 						  acl_subquery->data,
8948 						  racl_subquery->data,
8949 						  initacl_subquery->data,
8950 						  initracl_subquery->data);
8951 
8952 		destroyPQExpBuffer(acl_subquery);
8953 		destroyPQExpBuffer(racl_subquery);
8954 		destroyPQExpBuffer(initacl_subquery);
8955 		destroyPQExpBuffer(initracl_subquery);
8956 	}
8957 	else
8958 	{
8959 		appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
8960 						  "(%s srvowner) AS rolname, "
8961 						  "srvfdw, srvtype, srvversion, srvacl, "
8962 						  "NULL AS rsrvacl, "
8963 						  "NULL AS initsrvacl, NULL AS initrsrvacl, "
8964 						  "array_to_string(ARRAY("
8965 						  "SELECT quote_ident(option_name) || ' ' || "
8966 						  "quote_literal(option_value) "
8967 						  "FROM pg_options_to_table(srvoptions) "
8968 						  "ORDER BY option_name"
8969 						  "), E',\n    ') AS srvoptions "
8970 						  "FROM pg_foreign_server",
8971 						  username_subquery);
8972 	}
8973 
8974 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8975 
8976 	ntups = PQntuples(res);
8977 	*numForeignServers = ntups;
8978 
8979 	srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
8980 
8981 	i_tableoid = PQfnumber(res, "tableoid");
8982 	i_oid = PQfnumber(res, "oid");
8983 	i_srvname = PQfnumber(res, "srvname");
8984 	i_rolname = PQfnumber(res, "rolname");
8985 	i_srvfdw = PQfnumber(res, "srvfdw");
8986 	i_srvtype = PQfnumber(res, "srvtype");
8987 	i_srvversion = PQfnumber(res, "srvversion");
8988 	i_srvacl = PQfnumber(res, "srvacl");
8989 	i_rsrvacl = PQfnumber(res, "rsrvacl");
8990 	i_initsrvacl = PQfnumber(res, "initsrvacl");
8991 	i_initrsrvacl = PQfnumber(res, "initrsrvacl");
8992 	i_srvoptions = PQfnumber(res, "srvoptions");
8993 
8994 	for (i = 0; i < ntups; i++)
8995 	{
8996 		srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
8997 		srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8998 		srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8999 		AssignDumpId(&srvinfo[i].dobj);
9000 		srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9001 		srvinfo[i].dobj.namespace = NULL;
9002 		srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9003 		srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9004 		srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9005 		srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9006 		srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9007 		srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9008 		srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9009 		srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9010 		srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9011 
9012 		/* Decide whether we want to dump it */
9013 		selectDumpableObject(&(srvinfo[i].dobj), fout);
9014 
9015 		/* Do not try to dump ACL if no ACL exists. */
9016 		if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9017 			PQgetisnull(res, i, i_initsrvacl) &&
9018 			PQgetisnull(res, i, i_initrsrvacl))
9019 			srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9020 	}
9021 
9022 	PQclear(res);
9023 
9024 	destroyPQExpBuffer(query);
9025 
9026 	return srvinfo;
9027 }
9028 
9029 /*
9030  * getDefaultACLs:
9031  *	  read all default ACL information in the system catalogs and return
9032  *	  them in the DefaultACLInfo structure
9033  *
9034  *	numDefaultACLs is set to the number of ACLs read in
9035  */
9036 DefaultACLInfo *
getDefaultACLs(Archive * fout,int * numDefaultACLs)9037 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9038 {
9039 	DumpOptions *dopt = fout->dopt;
9040 	DefaultACLInfo *daclinfo;
9041 	PQExpBuffer query;
9042 	PGresult   *res;
9043 	int			i_oid;
9044 	int			i_tableoid;
9045 	int			i_defaclrole;
9046 	int			i_defaclnamespace;
9047 	int			i_defaclobjtype;
9048 	int			i_defaclacl;
9049 	int			i_rdefaclacl;
9050 	int			i_initdefaclacl;
9051 	int			i_initrdefaclacl;
9052 	int			i,
9053 				ntups;
9054 
9055 	if (fout->remoteVersion < 90000)
9056 	{
9057 		*numDefaultACLs = 0;
9058 		return NULL;
9059 	}
9060 
9061 	query = createPQExpBuffer();
9062 
9063 	if (fout->remoteVersion >= 90600)
9064 	{
9065 		PQExpBuffer acl_subquery = createPQExpBuffer();
9066 		PQExpBuffer racl_subquery = createPQExpBuffer();
9067 		PQExpBuffer initacl_subquery = createPQExpBuffer();
9068 		PQExpBuffer initracl_subquery = createPQExpBuffer();
9069 
9070 		/*
9071 		 * Global entries (with defaclnamespace=0) replace the hard-wired
9072 		 * default ACL for their object type.  We should dump them as deltas
9073 		 * from the default ACL, since that will be used as a starting point
9074 		 * for interpreting the ALTER DEFAULT PRIVILEGES commands.  On the
9075 		 * other hand, non-global entries can only add privileges not revoke
9076 		 * them.  We must dump those as-is (i.e., as deltas from an empty
9077 		 * ACL).  We implement that by passing NULL as the object type for
9078 		 * acldefault(), which works because acldefault() is STRICT.
9079 		 *
9080 		 * We can use defaclobjtype as the object type for acldefault(),
9081 		 * except for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be
9082 		 * converted to 's'.
9083 		 */
9084 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9085 						initracl_subquery, "defaclacl", "defaclrole",
9086 						"CASE WHEN defaclnamespace = 0 THEN"
9087 						"	  CASE WHEN defaclobjtype = 'S' THEN 's'::\"char\""
9088 						"	  ELSE defaclobjtype END "
9089 						"ELSE NULL END",
9090 						dopt->binary_upgrade);
9091 
9092 		appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9093 						  "(%s d.defaclrole) AS defaclrole, "
9094 						  "d.defaclnamespace, "
9095 						  "d.defaclobjtype, "
9096 						  "%s AS defaclacl, "
9097 						  "%s AS rdefaclacl, "
9098 						  "%s AS initdefaclacl, "
9099 						  "%s AS initrdefaclacl "
9100 						  "FROM pg_default_acl d "
9101 						  "LEFT JOIN pg_init_privs pip ON "
9102 						  "(d.oid = pip.objoid "
9103 						  "AND pip.classoid = 'pg_default_acl'::regclass "
9104 						  "AND pip.objsubid = 0) ",
9105 						  username_subquery,
9106 						  acl_subquery->data,
9107 						  racl_subquery->data,
9108 						  initacl_subquery->data,
9109 						  initracl_subquery->data);
9110 
9111 		destroyPQExpBuffer(acl_subquery);
9112 		destroyPQExpBuffer(racl_subquery);
9113 		destroyPQExpBuffer(initacl_subquery);
9114 		destroyPQExpBuffer(initracl_subquery);
9115 	}
9116 	else
9117 	{
9118 		appendPQExpBuffer(query, "SELECT oid, tableoid, "
9119 						  "(%s defaclrole) AS defaclrole, "
9120 						  "defaclnamespace, "
9121 						  "defaclobjtype, "
9122 						  "defaclacl, "
9123 						  "NULL AS rdefaclacl, "
9124 						  "NULL AS initdefaclacl, "
9125 						  "NULL AS initrdefaclacl "
9126 						  "FROM pg_default_acl",
9127 						  username_subquery);
9128 	}
9129 
9130 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9131 
9132 	ntups = PQntuples(res);
9133 	*numDefaultACLs = ntups;
9134 
9135 	daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9136 
9137 	i_oid = PQfnumber(res, "oid");
9138 	i_tableoid = PQfnumber(res, "tableoid");
9139 	i_defaclrole = PQfnumber(res, "defaclrole");
9140 	i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9141 	i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9142 	i_defaclacl = PQfnumber(res, "defaclacl");
9143 	i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9144 	i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9145 	i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9146 
9147 	for (i = 0; i < ntups; i++)
9148 	{
9149 		Oid			nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9150 
9151 		daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9152 		daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9153 		daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9154 		AssignDumpId(&daclinfo[i].dobj);
9155 		/* cheesy ... is it worth coming up with a better object name? */
9156 		daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9157 
9158 		if (nspid != InvalidOid)
9159 			daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
9160 												 daclinfo[i].dobj.catId.oid);
9161 		else
9162 			daclinfo[i].dobj.namespace = NULL;
9163 
9164 		daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9165 		daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9166 		daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9167 		daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9168 		daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9169 		daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9170 
9171 		/* Decide whether we want to dump it */
9172 		selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9173 	}
9174 
9175 	PQclear(res);
9176 
9177 	destroyPQExpBuffer(query);
9178 
9179 	return daclinfo;
9180 }
9181 
9182 /*
9183  * dumpComment --
9184  *
9185  * This routine is used to dump any comments associated with the
9186  * object handed to this routine. The routine takes the object type
9187  * and object name (ready to print, except for schema decoration), plus
9188  * the namespace and owner of the object (for labeling the ArchiveEntry),
9189  * plus catalog ID and subid which are the lookup key for pg_description,
9190  * plus the dump ID for the object (for setting a dependency).
9191  * If a matching pg_description entry is found, it is dumped.
9192  *
9193  * Note: in some cases, such as comments for triggers and rules, the "type"
9194  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9195  * but it doesn't seem worth complicating the API for all callers to make
9196  * it cleaner.
9197  *
9198  * Note: although this routine takes a dumpId for dependency purposes,
9199  * that purpose is just to mark the dependency in the emitted dump file
9200  * for possible future use by pg_restore.  We do NOT use it for determining
9201  * ordering of the comment in the dump file, because this routine is called
9202  * after dependency sorting occurs.  This routine should be called just after
9203  * calling ArchiveEntry() for the specified object.
9204  */
9205 static void
dumpComment(Archive * fout,const char * type,const char * name,const char * namespace,const char * owner,CatalogId catalogId,int subid,DumpId dumpId)9206 dumpComment(Archive *fout, const char *type, const char *name,
9207 			const char *namespace, const char *owner,
9208 			CatalogId catalogId, int subid, DumpId dumpId)
9209 {
9210 	DumpOptions *dopt = fout->dopt;
9211 	CommentItem *comments;
9212 	int			ncomments;
9213 
9214 	/* Comments are schema not data ... except blob comments are data */
9215 	if (strcmp(type, "LARGE OBJECT") != 0)
9216 	{
9217 		if (dopt->dataOnly)
9218 			return;
9219 	}
9220 	else
9221 	{
9222 		/* We do dump blob comments in binary-upgrade mode */
9223 		if (dopt->schemaOnly && !dopt->binary_upgrade)
9224 			return;
9225 	}
9226 
9227 	/* Search for comments associated with catalogId, using table */
9228 	ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9229 							 &comments);
9230 
9231 	/* Is there one matching the subid? */
9232 	while (ncomments > 0)
9233 	{
9234 		if (comments->objsubid == subid)
9235 			break;
9236 		comments++;
9237 		ncomments--;
9238 	}
9239 
9240 	/* If a comment exists, build COMMENT ON statement */
9241 	if (ncomments > 0)
9242 	{
9243 		PQExpBuffer query = createPQExpBuffer();
9244 		PQExpBuffer tag = createPQExpBuffer();
9245 
9246 		appendPQExpBuffer(query, "COMMENT ON %s ", type);
9247 		if (namespace && *namespace)
9248 			appendPQExpBuffer(query, "%s.", fmtId(namespace));
9249 		appendPQExpBuffer(query, "%s IS ", name);
9250 		appendStringLiteralAH(query, comments->descr, fout);
9251 		appendPQExpBufferStr(query, ";\n");
9252 
9253 		appendPQExpBuffer(tag, "%s %s", type, name);
9254 
9255 		/*
9256 		 * We mark comments as SECTION_NONE because they really belong in the
9257 		 * same section as their parent, whether that is pre-data or
9258 		 * post-data.
9259 		 */
9260 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
9261 					 tag->data, namespace, NULL, owner,
9262 					 false, "COMMENT", SECTION_NONE,
9263 					 query->data, "", NULL,
9264 					 &(dumpId), 1,
9265 					 NULL, NULL);
9266 
9267 		destroyPQExpBuffer(query);
9268 		destroyPQExpBuffer(tag);
9269 	}
9270 }
9271 
9272 /*
9273  * dumpTableComment --
9274  *
9275  * As above, but dump comments for both the specified table (or view)
9276  * and its columns.
9277  */
9278 static void
dumpTableComment(Archive * fout,TableInfo * tbinfo,const char * reltypename)9279 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9280 				 const char *reltypename)
9281 {
9282 	DumpOptions *dopt = fout->dopt;
9283 	CommentItem *comments;
9284 	int			ncomments;
9285 	PQExpBuffer query;
9286 	PQExpBuffer tag;
9287 
9288 	/* Comments are SCHEMA not data */
9289 	if (dopt->dataOnly)
9290 		return;
9291 
9292 	/* Search for comments associated with relation, using table */
9293 	ncomments = findComments(fout,
9294 							 tbinfo->dobj.catId.tableoid,
9295 							 tbinfo->dobj.catId.oid,
9296 							 &comments);
9297 
9298 	/* If comments exist, build COMMENT ON statements */
9299 	if (ncomments <= 0)
9300 		return;
9301 
9302 	query = createPQExpBuffer();
9303 	tag = createPQExpBuffer();
9304 
9305 	while (ncomments > 0)
9306 	{
9307 		const char *descr = comments->descr;
9308 		int			objsubid = comments->objsubid;
9309 
9310 		if (objsubid == 0)
9311 		{
9312 			resetPQExpBuffer(tag);
9313 			appendPQExpBuffer(tag, "%s %s", reltypename,
9314 							  fmtId(tbinfo->dobj.name));
9315 
9316 			resetPQExpBuffer(query);
9317 			appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9318 							  fmtQualifiedDumpable(tbinfo));
9319 			appendStringLiteralAH(query, descr, fout);
9320 			appendPQExpBufferStr(query, ";\n");
9321 
9322 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
9323 						 tag->data,
9324 						 tbinfo->dobj.namespace->dobj.name,
9325 						 NULL, tbinfo->rolname,
9326 						 false, "COMMENT", SECTION_NONE,
9327 						 query->data, "", NULL,
9328 						 &(tbinfo->dobj.dumpId), 1,
9329 						 NULL, NULL);
9330 		}
9331 		else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9332 		{
9333 			resetPQExpBuffer(tag);
9334 			appendPQExpBuffer(tag, "COLUMN %s.",
9335 							  fmtId(tbinfo->dobj.name));
9336 			appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9337 
9338 			resetPQExpBuffer(query);
9339 			appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9340 							  fmtQualifiedDumpable(tbinfo));
9341 			appendPQExpBuffer(query, "%s IS ",
9342 							  fmtId(tbinfo->attnames[objsubid - 1]));
9343 			appendStringLiteralAH(query, descr, fout);
9344 			appendPQExpBufferStr(query, ";\n");
9345 
9346 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
9347 						 tag->data,
9348 						 tbinfo->dobj.namespace->dobj.name,
9349 						 NULL, tbinfo->rolname,
9350 						 false, "COMMENT", SECTION_NONE,
9351 						 query->data, "", NULL,
9352 						 &(tbinfo->dobj.dumpId), 1,
9353 						 NULL, NULL);
9354 		}
9355 
9356 		comments++;
9357 		ncomments--;
9358 	}
9359 
9360 	destroyPQExpBuffer(query);
9361 	destroyPQExpBuffer(tag);
9362 }
9363 
9364 /*
9365  * findComments --
9366  *
9367  * Find the comment(s), if any, associated with the given object.  All the
9368  * objsubid values associated with the given classoid/objoid are found with
9369  * one search.
9370  */
9371 static int
findComments(Archive * fout,Oid classoid,Oid objoid,CommentItem ** items)9372 findComments(Archive *fout, Oid classoid, Oid objoid,
9373 			 CommentItem **items)
9374 {
9375 	/* static storage for table of comments */
9376 	static CommentItem *comments = NULL;
9377 	static int	ncomments = -1;
9378 
9379 	CommentItem *middle = NULL;
9380 	CommentItem *low;
9381 	CommentItem *high;
9382 	int			nmatch;
9383 
9384 	/* Get comments if we didn't already */
9385 	if (ncomments < 0)
9386 		ncomments = collectComments(fout, &comments);
9387 
9388 	/*
9389 	 * Pre-7.2, pg_description does not contain classoid, so collectComments
9390 	 * just stores a zero.  If there's a collision on object OID, well, you
9391 	 * get duplicate comments.
9392 	 */
9393 	if (fout->remoteVersion < 70200)
9394 		classoid = 0;
9395 
9396 	/*
9397 	 * Do binary search to find some item matching the object.
9398 	 */
9399 	low = &comments[0];
9400 	high = &comments[ncomments - 1];
9401 	while (low <= high)
9402 	{
9403 		middle = low + (high - low) / 2;
9404 
9405 		if (classoid < middle->classoid)
9406 			high = middle - 1;
9407 		else if (classoid > middle->classoid)
9408 			low = middle + 1;
9409 		else if (objoid < middle->objoid)
9410 			high = middle - 1;
9411 		else if (objoid > middle->objoid)
9412 			low = middle + 1;
9413 		else
9414 			break;				/* found a match */
9415 	}
9416 
9417 	if (low > high)				/* no matches */
9418 	{
9419 		*items = NULL;
9420 		return 0;
9421 	}
9422 
9423 	/*
9424 	 * Now determine how many items match the object.  The search loop
9425 	 * invariant still holds: only items between low and high inclusive could
9426 	 * match.
9427 	 */
9428 	nmatch = 1;
9429 	while (middle > low)
9430 	{
9431 		if (classoid != middle[-1].classoid ||
9432 			objoid != middle[-1].objoid)
9433 			break;
9434 		middle--;
9435 		nmatch++;
9436 	}
9437 
9438 	*items = middle;
9439 
9440 	middle += nmatch;
9441 	while (middle <= high)
9442 	{
9443 		if (classoid != middle->classoid ||
9444 			objoid != middle->objoid)
9445 			break;
9446 		middle++;
9447 		nmatch++;
9448 	}
9449 
9450 	return nmatch;
9451 }
9452 
9453 /*
9454  * collectComments --
9455  *
9456  * Construct a table of all comments available for database objects.
9457  * We used to do per-object queries for the comments, but it's much faster
9458  * to pull them all over at once, and on most databases the memory cost
9459  * isn't high.
9460  *
9461  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9462  */
9463 static int
collectComments(Archive * fout,CommentItem ** items)9464 collectComments(Archive *fout, CommentItem **items)
9465 {
9466 	PGresult   *res;
9467 	PQExpBuffer query;
9468 	int			i_description;
9469 	int			i_classoid;
9470 	int			i_objoid;
9471 	int			i_objsubid;
9472 	int			ntups;
9473 	int			i;
9474 	CommentItem *comments;
9475 
9476 	query = createPQExpBuffer();
9477 
9478 	if (fout->remoteVersion >= 70300)
9479 	{
9480 		appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9481 							 "FROM pg_catalog.pg_description "
9482 							 "ORDER BY classoid, objoid, objsubid");
9483 	}
9484 	else if (fout->remoteVersion >= 70200)
9485 	{
9486 		appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9487 							 "FROM pg_description "
9488 							 "ORDER BY classoid, objoid, objsubid");
9489 	}
9490 	else
9491 	{
9492 		/* Note: this will fail to find attribute comments in pre-7.2... */
9493 		appendPQExpBufferStr(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
9494 							 "FROM pg_description "
9495 							 "ORDER BY objoid");
9496 	}
9497 
9498 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9499 
9500 	/* Construct lookup table containing OIDs in numeric form */
9501 
9502 	i_description = PQfnumber(res, "description");
9503 	i_classoid = PQfnumber(res, "classoid");
9504 	i_objoid = PQfnumber(res, "objoid");
9505 	i_objsubid = PQfnumber(res, "objsubid");
9506 
9507 	ntups = PQntuples(res);
9508 
9509 	comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9510 
9511 	for (i = 0; i < ntups; i++)
9512 	{
9513 		comments[i].descr = PQgetvalue(res, i, i_description);
9514 		comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9515 		comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9516 		comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9517 	}
9518 
9519 	/* Do NOT free the PGresult since we are keeping pointers into it */
9520 	destroyPQExpBuffer(query);
9521 
9522 	*items = comments;
9523 	return ntups;
9524 }
9525 
9526 /*
9527  * dumpDumpableObject
9528  *
9529  * This routine and its subsidiaries are responsible for creating
9530  * ArchiveEntries (TOC objects) for each object to be dumped.
9531  */
9532 static void
dumpDumpableObject(Archive * fout,DumpableObject * dobj)9533 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9534 {
9535 	switch (dobj->objType)
9536 	{
9537 		case DO_NAMESPACE:
9538 			dumpNamespace(fout, (NamespaceInfo *) dobj);
9539 			break;
9540 		case DO_EXTENSION:
9541 			dumpExtension(fout, (ExtensionInfo *) dobj);
9542 			break;
9543 		case DO_TYPE:
9544 			dumpType(fout, (TypeInfo *) dobj);
9545 			break;
9546 		case DO_SHELL_TYPE:
9547 			dumpShellType(fout, (ShellTypeInfo *) dobj);
9548 			break;
9549 		case DO_FUNC:
9550 			dumpFunc(fout, (FuncInfo *) dobj);
9551 			break;
9552 		case DO_AGG:
9553 			dumpAgg(fout, (AggInfo *) dobj);
9554 			break;
9555 		case DO_OPERATOR:
9556 			dumpOpr(fout, (OprInfo *) dobj);
9557 			break;
9558 		case DO_ACCESS_METHOD:
9559 			dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9560 			break;
9561 		case DO_OPCLASS:
9562 			dumpOpclass(fout, (OpclassInfo *) dobj);
9563 			break;
9564 		case DO_OPFAMILY:
9565 			dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9566 			break;
9567 		case DO_COLLATION:
9568 			dumpCollation(fout, (CollInfo *) dobj);
9569 			break;
9570 		case DO_CONVERSION:
9571 			dumpConversion(fout, (ConvInfo *) dobj);
9572 			break;
9573 		case DO_TABLE:
9574 			dumpTable(fout, (TableInfo *) dobj);
9575 			break;
9576 		case DO_ATTRDEF:
9577 			dumpAttrDef(fout, (AttrDefInfo *) dobj);
9578 			break;
9579 		case DO_INDEX:
9580 			dumpIndex(fout, (IndxInfo *) dobj);
9581 			break;
9582 		case DO_REFRESH_MATVIEW:
9583 			refreshMatViewData(fout, (TableDataInfo *) dobj);
9584 			break;
9585 		case DO_RULE:
9586 			dumpRule(fout, (RuleInfo *) dobj);
9587 			break;
9588 		case DO_TRIGGER:
9589 			dumpTrigger(fout, (TriggerInfo *) dobj);
9590 			break;
9591 		case DO_EVENT_TRIGGER:
9592 			dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9593 			break;
9594 		case DO_CONSTRAINT:
9595 			dumpConstraint(fout, (ConstraintInfo *) dobj);
9596 			break;
9597 		case DO_FK_CONSTRAINT:
9598 			dumpConstraint(fout, (ConstraintInfo *) dobj);
9599 			break;
9600 		case DO_PROCLANG:
9601 			dumpProcLang(fout, (ProcLangInfo *) dobj);
9602 			break;
9603 		case DO_CAST:
9604 			dumpCast(fout, (CastInfo *) dobj);
9605 			break;
9606 		case DO_TRANSFORM:
9607 			dumpTransform(fout, (TransformInfo *) dobj);
9608 			break;
9609 		case DO_TABLE_DATA:
9610 			if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
9611 				dumpSequenceData(fout, (TableDataInfo *) dobj);
9612 			else
9613 				dumpTableData(fout, (TableDataInfo *) dobj);
9614 			break;
9615 		case DO_DUMMY_TYPE:
9616 			/* table rowtypes and array types are never dumped separately */
9617 			break;
9618 		case DO_TSPARSER:
9619 			dumpTSParser(fout, (TSParserInfo *) dobj);
9620 			break;
9621 		case DO_TSDICT:
9622 			dumpTSDictionary(fout, (TSDictInfo *) dobj);
9623 			break;
9624 		case DO_TSTEMPLATE:
9625 			dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9626 			break;
9627 		case DO_TSCONFIG:
9628 			dumpTSConfig(fout, (TSConfigInfo *) dobj);
9629 			break;
9630 		case DO_FDW:
9631 			dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9632 			break;
9633 		case DO_FOREIGN_SERVER:
9634 			dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9635 			break;
9636 		case DO_DEFAULT_ACL:
9637 			dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9638 			break;
9639 		case DO_BLOB:
9640 			dumpBlob(fout, (BlobInfo *) dobj);
9641 			break;
9642 		case DO_BLOB_DATA:
9643 			if (dobj->dump & DUMP_COMPONENT_DATA)
9644 				ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9645 							 dobj->name, NULL, NULL, "",
9646 							 false, "BLOBS", SECTION_DATA,
9647 							 "", "", NULL,
9648 							 NULL, 0,
9649 							 dumpBlobs, NULL);
9650 			break;
9651 		case DO_POLICY:
9652 			dumpPolicy(fout, (PolicyInfo *) dobj);
9653 			break;
9654 		case DO_PRE_DATA_BOUNDARY:
9655 		case DO_POST_DATA_BOUNDARY:
9656 			/* never dumped, nothing to do */
9657 			break;
9658 	}
9659 }
9660 
9661 /*
9662  * dumpNamespace
9663  *	  writes out to fout the queries to recreate a user-defined namespace
9664  */
9665 static void
dumpNamespace(Archive * fout,NamespaceInfo * nspinfo)9666 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9667 {
9668 	DumpOptions *dopt = fout->dopt;
9669 	PQExpBuffer q;
9670 	PQExpBuffer delq;
9671 	char	   *qnspname;
9672 
9673 	/* Skip if not to be dumped */
9674 	if (!nspinfo->dobj.dump || dopt->dataOnly)
9675 		return;
9676 
9677 	/* don't dump dummy namespace from pre-7.3 source */
9678 	if (strlen(nspinfo->dobj.name) == 0)
9679 		return;
9680 
9681 	q = createPQExpBuffer();
9682 	delq = createPQExpBuffer();
9683 
9684 	qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9685 
9686 	appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9687 
9688 	appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9689 
9690 	if (dopt->binary_upgrade)
9691 		binary_upgrade_extension_member(q, &nspinfo->dobj,
9692 										"SCHEMA", qnspname, NULL);
9693 
9694 	if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9695 		ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9696 					 nspinfo->dobj.name,
9697 					 NULL, NULL,
9698 					 nspinfo->rolname,
9699 					 false, "SCHEMA", SECTION_PRE_DATA,
9700 					 q->data, delq->data, NULL,
9701 					 NULL, 0,
9702 					 NULL, NULL);
9703 
9704 	/* Dump Schema Comments and Security Labels */
9705 	if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9706 		dumpComment(fout, "SCHEMA", qnspname,
9707 					NULL, nspinfo->rolname,
9708 					nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9709 
9710 	if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9711 		dumpSecLabel(fout, "SCHEMA", qnspname,
9712 					 NULL, nspinfo->rolname,
9713 					 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9714 
9715 	if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9716 		dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
9717 				qnspname, NULL, NULL,
9718 				nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9719 				nspinfo->initnspacl, nspinfo->initrnspacl);
9720 
9721 	free(qnspname);
9722 
9723 	destroyPQExpBuffer(q);
9724 	destroyPQExpBuffer(delq);
9725 }
9726 
9727 /*
9728  * dumpExtension
9729  *	  writes out to fout the queries to recreate an extension
9730  */
9731 static void
dumpExtension(Archive * fout,ExtensionInfo * extinfo)9732 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
9733 {
9734 	DumpOptions *dopt = fout->dopt;
9735 	PQExpBuffer q;
9736 	PQExpBuffer delq;
9737 	char	   *qextname;
9738 
9739 	/* Skip if not to be dumped */
9740 	if (!extinfo->dobj.dump || dopt->dataOnly)
9741 		return;
9742 
9743 	q = createPQExpBuffer();
9744 	delq = createPQExpBuffer();
9745 
9746 	qextname = pg_strdup(fmtId(extinfo->dobj.name));
9747 
9748 	appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
9749 
9750 	if (!dopt->binary_upgrade)
9751 	{
9752 		/*
9753 		 * In a regular dump, we use IF NOT EXISTS so that there isn't a
9754 		 * problem if the extension already exists in the target database;
9755 		 * this is essential for installed-by-default extensions such as
9756 		 * plpgsql.
9757 		 *
9758 		 * In binary-upgrade mode, that doesn't work well, so instead we skip
9759 		 * built-in extensions based on their OIDs; see
9760 		 * selectDumpableExtension.
9761 		 */
9762 		appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
9763 						  qextname, fmtId(extinfo->namespace));
9764 	}
9765 	else
9766 	{
9767 		int			i;
9768 		int			n;
9769 
9770 		appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
9771 
9772 		/*
9773 		 * We unconditionally create the extension, so we must drop it if it
9774 		 * exists.  This could happen if the user deleted 'plpgsql' and then
9775 		 * readded it, causing its oid to be greater than g_last_builtin_oid.
9776 		 * The g_last_builtin_oid test was kept to avoid repeatedly dropping
9777 		 * and recreating extensions like 'plpgsql'.
9778 		 */
9779 		appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
9780 
9781 		appendPQExpBufferStr(q,
9782 				 "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
9783 		appendStringLiteralAH(q, extinfo->dobj.name, fout);
9784 		appendPQExpBufferStr(q, ", ");
9785 		appendStringLiteralAH(q, extinfo->namespace, fout);
9786 		appendPQExpBufferStr(q, ", ");
9787 		appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
9788 		appendStringLiteralAH(q, extinfo->extversion, fout);
9789 		appendPQExpBufferStr(q, ", ");
9790 
9791 		/*
9792 		 * Note that we're pushing extconfig (an OID array) back into
9793 		 * pg_extension exactly as-is.  This is OK because pg_class OIDs are
9794 		 * preserved in binary upgrade.
9795 		 */
9796 		if (strlen(extinfo->extconfig) > 2)
9797 			appendStringLiteralAH(q, extinfo->extconfig, fout);
9798 		else
9799 			appendPQExpBufferStr(q, "NULL");
9800 		appendPQExpBufferStr(q, ", ");
9801 		if (strlen(extinfo->extcondition) > 2)
9802 			appendStringLiteralAH(q, extinfo->extcondition, fout);
9803 		else
9804 			appendPQExpBufferStr(q, "NULL");
9805 		appendPQExpBufferStr(q, ", ");
9806 		appendPQExpBufferStr(q, "ARRAY[");
9807 		n = 0;
9808 		for (i = 0; i < extinfo->dobj.nDeps; i++)
9809 		{
9810 			DumpableObject *extobj;
9811 
9812 			extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
9813 			if (extobj && extobj->objType == DO_EXTENSION)
9814 			{
9815 				if (n++ > 0)
9816 					appendPQExpBufferChar(q, ',');
9817 				appendStringLiteralAH(q, extobj->name, fout);
9818 			}
9819 		}
9820 		appendPQExpBufferStr(q, "]::pg_catalog.text[]");
9821 		appendPQExpBufferStr(q, ");\n");
9822 	}
9823 
9824 	if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9825 		ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
9826 					 extinfo->dobj.name,
9827 					 NULL, NULL,
9828 					 "",
9829 					 false, "EXTENSION", SECTION_PRE_DATA,
9830 					 q->data, delq->data, NULL,
9831 					 NULL, 0,
9832 					 NULL, NULL);
9833 
9834 	/* Dump Extension Comments and Security Labels */
9835 	if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9836 		dumpComment(fout, "EXTENSION", qextname,
9837 					NULL, "",
9838 					extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9839 
9840 	if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9841 		dumpSecLabel(fout, "EXTENSION", qextname,
9842 					 NULL, "",
9843 					 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9844 
9845 	free(qextname);
9846 
9847 	destroyPQExpBuffer(q);
9848 	destroyPQExpBuffer(delq);
9849 }
9850 
9851 /*
9852  * dumpType
9853  *	  writes out to fout the queries to recreate a user-defined type
9854  */
9855 static void
dumpType(Archive * fout,TypeInfo * tyinfo)9856 dumpType(Archive *fout, TypeInfo *tyinfo)
9857 {
9858 	DumpOptions *dopt = fout->dopt;
9859 
9860 	/* Skip if not to be dumped */
9861 	if (!tyinfo->dobj.dump || dopt->dataOnly)
9862 		return;
9863 
9864 	/* Dump out in proper style */
9865 	if (tyinfo->typtype == TYPTYPE_BASE)
9866 		dumpBaseType(fout, tyinfo);
9867 	else if (tyinfo->typtype == TYPTYPE_DOMAIN)
9868 		dumpDomain(fout, tyinfo);
9869 	else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
9870 		dumpCompositeType(fout, tyinfo);
9871 	else if (tyinfo->typtype == TYPTYPE_ENUM)
9872 		dumpEnumType(fout, tyinfo);
9873 	else if (tyinfo->typtype == TYPTYPE_RANGE)
9874 		dumpRangeType(fout, tyinfo);
9875 	else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
9876 		dumpUndefinedType(fout, tyinfo);
9877 	else
9878 		write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
9879 				  tyinfo->dobj.name);
9880 }
9881 
9882 /*
9883  * dumpEnumType
9884  *	  writes out to fout the queries to recreate a user-defined enum type
9885  */
9886 static void
dumpEnumType(Archive * fout,TypeInfo * tyinfo)9887 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
9888 {
9889 	DumpOptions *dopt = fout->dopt;
9890 	PQExpBuffer q = createPQExpBuffer();
9891 	PQExpBuffer delq = createPQExpBuffer();
9892 	PQExpBuffer query = createPQExpBuffer();
9893 	PGresult   *res;
9894 	int			num,
9895 				i;
9896 	Oid			enum_oid;
9897 	char	   *qtypname;
9898 	char	   *qualtypname;
9899 	char	   *label;
9900 
9901 	if (fout->remoteVersion >= 90100)
9902 		appendPQExpBuffer(query, "SELECT oid, enumlabel "
9903 						  "FROM pg_catalog.pg_enum "
9904 						  "WHERE enumtypid = '%u'"
9905 						  "ORDER BY enumsortorder",
9906 						  tyinfo->dobj.catId.oid);
9907 	else
9908 		appendPQExpBuffer(query, "SELECT oid, enumlabel "
9909 						  "FROM pg_catalog.pg_enum "
9910 						  "WHERE enumtypid = '%u'"
9911 						  "ORDER BY oid",
9912 						  tyinfo->dobj.catId.oid);
9913 
9914 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9915 
9916 	num = PQntuples(res);
9917 
9918 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
9919 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
9920 
9921 	/*
9922 	 * CASCADE shouldn't be required here as for normal types since the I/O
9923 	 * functions are generic and do not get dropped.
9924 	 */
9925 	appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
9926 
9927 	if (dopt->binary_upgrade)
9928 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
9929 												 tyinfo->dobj.catId.oid);
9930 
9931 	appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
9932 					  qualtypname);
9933 
9934 	if (!dopt->binary_upgrade)
9935 	{
9936 		/* Labels with server-assigned oids */
9937 		for (i = 0; i < num; i++)
9938 		{
9939 			label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
9940 			if (i > 0)
9941 				appendPQExpBufferChar(q, ',');
9942 			appendPQExpBufferStr(q, "\n    ");
9943 			appendStringLiteralAH(q, label, fout);
9944 		}
9945 	}
9946 
9947 	appendPQExpBufferStr(q, "\n);\n");
9948 
9949 	if (dopt->binary_upgrade)
9950 	{
9951 		/* Labels with dump-assigned (preserved) oids */
9952 		for (i = 0; i < num; i++)
9953 		{
9954 			enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
9955 			label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
9956 
9957 			if (i == 0)
9958 				appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
9959 			appendPQExpBuffer(q,
9960 							  "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
9961 							  enum_oid);
9962 			appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
9963 			appendStringLiteralAH(q, label, fout);
9964 			appendPQExpBufferStr(q, ";\n\n");
9965 		}
9966 	}
9967 
9968 	if (dopt->binary_upgrade)
9969 		binary_upgrade_extension_member(q, &tyinfo->dobj,
9970 										"TYPE", qtypname,
9971 										tyinfo->dobj.namespace->dobj.name);
9972 
9973 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9974 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
9975 					 tyinfo->dobj.name,
9976 					 tyinfo->dobj.namespace->dobj.name,
9977 					 NULL,
9978 					 tyinfo->rolname, false,
9979 					 "TYPE", SECTION_PRE_DATA,
9980 					 q->data, delq->data, NULL,
9981 					 NULL, 0,
9982 					 NULL, NULL);
9983 
9984 	/* Dump Type Comments and Security Labels */
9985 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9986 		dumpComment(fout, "TYPE", qtypname,
9987 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9988 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9989 
9990 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9991 		dumpSecLabel(fout, "TYPE", qtypname,
9992 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9993 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9994 
9995 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
9996 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
9997 				qtypname, NULL,
9998 				tyinfo->dobj.namespace->dobj.name,
9999 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10000 				tyinfo->inittypacl, tyinfo->initrtypacl);
10001 
10002 	PQclear(res);
10003 	destroyPQExpBuffer(q);
10004 	destroyPQExpBuffer(delq);
10005 	destroyPQExpBuffer(query);
10006 	free(qtypname);
10007 	free(qualtypname);
10008 }
10009 
10010 /*
10011  * dumpRangeType
10012  *	  writes out to fout the queries to recreate a user-defined range type
10013  */
10014 static void
dumpRangeType(Archive * fout,TypeInfo * tyinfo)10015 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10016 {
10017 	DumpOptions *dopt = fout->dopt;
10018 	PQExpBuffer q = createPQExpBuffer();
10019 	PQExpBuffer delq = createPQExpBuffer();
10020 	PQExpBuffer query = createPQExpBuffer();
10021 	PGresult   *res;
10022 	Oid			collationOid;
10023 	char	   *qtypname;
10024 	char	   *qualtypname;
10025 	char	   *procname;
10026 
10027 	appendPQExpBuffer(query,
10028 			"SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10029 					  "opc.opcname AS opcname, "
10030 					  "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10031 					  "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10032 					  "opc.opcdefault, "
10033 					  "CASE WHEN rngcollation = st.typcollation THEN 0 "
10034 					  "     ELSE rngcollation END AS collation, "
10035 					  "rngcanonical, rngsubdiff "
10036 					  "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10037 					  "     pg_catalog.pg_opclass opc "
10038 					  "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10039 					  "rngtypid = '%u'",
10040 					  tyinfo->dobj.catId.oid);
10041 
10042 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
10043 
10044 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10045 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10046 
10047 	/*
10048 	 * CASCADE shouldn't be required here as for normal types since the I/O
10049 	 * functions are generic and do not get dropped.
10050 	 */
10051 	appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10052 
10053 	if (dopt->binary_upgrade)
10054 		binary_upgrade_set_type_oids_by_type_oid(fout,
10055 												 q, tyinfo->dobj.catId.oid);
10056 
10057 	appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10058 					  qualtypname);
10059 
10060 	appendPQExpBuffer(q, "\n    subtype = %s",
10061 					  PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10062 
10063 	/* print subtype_opclass only if not default for subtype */
10064 	if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10065 	{
10066 		char	   *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10067 		char	   *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10068 
10069 		appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10070 						  fmtId(nspname));
10071 		appendPQExpBufferStr(q, fmtId(opcname));
10072 	}
10073 
10074 	collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10075 	if (OidIsValid(collationOid))
10076 	{
10077 		CollInfo   *coll = findCollationByOid(collationOid);
10078 
10079 		if (coll)
10080 			appendPQExpBuffer(q, ",\n    collation = %s",
10081 							  fmtQualifiedDumpable(coll));
10082 	}
10083 
10084 	procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10085 	if (strcmp(procname, "-") != 0)
10086 		appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10087 
10088 	procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10089 	if (strcmp(procname, "-") != 0)
10090 		appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10091 
10092 	appendPQExpBufferStr(q, "\n);\n");
10093 
10094 	if (dopt->binary_upgrade)
10095 		binary_upgrade_extension_member(q, &tyinfo->dobj,
10096 										"TYPE", qtypname,
10097 										tyinfo->dobj.namespace->dobj.name);
10098 
10099 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10100 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10101 					 tyinfo->dobj.name,
10102 					 tyinfo->dobj.namespace->dobj.name,
10103 					 NULL,
10104 					 tyinfo->rolname, false,
10105 					 "TYPE", SECTION_PRE_DATA,
10106 					 q->data, delq->data, NULL,
10107 					 NULL, 0,
10108 					 NULL, NULL);
10109 
10110 	/* Dump Type Comments and Security Labels */
10111 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10112 		dumpComment(fout, "TYPE", qtypname,
10113 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10114 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10115 
10116 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10117 		dumpSecLabel(fout, "TYPE", qtypname,
10118 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10119 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10120 
10121 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10122 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10123 				qtypname, NULL,
10124 				tyinfo->dobj.namespace->dobj.name,
10125 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10126 				tyinfo->inittypacl, tyinfo->initrtypacl);
10127 
10128 	PQclear(res);
10129 	destroyPQExpBuffer(q);
10130 	destroyPQExpBuffer(delq);
10131 	destroyPQExpBuffer(query);
10132 	free(qtypname);
10133 	free(qualtypname);
10134 }
10135 
10136 /*
10137  * dumpUndefinedType
10138  *	  writes out to fout the queries to recreate a !typisdefined type
10139  *
10140  * This is a shell type, but we use different terminology to distinguish
10141  * this case from where we have to emit a shell type definition to break
10142  * circular dependencies.  An undefined type shouldn't ever have anything
10143  * depending on it.
10144  */
10145 static void
dumpUndefinedType(Archive * fout,TypeInfo * tyinfo)10146 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10147 {
10148 	DumpOptions *dopt = fout->dopt;
10149 	PQExpBuffer q = createPQExpBuffer();
10150 	PQExpBuffer delq = createPQExpBuffer();
10151 	char	   *qtypname;
10152 	char	   *qualtypname;
10153 
10154 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10155 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10156 
10157 	appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10158 
10159 	if (dopt->binary_upgrade)
10160 		binary_upgrade_set_type_oids_by_type_oid(fout,
10161 												 q, tyinfo->dobj.catId.oid);
10162 
10163 	appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10164 					  qualtypname);
10165 
10166 	if (dopt->binary_upgrade)
10167 		binary_upgrade_extension_member(q, &tyinfo->dobj,
10168 										"TYPE", qtypname,
10169 										tyinfo->dobj.namespace->dobj.name);
10170 
10171 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10172 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10173 					 tyinfo->dobj.name,
10174 					 tyinfo->dobj.namespace->dobj.name,
10175 					 NULL,
10176 					 tyinfo->rolname, false,
10177 					 "TYPE", SECTION_PRE_DATA,
10178 					 q->data, delq->data, NULL,
10179 					 NULL, 0,
10180 					 NULL, NULL);
10181 
10182 	/* Dump Type Comments and Security Labels */
10183 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10184 		dumpComment(fout, "TYPE", qtypname,
10185 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10186 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10187 
10188 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10189 		dumpSecLabel(fout, "TYPE", qtypname,
10190 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10191 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10192 
10193 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10194 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10195 				qtypname, NULL,
10196 				tyinfo->dobj.namespace->dobj.name,
10197 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10198 				tyinfo->inittypacl, tyinfo->initrtypacl);
10199 
10200 	destroyPQExpBuffer(q);
10201 	destroyPQExpBuffer(delq);
10202 	free(qtypname);
10203 	free(qualtypname);
10204 }
10205 
10206 /*
10207  * dumpBaseType
10208  *	  writes out to fout the queries to recreate a user-defined base type
10209  */
10210 static void
dumpBaseType(Archive * fout,TypeInfo * tyinfo)10211 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10212 {
10213 	DumpOptions *dopt = fout->dopt;
10214 	PQExpBuffer q = createPQExpBuffer();
10215 	PQExpBuffer delq = createPQExpBuffer();
10216 	PQExpBuffer query = createPQExpBuffer();
10217 	PGresult   *res;
10218 	char	   *qtypname;
10219 	char	   *qualtypname;
10220 	char	   *typlen;
10221 	char	   *typinput;
10222 	char	   *typoutput;
10223 	char	   *typreceive;
10224 	char	   *typsend;
10225 	char	   *typmodin;
10226 	char	   *typmodout;
10227 	char	   *typanalyze;
10228 	Oid			typreceiveoid;
10229 	Oid			typsendoid;
10230 	Oid			typmodinoid;
10231 	Oid			typmodoutoid;
10232 	Oid			typanalyzeoid;
10233 	char	   *typcategory;
10234 	char	   *typispreferred;
10235 	char	   *typdelim;
10236 	char	   *typbyval;
10237 	char	   *typalign;
10238 	char	   *typstorage;
10239 	char	   *typcollatable;
10240 	char	   *typdefault;
10241 	bool		typdefault_is_literal = false;
10242 
10243 	/* Fetch type-specific details */
10244 	if (fout->remoteVersion >= 90100)
10245 	{
10246 		appendPQExpBuffer(query, "SELECT typlen, "
10247 						  "typinput, typoutput, typreceive, typsend, "
10248 						  "typmodin, typmodout, typanalyze, "
10249 						  "typreceive::pg_catalog.oid AS typreceiveoid, "
10250 						  "typsend::pg_catalog.oid AS typsendoid, "
10251 						  "typmodin::pg_catalog.oid AS typmodinoid, "
10252 						  "typmodout::pg_catalog.oid AS typmodoutoid, "
10253 						  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10254 						  "typcategory, typispreferred, "
10255 						  "typdelim, typbyval, typalign, typstorage, "
10256 						  "(typcollation <> 0) AS typcollatable, "
10257 						  "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10258 						  "FROM pg_catalog.pg_type "
10259 						  "WHERE oid = '%u'::pg_catalog.oid",
10260 						  tyinfo->dobj.catId.oid);
10261 	}
10262 	else if (fout->remoteVersion >= 80400)
10263 	{
10264 		appendPQExpBuffer(query, "SELECT typlen, "
10265 						  "typinput, typoutput, typreceive, typsend, "
10266 						  "typmodin, typmodout, typanalyze, "
10267 						  "typreceive::pg_catalog.oid AS typreceiveoid, "
10268 						  "typsend::pg_catalog.oid AS typsendoid, "
10269 						  "typmodin::pg_catalog.oid AS typmodinoid, "
10270 						  "typmodout::pg_catalog.oid AS typmodoutoid, "
10271 						  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10272 						  "typcategory, typispreferred, "
10273 						  "typdelim, typbyval, typalign, typstorage, "
10274 						  "false AS typcollatable, "
10275 						  "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10276 						  "FROM pg_catalog.pg_type "
10277 						  "WHERE oid = '%u'::pg_catalog.oid",
10278 						  tyinfo->dobj.catId.oid);
10279 	}
10280 	else if (fout->remoteVersion >= 80300)
10281 	{
10282 		/* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10283 		appendPQExpBuffer(query, "SELECT typlen, "
10284 						  "typinput, typoutput, typreceive, typsend, "
10285 						  "typmodin, typmodout, typanalyze, "
10286 						  "typreceive::pg_catalog.oid AS typreceiveoid, "
10287 						  "typsend::pg_catalog.oid AS typsendoid, "
10288 						  "typmodin::pg_catalog.oid AS typmodinoid, "
10289 						  "typmodout::pg_catalog.oid AS typmodoutoid, "
10290 						  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10291 						  "'U' AS typcategory, false AS typispreferred, "
10292 						  "typdelim, typbyval, typalign, typstorage, "
10293 						  "false AS typcollatable, "
10294 						  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10295 						  "FROM pg_catalog.pg_type "
10296 						  "WHERE oid = '%u'::pg_catalog.oid",
10297 						  tyinfo->dobj.catId.oid);
10298 	}
10299 	else if (fout->remoteVersion >= 80000)
10300 	{
10301 		appendPQExpBuffer(query, "SELECT typlen, "
10302 						  "typinput, typoutput, typreceive, typsend, "
10303 						  "'-' AS typmodin, '-' AS typmodout, "
10304 						  "typanalyze, "
10305 						  "typreceive::pg_catalog.oid AS typreceiveoid, "
10306 						  "typsend::pg_catalog.oid AS typsendoid, "
10307 						  "0 AS typmodinoid, 0 AS typmodoutoid, "
10308 						  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10309 						  "'U' AS typcategory, false AS typispreferred, "
10310 						  "typdelim, typbyval, typalign, typstorage, "
10311 						  "false AS typcollatable, "
10312 						  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10313 						  "FROM pg_catalog.pg_type "
10314 						  "WHERE oid = '%u'::pg_catalog.oid",
10315 						  tyinfo->dobj.catId.oid);
10316 	}
10317 	else if (fout->remoteVersion >= 70400)
10318 	{
10319 		appendPQExpBuffer(query, "SELECT typlen, "
10320 						  "typinput, typoutput, typreceive, typsend, "
10321 						  "'-' AS typmodin, '-' AS typmodout, "
10322 						  "'-' AS typanalyze, "
10323 						  "typreceive::pg_catalog.oid AS typreceiveoid, "
10324 						  "typsend::pg_catalog.oid AS typsendoid, "
10325 						  "0 AS typmodinoid, 0 AS typmodoutoid, "
10326 						  "0 AS typanalyzeoid, "
10327 						  "'U' AS typcategory, false AS typispreferred, "
10328 						  "typdelim, typbyval, typalign, typstorage, "
10329 						  "false AS typcollatable, "
10330 						  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10331 						  "FROM pg_catalog.pg_type "
10332 						  "WHERE oid = '%u'::pg_catalog.oid",
10333 						  tyinfo->dobj.catId.oid);
10334 	}
10335 	else if (fout->remoteVersion >= 70300)
10336 	{
10337 		appendPQExpBuffer(query, "SELECT typlen, "
10338 						  "typinput, typoutput, "
10339 						  "'-' AS typreceive, '-' AS typsend, "
10340 						  "'-' AS typmodin, '-' AS typmodout, "
10341 						  "'-' AS typanalyze, "
10342 						  "0 AS typreceiveoid, 0 AS typsendoid, "
10343 						  "0 AS typmodinoid, 0 AS typmodoutoid, "
10344 						  "0 AS typanalyzeoid, "
10345 						  "'U' AS typcategory, false AS typispreferred, "
10346 						  "typdelim, typbyval, typalign, typstorage, "
10347 						  "false AS typcollatable, "
10348 						  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10349 						  "FROM pg_catalog.pg_type "
10350 						  "WHERE oid = '%u'::pg_catalog.oid",
10351 						  tyinfo->dobj.catId.oid);
10352 	}
10353 	else if (fout->remoteVersion >= 70200)
10354 	{
10355 		/*
10356 		 * Note: although pre-7.3 catalogs contain typreceive and typsend,
10357 		 * ignore them because they are not right.
10358 		 */
10359 		appendPQExpBuffer(query, "SELECT typlen, "
10360 						  "typinput, typoutput, "
10361 						  "'-' AS typreceive, '-' AS typsend, "
10362 						  "'-' AS typmodin, '-' AS typmodout, "
10363 						  "'-' AS typanalyze, "
10364 						  "0 AS typreceiveoid, 0 AS typsendoid, "
10365 						  "0 AS typmodinoid, 0 AS typmodoutoid, "
10366 						  "0 AS typanalyzeoid, "
10367 						  "'U' AS typcategory, false AS typispreferred, "
10368 						  "typdelim, typbyval, typalign, typstorage, "
10369 						  "false AS typcollatable, "
10370 						  "NULL AS typdefaultbin, typdefault "
10371 						  "FROM pg_type "
10372 						  "WHERE oid = '%u'::oid",
10373 						  tyinfo->dobj.catId.oid);
10374 	}
10375 	else if (fout->remoteVersion >= 70100)
10376 	{
10377 		/*
10378 		 * Ignore pre-7.2 typdefault; the field exists but has an unusable
10379 		 * representation.
10380 		 */
10381 		appendPQExpBuffer(query, "SELECT typlen, "
10382 						  "typinput, typoutput, "
10383 						  "'-' AS typreceive, '-' AS typsend, "
10384 						  "'-' AS typmodin, '-' AS typmodout, "
10385 						  "'-' AS typanalyze, "
10386 						  "0 AS typreceiveoid, 0 AS typsendoid, "
10387 						  "0 AS typmodinoid, 0 AS typmodoutoid, "
10388 						  "0 AS typanalyzeoid, "
10389 						  "'U' AS typcategory, false AS typispreferred, "
10390 						  "typdelim, typbyval, typalign, typstorage, "
10391 						  "false AS typcollatable, "
10392 						  "NULL AS typdefaultbin, NULL AS typdefault "
10393 						  "FROM pg_type "
10394 						  "WHERE oid = '%u'::oid",
10395 						  tyinfo->dobj.catId.oid);
10396 	}
10397 	else
10398 	{
10399 		appendPQExpBuffer(query, "SELECT typlen, "
10400 						  "typinput, typoutput, "
10401 						  "'-' AS typreceive, '-' AS typsend, "
10402 						  "'-' AS typmodin, '-' AS typmodout, "
10403 						  "'-' AS typanalyze, "
10404 						  "0 AS typreceiveoid, 0 AS typsendoid, "
10405 						  "0 AS typmodinoid, 0 AS typmodoutoid, "
10406 						  "0 AS typanalyzeoid, "
10407 						  "'U' AS typcategory, false AS typispreferred, "
10408 						  "typdelim, typbyval, typalign, "
10409 						  "'p'::char AS typstorage, "
10410 						  "false AS typcollatable, "
10411 						  "NULL AS typdefaultbin, NULL AS typdefault "
10412 						  "FROM pg_type "
10413 						  "WHERE oid = '%u'::oid",
10414 						  tyinfo->dobj.catId.oid);
10415 	}
10416 
10417 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
10418 
10419 	typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10420 	typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10421 	typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10422 	typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10423 	typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10424 	typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10425 	typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10426 	typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10427 	typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10428 	typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10429 	typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10430 	typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10431 	typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10432 	typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10433 	typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10434 	typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10435 	typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10436 	typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10437 	typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10438 	typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10439 	if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10440 		typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10441 	else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10442 	{
10443 		typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10444 		typdefault_is_literal = true;	/* it needs quotes */
10445 	}
10446 	else
10447 		typdefault = NULL;
10448 
10449 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10450 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10451 
10452 	/*
10453 	 * The reason we include CASCADE is that the circular dependency between
10454 	 * the type and its I/O functions makes it impossible to drop the type any
10455 	 * other way.
10456 	 */
10457 	appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10458 
10459 	/* We might already have a shell type, but setting pg_type_oid is harmless */
10460 	if (dopt->binary_upgrade)
10461 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
10462 												 tyinfo->dobj.catId.oid);
10463 
10464 	appendPQExpBuffer(q,
10465 					  "CREATE TYPE %s (\n"
10466 					  "    INTERNALLENGTH = %s",
10467 					  qualtypname,
10468 					  (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10469 
10470 	if (fout->remoteVersion >= 70300)
10471 	{
10472 		/* regproc result is correctly quoted as of 7.3 */
10473 		appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10474 		appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10475 		if (OidIsValid(typreceiveoid))
10476 			appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10477 		if (OidIsValid(typsendoid))
10478 			appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10479 		if (OidIsValid(typmodinoid))
10480 			appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10481 		if (OidIsValid(typmodoutoid))
10482 			appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10483 		if (OidIsValid(typanalyzeoid))
10484 			appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10485 	}
10486 	else
10487 	{
10488 		/* regproc delivers an unquoted name before 7.3 */
10489 		/* cannot combine these because fmtId uses static result area */
10490 		appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
10491 		appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
10492 		/* receive/send/typmodin/typmodout/analyze need not be printed */
10493 	}
10494 
10495 	if (strcmp(typcollatable, "t") == 0)
10496 		appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10497 
10498 	if (typdefault != NULL)
10499 	{
10500 		appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10501 		if (typdefault_is_literal)
10502 			appendStringLiteralAH(q, typdefault, fout);
10503 		else
10504 			appendPQExpBufferStr(q, typdefault);
10505 	}
10506 
10507 	if (OidIsValid(tyinfo->typelem))
10508 		appendPQExpBuffer(q, ",\n    ELEMENT = %s",
10509 						  getFormattedTypeName(fout, tyinfo->typelem,
10510 											   zeroAsOpaque));
10511 
10512 	if (strcmp(typcategory, "U") != 0)
10513 	{
10514 		appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10515 		appendStringLiteralAH(q, typcategory, fout);
10516 	}
10517 
10518 	if (strcmp(typispreferred, "t") == 0)
10519 		appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10520 
10521 	if (typdelim && strcmp(typdelim, ",") != 0)
10522 	{
10523 		appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10524 		appendStringLiteralAH(q, typdelim, fout);
10525 	}
10526 
10527 	if (strcmp(typalign, "c") == 0)
10528 		appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10529 	else if (strcmp(typalign, "s") == 0)
10530 		appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10531 	else if (strcmp(typalign, "i") == 0)
10532 		appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10533 	else if (strcmp(typalign, "d") == 0)
10534 		appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10535 
10536 	if (strcmp(typstorage, "p") == 0)
10537 		appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10538 	else if (strcmp(typstorage, "e") == 0)
10539 		appendPQExpBufferStr(q, ",\n    STORAGE = external");
10540 	else if (strcmp(typstorage, "x") == 0)
10541 		appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10542 	else if (strcmp(typstorage, "m") == 0)
10543 		appendPQExpBufferStr(q, ",\n    STORAGE = main");
10544 
10545 	if (strcmp(typbyval, "t") == 0)
10546 		appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10547 
10548 	appendPQExpBufferStr(q, "\n);\n");
10549 
10550 	if (dopt->binary_upgrade)
10551 		binary_upgrade_extension_member(q, &tyinfo->dobj,
10552 										"TYPE", qtypname,
10553 										tyinfo->dobj.namespace->dobj.name);
10554 
10555 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10556 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10557 					 tyinfo->dobj.name,
10558 					 tyinfo->dobj.namespace->dobj.name,
10559 					 NULL,
10560 					 tyinfo->rolname, false,
10561 					 "TYPE", SECTION_PRE_DATA,
10562 					 q->data, delq->data, NULL,
10563 					 NULL, 0,
10564 					 NULL, NULL);
10565 
10566 	/* Dump Type Comments and Security Labels */
10567 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10568 		dumpComment(fout, "TYPE", qtypname,
10569 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10570 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10571 
10572 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10573 		dumpSecLabel(fout, "TYPE", qtypname,
10574 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10575 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10576 
10577 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10578 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10579 				qtypname, NULL,
10580 				tyinfo->dobj.namespace->dobj.name,
10581 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10582 				tyinfo->inittypacl, tyinfo->initrtypacl);
10583 
10584 	PQclear(res);
10585 	destroyPQExpBuffer(q);
10586 	destroyPQExpBuffer(delq);
10587 	destroyPQExpBuffer(query);
10588 	free(qtypname);
10589 	free(qualtypname);
10590 }
10591 
10592 /*
10593  * dumpDomain
10594  *	  writes out to fout the queries to recreate a user-defined domain
10595  */
10596 static void
dumpDomain(Archive * fout,TypeInfo * tyinfo)10597 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10598 {
10599 	DumpOptions *dopt = fout->dopt;
10600 	PQExpBuffer q = createPQExpBuffer();
10601 	PQExpBuffer delq = createPQExpBuffer();
10602 	PQExpBuffer query = createPQExpBuffer();
10603 	PGresult   *res;
10604 	int			i;
10605 	char	   *qtypname;
10606 	char	   *qualtypname;
10607 	char	   *typnotnull;
10608 	char	   *typdefn;
10609 	char	   *typdefault;
10610 	Oid			typcollation;
10611 	bool		typdefault_is_literal = false;
10612 
10613 	/* Fetch domain specific details */
10614 	if (fout->remoteVersion >= 90100)
10615 	{
10616 		/* typcollation is new in 9.1 */
10617 		appendPQExpBuffer(query, "SELECT t.typnotnull, "
10618 			"pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10619 						  "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10620 						  "t.typdefault, "
10621 						  "CASE WHEN t.typcollation <> u.typcollation "
10622 						  "THEN t.typcollation ELSE 0 END AS typcollation "
10623 						  "FROM pg_catalog.pg_type t "
10624 				 "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10625 						  "WHERE t.oid = '%u'::pg_catalog.oid",
10626 						  tyinfo->dobj.catId.oid);
10627 	}
10628 	else
10629 	{
10630 		/* We assume here that remoteVersion must be at least 70300 */
10631 		appendPQExpBuffer(query, "SELECT typnotnull, "
10632 				"pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10633 						  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10634 						  "typdefault, 0 AS typcollation "
10635 						  "FROM pg_catalog.pg_type "
10636 						  "WHERE oid = '%u'::pg_catalog.oid",
10637 						  tyinfo->dobj.catId.oid);
10638 	}
10639 
10640 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
10641 
10642 	typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10643 	typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10644 	if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10645 		typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10646 	else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10647 	{
10648 		typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10649 		typdefault_is_literal = true;	/* it needs quotes */
10650 	}
10651 	else
10652 		typdefault = NULL;
10653 	typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10654 
10655 	if (dopt->binary_upgrade)
10656 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
10657 												 tyinfo->dobj.catId.oid);
10658 
10659 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10660 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10661 
10662 	appendPQExpBuffer(q,
10663 					  "CREATE DOMAIN %s AS %s",
10664 					  qualtypname,
10665 					  typdefn);
10666 
10667 	/* Print collation only if different from base type's collation */
10668 	if (OidIsValid(typcollation))
10669 	{
10670 		CollInfo   *coll;
10671 
10672 		coll = findCollationByOid(typcollation);
10673 		if (coll)
10674 			appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10675 	}
10676 
10677 	if (typnotnull[0] == 't')
10678 		appendPQExpBufferStr(q, " NOT NULL");
10679 
10680 	if (typdefault != NULL)
10681 	{
10682 		appendPQExpBufferStr(q, " DEFAULT ");
10683 		if (typdefault_is_literal)
10684 			appendStringLiteralAH(q, typdefault, fout);
10685 		else
10686 			appendPQExpBufferStr(q, typdefault);
10687 	}
10688 
10689 	PQclear(res);
10690 
10691 	/*
10692 	 * Add any CHECK constraints for the domain
10693 	 */
10694 	for (i = 0; i < tyinfo->nDomChecks; i++)
10695 	{
10696 		ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10697 
10698 		if (!domcheck->separate)
10699 			appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10700 							  fmtId(domcheck->dobj.name), domcheck->condef);
10701 	}
10702 
10703 	appendPQExpBufferStr(q, ";\n");
10704 
10705 	appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10706 
10707 	if (dopt->binary_upgrade)
10708 		binary_upgrade_extension_member(q, &tyinfo->dobj,
10709 										"DOMAIN", qtypname,
10710 										tyinfo->dobj.namespace->dobj.name);
10711 
10712 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10713 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10714 					 tyinfo->dobj.name,
10715 					 tyinfo->dobj.namespace->dobj.name,
10716 					 NULL,
10717 					 tyinfo->rolname, false,
10718 					 "DOMAIN", SECTION_PRE_DATA,
10719 					 q->data, delq->data, NULL,
10720 					 NULL, 0,
10721 					 NULL, NULL);
10722 
10723 	/* Dump Domain Comments and Security Labels */
10724 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10725 		dumpComment(fout, "DOMAIN", qtypname,
10726 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10727 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10728 
10729 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10730 		dumpSecLabel(fout, "DOMAIN", qtypname,
10731 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10732 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10733 
10734 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10735 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10736 				qtypname, NULL,
10737 				tyinfo->dobj.namespace->dobj.name,
10738 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10739 				tyinfo->inittypacl, tyinfo->initrtypacl);
10740 
10741 	/* Dump any per-constraint comments */
10742 	for (i = 0; i < tyinfo->nDomChecks; i++)
10743 	{
10744 		ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10745 		PQExpBuffer conprefix = createPQExpBuffer();
10746 
10747 		appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10748 						  fmtId(domcheck->dobj.name));
10749 
10750 		if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10751 			dumpComment(fout, conprefix->data, qtypname,
10752 						tyinfo->dobj.namespace->dobj.name,
10753 						tyinfo->rolname,
10754 						domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10755 
10756 		destroyPQExpBuffer(conprefix);
10757 	}
10758 
10759 	destroyPQExpBuffer(q);
10760 	destroyPQExpBuffer(delq);
10761 	destroyPQExpBuffer(query);
10762 	free(qtypname);
10763 	free(qualtypname);
10764 }
10765 
10766 /*
10767  * dumpCompositeType
10768  *	  writes out to fout the queries to recreate a user-defined stand-alone
10769  *	  composite type
10770  */
10771 static void
dumpCompositeType(Archive * fout,TypeInfo * tyinfo)10772 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10773 {
10774 	DumpOptions *dopt = fout->dopt;
10775 	PQExpBuffer q = createPQExpBuffer();
10776 	PQExpBuffer dropped = createPQExpBuffer();
10777 	PQExpBuffer delq = createPQExpBuffer();
10778 	PQExpBuffer query = createPQExpBuffer();
10779 	PGresult   *res;
10780 	char	   *qtypname;
10781 	char	   *qualtypname;
10782 	int			ntups;
10783 	int			i_attname;
10784 	int			i_atttypdefn;
10785 	int			i_attlen;
10786 	int			i_attalign;
10787 	int			i_attisdropped;
10788 	int			i_attcollation;
10789 	int			i;
10790 	int			actual_atts;
10791 
10792 	/* Fetch type specific details */
10793 	if (fout->remoteVersion >= 90100)
10794 	{
10795 		/*
10796 		 * attcollation is new in 9.1.  Since we only want to dump COLLATE
10797 		 * clauses for attributes whose collation is different from their
10798 		 * type's default, we use a CASE here to suppress uninteresting
10799 		 * attcollations cheaply.  atttypid will be 0 for dropped columns;
10800 		 * collation does not matter for those.
10801 		 */
10802 		appendPQExpBuffer(query, "SELECT a.attname, "
10803 			"pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10804 						  "a.attlen, a.attalign, a.attisdropped, "
10805 						  "CASE WHEN a.attcollation <> at.typcollation "
10806 						  "THEN a.attcollation ELSE 0 END AS attcollation "
10807 						  "FROM pg_catalog.pg_type ct "
10808 				"JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10809 					"LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10810 						  "WHERE ct.oid = '%u'::pg_catalog.oid "
10811 						  "ORDER BY a.attnum ",
10812 						  tyinfo->dobj.catId.oid);
10813 	}
10814 	else
10815 	{
10816 		/*
10817 		 * We assume here that remoteVersion must be at least 70300.  Since
10818 		 * ALTER TYPE could not drop columns until 9.1, attisdropped should
10819 		 * always be false.
10820 		 */
10821 		appendPQExpBuffer(query, "SELECT a.attname, "
10822 			"pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10823 						  "a.attlen, a.attalign, a.attisdropped, "
10824 						  "0 AS attcollation "
10825 					 "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10826 						  "WHERE ct.oid = '%u'::pg_catalog.oid "
10827 						  "AND a.attrelid = ct.typrelid "
10828 						  "ORDER BY a.attnum ",
10829 						  tyinfo->dobj.catId.oid);
10830 	}
10831 
10832 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10833 
10834 	ntups = PQntuples(res);
10835 
10836 	i_attname = PQfnumber(res, "attname");
10837 	i_atttypdefn = PQfnumber(res, "atttypdefn");
10838 	i_attlen = PQfnumber(res, "attlen");
10839 	i_attalign = PQfnumber(res, "attalign");
10840 	i_attisdropped = PQfnumber(res, "attisdropped");
10841 	i_attcollation = PQfnumber(res, "attcollation");
10842 
10843 	if (dopt->binary_upgrade)
10844 	{
10845 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
10846 												 tyinfo->dobj.catId.oid);
10847 		binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
10848 	}
10849 
10850 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10851 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10852 
10853 	appendPQExpBuffer(q, "CREATE TYPE %s AS (",
10854 					  qualtypname);
10855 
10856 	actual_atts = 0;
10857 	for (i = 0; i < ntups; i++)
10858 	{
10859 		char	   *attname;
10860 		char	   *atttypdefn;
10861 		char	   *attlen;
10862 		char	   *attalign;
10863 		bool		attisdropped;
10864 		Oid			attcollation;
10865 
10866 		attname = PQgetvalue(res, i, i_attname);
10867 		atttypdefn = PQgetvalue(res, i, i_atttypdefn);
10868 		attlen = PQgetvalue(res, i, i_attlen);
10869 		attalign = PQgetvalue(res, i, i_attalign);
10870 		attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
10871 		attcollation = atooid(PQgetvalue(res, i, i_attcollation));
10872 
10873 		if (attisdropped && !dopt->binary_upgrade)
10874 			continue;
10875 
10876 		/* Format properly if not first attr */
10877 		if (actual_atts++ > 0)
10878 			appendPQExpBufferChar(q, ',');
10879 		appendPQExpBufferStr(q, "\n\t");
10880 
10881 		if (!attisdropped)
10882 		{
10883 			appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
10884 
10885 			/* Add collation if not default for the column type */
10886 			if (OidIsValid(attcollation))
10887 			{
10888 				CollInfo   *coll;
10889 
10890 				coll = findCollationByOid(attcollation);
10891 				if (coll)
10892 					appendPQExpBuffer(q, " COLLATE %s",
10893 									  fmtQualifiedDumpable(coll));
10894 			}
10895 		}
10896 		else
10897 		{
10898 			/*
10899 			 * This is a dropped attribute and we're in binary_upgrade mode.
10900 			 * Insert a placeholder for it in the CREATE TYPE command, and set
10901 			 * length and alignment with direct UPDATE to the catalogs
10902 			 * afterwards. See similar code in dumpTableSchema().
10903 			 */
10904 			appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
10905 
10906 			/* stash separately for insertion after the CREATE TYPE */
10907 			appendPQExpBufferStr(dropped,
10908 					  "\n-- For binary upgrade, recreate dropped column.\n");
10909 			appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
10910 							  "SET attlen = %s, "
10911 							  "attalign = '%s', attbyval = false\n"
10912 							  "WHERE attname = ", attlen, attalign);
10913 			appendStringLiteralAH(dropped, attname, fout);
10914 			appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
10915 			appendStringLiteralAH(dropped, qualtypname, fout);
10916 			appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
10917 
10918 			appendPQExpBuffer(dropped, "ALTER TYPE %s ",
10919 							  qualtypname);
10920 			appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
10921 							  fmtId(attname));
10922 		}
10923 	}
10924 	appendPQExpBufferStr(q, "\n);\n");
10925 	appendPQExpBufferStr(q, dropped->data);
10926 
10927 	appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10928 
10929 	if (dopt->binary_upgrade)
10930 		binary_upgrade_extension_member(q, &tyinfo->dobj,
10931 										"TYPE", qtypname,
10932 										tyinfo->dobj.namespace->dobj.name);
10933 
10934 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10935 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10936 					 tyinfo->dobj.name,
10937 					 tyinfo->dobj.namespace->dobj.name,
10938 					 NULL,
10939 					 tyinfo->rolname, false,
10940 					 "TYPE", SECTION_PRE_DATA,
10941 					 q->data, delq->data, NULL,
10942 					 NULL, 0,
10943 					 NULL, NULL);
10944 
10945 
10946 	/* Dump Type Comments and Security Labels */
10947 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10948 		dumpComment(fout, "TYPE", qtypname,
10949 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10950 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10951 
10952 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10953 		dumpSecLabel(fout, "TYPE", qtypname,
10954 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10955 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10956 
10957 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10958 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10959 				qtypname, NULL,
10960 				tyinfo->dobj.namespace->dobj.name,
10961 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10962 				tyinfo->inittypacl, tyinfo->initrtypacl);
10963 
10964 	PQclear(res);
10965 	destroyPQExpBuffer(q);
10966 	destroyPQExpBuffer(dropped);
10967 	destroyPQExpBuffer(delq);
10968 	destroyPQExpBuffer(query);
10969 	free(qtypname);
10970 	free(qualtypname);
10971 
10972 	/* Dump any per-column comments */
10973 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10974 		dumpCompositeTypeColComments(fout, tyinfo);
10975 }
10976 
10977 /*
10978  * dumpCompositeTypeColComments
10979  *	  writes out to fout the queries to recreate comments on the columns of
10980  *	  a user-defined stand-alone composite type
10981  */
10982 static void
dumpCompositeTypeColComments(Archive * fout,TypeInfo * tyinfo)10983 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
10984 {
10985 	CommentItem *comments;
10986 	int			ncomments;
10987 	PGresult   *res;
10988 	PQExpBuffer query;
10989 	PQExpBuffer target;
10990 	Oid			pgClassOid;
10991 	int			i;
10992 	int			ntups;
10993 	int			i_attname;
10994 	int			i_attnum;
10995 
10996 	query = createPQExpBuffer();
10997 
10998 	/* We assume here that remoteVersion must be at least 70300 */
10999 	appendPQExpBuffer(query,
11000 					  "SELECT c.tableoid, a.attname, a.attnum "
11001 					  "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11002 					  "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11003 					  "  AND NOT a.attisdropped "
11004 					  "ORDER BY a.attnum ",
11005 					  tyinfo->typrelid);
11006 
11007 	/* Fetch column attnames */
11008 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11009 
11010 	ntups = PQntuples(res);
11011 	if (ntups < 1)
11012 	{
11013 		PQclear(res);
11014 		destroyPQExpBuffer(query);
11015 		return;
11016 	}
11017 
11018 	pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11019 
11020 	/* Search for comments associated with type's pg_class OID */
11021 	ncomments = findComments(fout,
11022 							 pgClassOid,
11023 							 tyinfo->typrelid,
11024 							 &comments);
11025 
11026 	/* If no comments exist, we're done */
11027 	if (ncomments <= 0)
11028 	{
11029 		PQclear(res);
11030 		destroyPQExpBuffer(query);
11031 		return;
11032 	}
11033 
11034 	/* Build COMMENT ON statements */
11035 	target = createPQExpBuffer();
11036 
11037 	i_attnum = PQfnumber(res, "attnum");
11038 	i_attname = PQfnumber(res, "attname");
11039 	while (ncomments > 0)
11040 	{
11041 		const char *attname;
11042 
11043 		attname = NULL;
11044 		for (i = 0; i < ntups; i++)
11045 		{
11046 			if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11047 			{
11048 				attname = PQgetvalue(res, i, i_attname);
11049 				break;
11050 			}
11051 		}
11052 		if (attname)			/* just in case we don't find it */
11053 		{
11054 			const char *descr = comments->descr;
11055 
11056 			resetPQExpBuffer(target);
11057 			appendPQExpBuffer(target, "COLUMN %s.",
11058 							  fmtId(tyinfo->dobj.name));
11059 			appendPQExpBufferStr(target, fmtId(attname));
11060 
11061 			resetPQExpBuffer(query);
11062 			appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11063 							  fmtQualifiedDumpable(tyinfo));
11064 			appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11065 			appendStringLiteralAH(query, descr, fout);
11066 			appendPQExpBufferStr(query, ";\n");
11067 
11068 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
11069 						 target->data,
11070 						 tyinfo->dobj.namespace->dobj.name,
11071 						 NULL, tyinfo->rolname,
11072 						 false, "COMMENT", SECTION_NONE,
11073 						 query->data, "", NULL,
11074 						 &(tyinfo->dobj.dumpId), 1,
11075 						 NULL, NULL);
11076 		}
11077 
11078 		comments++;
11079 		ncomments--;
11080 	}
11081 
11082 	PQclear(res);
11083 	destroyPQExpBuffer(query);
11084 	destroyPQExpBuffer(target);
11085 }
11086 
11087 /*
11088  * dumpShellType
11089  *	  writes out to fout the queries to create a shell type
11090  *
11091  * We dump a shell definition in advance of the I/O functions for the type.
11092  */
11093 static void
dumpShellType(Archive * fout,ShellTypeInfo * stinfo)11094 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11095 {
11096 	DumpOptions *dopt = fout->dopt;
11097 	PQExpBuffer q;
11098 
11099 	/* Skip if not to be dumped */
11100 	if (!stinfo->dobj.dump || dopt->dataOnly)
11101 		return;
11102 
11103 	q = createPQExpBuffer();
11104 
11105 	/*
11106 	 * Note the lack of a DROP command for the shell type; any required DROP
11107 	 * is driven off the base type entry, instead.  This interacts with
11108 	 * _printTocEntry()'s use of the presence of a DROP command to decide
11109 	 * whether an entry needs an ALTER OWNER command.  We don't want to alter
11110 	 * the shell type's owner immediately on creation; that should happen only
11111 	 * after it's filled in, otherwise the backend complains.
11112 	 */
11113 
11114 	if (dopt->binary_upgrade)
11115 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
11116 										   stinfo->baseType->dobj.catId.oid);
11117 
11118 	appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11119 					  fmtQualifiedDumpable(stinfo));
11120 
11121 	if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11122 		ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11123 					 stinfo->dobj.name,
11124 					 stinfo->dobj.namespace->dobj.name,
11125 					 NULL,
11126 					 stinfo->baseType->rolname, false,
11127 					 "SHELL TYPE", SECTION_PRE_DATA,
11128 					 q->data, "", NULL,
11129 					 NULL, 0,
11130 					 NULL, NULL);
11131 
11132 	destroyPQExpBuffer(q);
11133 }
11134 
11135 /*
11136  * dumpProcLang
11137  *		  writes out to fout the queries to recreate a user-defined
11138  *		  procedural language
11139  */
11140 static void
dumpProcLang(Archive * fout,ProcLangInfo * plang)11141 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11142 {
11143 	DumpOptions *dopt = fout->dopt;
11144 	PQExpBuffer defqry;
11145 	PQExpBuffer delqry;
11146 	bool		useParams;
11147 	char	   *qlanname;
11148 	FuncInfo   *funcInfo;
11149 	FuncInfo   *inlineInfo = NULL;
11150 	FuncInfo   *validatorInfo = NULL;
11151 
11152 	/* Skip if not to be dumped */
11153 	if (!plang->dobj.dump || dopt->dataOnly)
11154 		return;
11155 
11156 	/*
11157 	 * Try to find the support function(s).  It is not an error if we don't
11158 	 * find them --- if the functions are in the pg_catalog schema, as is
11159 	 * standard in 8.1 and up, then we won't have loaded them. (In this case
11160 	 * we will emit a parameterless CREATE LANGUAGE command, which will
11161 	 * require PL template knowledge in the backend to reload.)
11162 	 */
11163 
11164 	funcInfo = findFuncByOid(plang->lanplcallfoid);
11165 	if (funcInfo != NULL && !funcInfo->dobj.dump)
11166 		funcInfo = NULL;		/* treat not-dumped same as not-found */
11167 
11168 	if (OidIsValid(plang->laninline))
11169 	{
11170 		inlineInfo = findFuncByOid(plang->laninline);
11171 		if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11172 			inlineInfo = NULL;
11173 	}
11174 
11175 	if (OidIsValid(plang->lanvalidator))
11176 	{
11177 		validatorInfo = findFuncByOid(plang->lanvalidator);
11178 		if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11179 			validatorInfo = NULL;
11180 	}
11181 
11182 	/*
11183 	 * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11184 	 * with parameters.  Otherwise, we'll write a parameterless command, which
11185 	 * will rely on data from pg_pltemplate.
11186 	 */
11187 	useParams = (funcInfo != NULL &&
11188 				 (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11189 				 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11190 
11191 	defqry = createPQExpBuffer();
11192 	delqry = createPQExpBuffer();
11193 
11194 	qlanname = pg_strdup(fmtId(plang->dobj.name));
11195 
11196 	appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11197 					  qlanname);
11198 
11199 	if (useParams)
11200 	{
11201 		appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11202 						  plang->lanpltrusted ? "TRUSTED " : "",
11203 						  qlanname);
11204 		appendPQExpBuffer(defqry, " HANDLER %s",
11205 						  fmtQualifiedDumpable(funcInfo));
11206 		if (OidIsValid(plang->laninline))
11207 			appendPQExpBuffer(defqry, " INLINE %s",
11208 							  fmtQualifiedDumpable(inlineInfo));
11209 		if (OidIsValid(plang->lanvalidator))
11210 			appendPQExpBuffer(defqry, " VALIDATOR %s",
11211 							  fmtQualifiedDumpable(validatorInfo));
11212 	}
11213 	else
11214 	{
11215 		/*
11216 		 * If not dumping parameters, then use CREATE OR REPLACE so that the
11217 		 * command will not fail if the language is preinstalled in the target
11218 		 * database.  We restrict the use of REPLACE to this case so as to
11219 		 * eliminate the risk of replacing a language with incompatible
11220 		 * parameter settings: this command will only succeed at all if there
11221 		 * is a pg_pltemplate entry, and if there is one, the existing entry
11222 		 * must match it too.
11223 		 */
11224 		appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11225 						  qlanname);
11226 	}
11227 	appendPQExpBufferStr(defqry, ";\n");
11228 
11229 	if (dopt->binary_upgrade)
11230 		binary_upgrade_extension_member(defqry, &plang->dobj,
11231 										"LANGUAGE", qlanname, NULL);
11232 
11233 	if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11234 		ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11235 					 plang->dobj.name,
11236 					 NULL, NULL, plang->lanowner,
11237 					 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
11238 					 defqry->data, delqry->data, NULL,
11239 					 NULL, 0,
11240 					 NULL, NULL);
11241 
11242 	/* Dump Proc Lang Comments and Security Labels */
11243 	if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11244 		dumpComment(fout, "LANGUAGE", qlanname,
11245 					NULL, plang->lanowner,
11246 					plang->dobj.catId, 0, plang->dobj.dumpId);
11247 
11248 	if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11249 		dumpSecLabel(fout, "LANGUAGE", qlanname,
11250 					 NULL, plang->lanowner,
11251 					 plang->dobj.catId, 0, plang->dobj.dumpId);
11252 
11253 	if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11254 		dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
11255 				qlanname, NULL, NULL,
11256 				plang->lanowner, plang->lanacl, plang->rlanacl,
11257 				plang->initlanacl, plang->initrlanacl);
11258 
11259 	free(qlanname);
11260 
11261 	destroyPQExpBuffer(defqry);
11262 	destroyPQExpBuffer(delqry);
11263 }
11264 
11265 /*
11266  * format_function_arguments: generate function name and argument list
11267  *
11268  * This is used when we can rely on pg_get_function_arguments to format
11269  * the argument list.  Note, however, that pg_get_function_arguments
11270  * does not special-case zero-argument aggregates.
11271  */
11272 static char *
format_function_arguments(FuncInfo * finfo,char * funcargs,bool is_agg)11273 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11274 {
11275 	PQExpBufferData fn;
11276 
11277 	initPQExpBuffer(&fn);
11278 	appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11279 	if (is_agg && finfo->nargs == 0)
11280 		appendPQExpBufferStr(&fn, "(*)");
11281 	else
11282 		appendPQExpBuffer(&fn, "(%s)", funcargs);
11283 	return fn.data;
11284 }
11285 
11286 /*
11287  * format_function_arguments_old: generate function name and argument list
11288  *
11289  * The argument type names are qualified if needed.  The function name
11290  * is never qualified.
11291  *
11292  * This is used only with pre-8.4 servers, so we aren't expecting to see
11293  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11294  *
11295  * Any or all of allargtypes, argmodes, argnames may be NULL.
11296  */
11297 static char *
format_function_arguments_old(Archive * fout,FuncInfo * finfo,int nallargs,char ** allargtypes,char ** argmodes,char ** argnames)11298 format_function_arguments_old(Archive *fout,
11299 							  FuncInfo *finfo, int nallargs,
11300 							  char **allargtypes,
11301 							  char **argmodes,
11302 							  char **argnames)
11303 {
11304 	PQExpBufferData fn;
11305 	int			j;
11306 
11307 	initPQExpBuffer(&fn);
11308 	appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11309 	for (j = 0; j < nallargs; j++)
11310 	{
11311 		Oid			typid;
11312 		const char *typname;
11313 		const char *argmode;
11314 		const char *argname;
11315 
11316 		typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11317 		typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11318 
11319 		if (argmodes)
11320 		{
11321 			switch (argmodes[j][0])
11322 			{
11323 				case PROARGMODE_IN:
11324 					argmode = "";
11325 					break;
11326 				case PROARGMODE_OUT:
11327 					argmode = "OUT ";
11328 					break;
11329 				case PROARGMODE_INOUT:
11330 					argmode = "INOUT ";
11331 					break;
11332 				default:
11333 					write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
11334 					argmode = "";
11335 					break;
11336 			}
11337 		}
11338 		else
11339 			argmode = "";
11340 
11341 		argname = argnames ? argnames[j] : (char *) NULL;
11342 		if (argname && argname[0] == '\0')
11343 			argname = NULL;
11344 
11345 		appendPQExpBuffer(&fn, "%s%s%s%s%s",
11346 						  (j > 0) ? ", " : "",
11347 						  argmode,
11348 						  argname ? fmtId(argname) : "",
11349 						  argname ? " " : "",
11350 						  typname);
11351 	}
11352 	appendPQExpBufferChar(&fn, ')');
11353 	return fn.data;
11354 }
11355 
11356 /*
11357  * format_function_signature: generate function name and argument list
11358  *
11359  * This is like format_function_arguments_old except that only a minimal
11360  * list of input argument types is generated; this is sufficient to
11361  * reference the function, but not to define it.
11362  *
11363  * If honor_quotes is false then the function name is never quoted.
11364  * This is appropriate for use in TOC tags, but not in SQL commands.
11365  */
11366 static char *
format_function_signature(Archive * fout,FuncInfo * finfo,bool honor_quotes)11367 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11368 {
11369 	PQExpBufferData fn;
11370 	int			j;
11371 
11372 	initPQExpBuffer(&fn);
11373 	if (honor_quotes)
11374 		appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11375 	else
11376 		appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11377 	for (j = 0; j < finfo->nargs; j++)
11378 	{
11379 		if (j > 0)
11380 			appendPQExpBufferStr(&fn, ", ");
11381 
11382 		appendPQExpBufferStr(&fn,
11383 							 getFormattedTypeName(fout, finfo->argtypes[j],
11384 												  zeroAsOpaque));
11385 	}
11386 	appendPQExpBufferChar(&fn, ')');
11387 	return fn.data;
11388 }
11389 
11390 
11391 /*
11392  * dumpFunc:
11393  *	  dump out one function
11394  */
11395 static void
dumpFunc(Archive * fout,FuncInfo * finfo)11396 dumpFunc(Archive *fout, FuncInfo *finfo)
11397 {
11398 	DumpOptions *dopt = fout->dopt;
11399 	PQExpBuffer query;
11400 	PQExpBuffer q;
11401 	PQExpBuffer delqry;
11402 	PQExpBuffer asPart;
11403 	PGresult   *res;
11404 	char	   *funcsig;		/* identity signature */
11405 	char	   *funcfullsig = NULL;		/* full signature */
11406 	char	   *funcsig_tag;
11407 	char	   *proretset;
11408 	char	   *prosrc;
11409 	char	   *probin;
11410 	char	   *funcargs;
11411 	char	   *funciargs;
11412 	char	   *funcresult;
11413 	char	   *proallargtypes;
11414 	char	   *proargmodes;
11415 	char	   *proargnames;
11416 	char	   *protrftypes;
11417 	char	   *proiswindow;
11418 	char	   *provolatile;
11419 	char	   *proisstrict;
11420 	char	   *prosecdef;
11421 	char	   *proleakproof;
11422 	char	   *proconfig;
11423 	char	   *procost;
11424 	char	   *prorows;
11425 	char	   *proparallel;
11426 	char	   *lanname;
11427 	int			nallargs;
11428 	char	  **allargtypes = NULL;
11429 	char	  **argmodes = NULL;
11430 	char	  **argnames = NULL;
11431 	char	  **configitems = NULL;
11432 	int			nconfigitems = 0;
11433 	int			i;
11434 
11435 	/* Skip if not to be dumped */
11436 	if (!finfo->dobj.dump || dopt->dataOnly)
11437 		return;
11438 
11439 	query = createPQExpBuffer();
11440 	q = createPQExpBuffer();
11441 	delqry = createPQExpBuffer();
11442 	asPart = createPQExpBuffer();
11443 
11444 	/* Fetch function-specific details */
11445 	if (fout->remoteVersion >= 90600)
11446 	{
11447 		/*
11448 		 * proparallel was added in 9.6
11449 		 */
11450 		appendPQExpBuffer(query,
11451 						  "SELECT proretset, prosrc, probin, "
11452 					"pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11453 		  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11454 					 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11455 						  "array_to_string(protrftypes, ' ') AS protrftypes, "
11456 						  "proiswindow, provolatile, proisstrict, prosecdef, "
11457 						  "proleakproof, proconfig, procost, prorows, "
11458 						  "proparallel, "
11459 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11460 						  "FROM pg_catalog.pg_proc "
11461 						  "WHERE oid = '%u'::pg_catalog.oid",
11462 						  finfo->dobj.catId.oid);
11463 	}
11464 	else if (fout->remoteVersion >= 90500)
11465 	{
11466 		/*
11467 		 * protrftypes was added in 9.5
11468 		 */
11469 		appendPQExpBuffer(query,
11470 						  "SELECT proretset, prosrc, probin, "
11471 					"pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11472 		  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11473 					 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11474 						  "array_to_string(protrftypes, ' ') AS protrftypes, "
11475 						  "proiswindow, provolatile, proisstrict, prosecdef, "
11476 						  "proleakproof, proconfig, procost, prorows, "
11477 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11478 						  "FROM pg_catalog.pg_proc "
11479 						  "WHERE oid = '%u'::pg_catalog.oid",
11480 						  finfo->dobj.catId.oid);
11481 	}
11482 	else if (fout->remoteVersion >= 90200)
11483 	{
11484 		/*
11485 		 * proleakproof was added in 9.2
11486 		 */
11487 		appendPQExpBuffer(query,
11488 						  "SELECT proretset, prosrc, probin, "
11489 					"pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11490 		  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11491 					 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11492 						  "proiswindow, provolatile, proisstrict, prosecdef, "
11493 						  "proleakproof, proconfig, procost, prorows, "
11494 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11495 						  "FROM pg_catalog.pg_proc "
11496 						  "WHERE oid = '%u'::pg_catalog.oid",
11497 						  finfo->dobj.catId.oid);
11498 	}
11499 	else if (fout->remoteVersion >= 80400)
11500 	{
11501 		/*
11502 		 * In 8.4 and up we rely on pg_get_function_arguments and
11503 		 * pg_get_function_result instead of examining proallargtypes etc.
11504 		 */
11505 		appendPQExpBuffer(query,
11506 						  "SELECT proretset, prosrc, probin, "
11507 					"pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11508 		  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11509 					 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11510 						  "proiswindow, provolatile, proisstrict, prosecdef, "
11511 						  "false AS proleakproof, "
11512 						  " proconfig, procost, prorows, "
11513 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11514 						  "FROM pg_catalog.pg_proc "
11515 						  "WHERE oid = '%u'::pg_catalog.oid",
11516 						  finfo->dobj.catId.oid);
11517 	}
11518 	else if (fout->remoteVersion >= 80300)
11519 	{
11520 		appendPQExpBuffer(query,
11521 						  "SELECT proretset, prosrc, probin, "
11522 						  "proallargtypes, proargmodes, proargnames, "
11523 						  "false AS proiswindow, "
11524 						  "provolatile, proisstrict, prosecdef, "
11525 						  "false AS proleakproof, "
11526 						  "proconfig, procost, prorows, "
11527 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11528 						  "FROM pg_catalog.pg_proc "
11529 						  "WHERE oid = '%u'::pg_catalog.oid",
11530 						  finfo->dobj.catId.oid);
11531 	}
11532 	else if (fout->remoteVersion >= 80100)
11533 	{
11534 		appendPQExpBuffer(query,
11535 						  "SELECT proretset, prosrc, probin, "
11536 						  "proallargtypes, proargmodes, proargnames, "
11537 						  "false AS proiswindow, "
11538 						  "provolatile, proisstrict, prosecdef, "
11539 						  "false AS proleakproof, "
11540 						  "null AS proconfig, 0 AS procost, 0 AS prorows, "
11541 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11542 						  "FROM pg_catalog.pg_proc "
11543 						  "WHERE oid = '%u'::pg_catalog.oid",
11544 						  finfo->dobj.catId.oid);
11545 	}
11546 	else if (fout->remoteVersion >= 80000)
11547 	{
11548 		appendPQExpBuffer(query,
11549 						  "SELECT proretset, prosrc, probin, "
11550 						  "null AS proallargtypes, "
11551 						  "null AS proargmodes, "
11552 						  "proargnames, "
11553 						  "false AS proiswindow, "
11554 						  "provolatile, proisstrict, prosecdef, "
11555 						  "false AS proleakproof, "
11556 						  "null AS proconfig, 0 AS procost, 0 AS prorows, "
11557 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11558 						  "FROM pg_catalog.pg_proc "
11559 						  "WHERE oid = '%u'::pg_catalog.oid",
11560 						  finfo->dobj.catId.oid);
11561 	}
11562 	else if (fout->remoteVersion >= 70300)
11563 	{
11564 		appendPQExpBuffer(query,
11565 						  "SELECT proretset, prosrc, probin, "
11566 						  "null AS proallargtypes, "
11567 						  "null AS proargmodes, "
11568 						  "null AS proargnames, "
11569 						  "false AS proiswindow, "
11570 						  "provolatile, proisstrict, prosecdef, "
11571 						  "false AS proleakproof, "
11572 						  "null AS proconfig, 0 AS procost, 0 AS prorows, "
11573 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11574 						  "FROM pg_catalog.pg_proc "
11575 						  "WHERE oid = '%u'::pg_catalog.oid",
11576 						  finfo->dobj.catId.oid);
11577 	}
11578 	else if (fout->remoteVersion >= 70100)
11579 	{
11580 		appendPQExpBuffer(query,
11581 						  "SELECT proretset, prosrc, probin, "
11582 						  "null AS proallargtypes, "
11583 						  "null AS proargmodes, "
11584 						  "null AS proargnames, "
11585 						  "false AS proiswindow, "
11586 			 "case when proiscachable then 'i' else 'v' end AS provolatile, "
11587 						  "proisstrict, "
11588 						  "false AS prosecdef, "
11589 						  "false AS proleakproof, "
11590 						  "null AS proconfig, 0 AS procost, 0 AS prorows, "
11591 		  "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
11592 						  "FROM pg_proc "
11593 						  "WHERE oid = '%u'::oid",
11594 						  finfo->dobj.catId.oid);
11595 	}
11596 	else
11597 	{
11598 		appendPQExpBuffer(query,
11599 						  "SELECT proretset, prosrc, probin, "
11600 						  "null AS proallargtypes, "
11601 						  "null AS proargmodes, "
11602 						  "null AS proargnames, "
11603 						  "false AS proiswindow, "
11604 			 "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
11605 						  "false AS proisstrict, "
11606 						  "false AS prosecdef, "
11607 						  "false AS proleakproof, "
11608 						  "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
11609 		  "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
11610 						  "FROM pg_proc "
11611 						  "WHERE oid = '%u'::oid",
11612 						  finfo->dobj.catId.oid);
11613 	}
11614 
11615 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
11616 
11617 	proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11618 	prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11619 	probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11620 	if (fout->remoteVersion >= 80400)
11621 	{
11622 		funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11623 		funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11624 		funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11625 		proallargtypes = proargmodes = proargnames = NULL;
11626 	}
11627 	else
11628 	{
11629 		proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11630 		proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11631 		proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11632 		funcargs = funciargs = funcresult = NULL;
11633 	}
11634 	if (PQfnumber(res, "protrftypes") != -1)
11635 		protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11636 	else
11637 		protrftypes = NULL;
11638 	proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
11639 	provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11640 	proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11641 	prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11642 	proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11643 	proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11644 	procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11645 	prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11646 
11647 	if (PQfnumber(res, "proparallel") != -1)
11648 		proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11649 	else
11650 		proparallel = NULL;
11651 
11652 	lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11653 
11654 	/*
11655 	 * Before 7.3, the "C" language name was actually upper case in the
11656 	 * pg_language catalog.  If we don't down-case it, we'll get a lookup
11657 	 * failure at restore.
11658 	 */
11659 	if (fout->remoteVersion < 70300 &&
11660 		strcmp(lanname, "C") == 0)
11661 		lanname = "c";
11662 
11663 	/*
11664 	 * See backend/commands/functioncmds.c for details of how the 'AS' clause
11665 	 * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11666 	 * versions would set it to "-".  There are no known cases in which prosrc
11667 	 * is unused, so the tests below for "-" are probably useless.
11668 	 */
11669 	if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11670 	{
11671 		appendPQExpBufferStr(asPart, "AS ");
11672 		appendStringLiteralAH(asPart, probin, fout);
11673 		if (strcmp(prosrc, "-") != 0)
11674 		{
11675 			appendPQExpBufferStr(asPart, ", ");
11676 
11677 			/*
11678 			 * where we have bin, use dollar quoting if allowed and src
11679 			 * contains quote or backslash; else use regular quoting.
11680 			 */
11681 			if (dopt->disable_dollar_quoting ||
11682 			  (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11683 				appendStringLiteralAH(asPart, prosrc, fout);
11684 			else
11685 				appendStringLiteralDQ(asPart, prosrc, NULL);
11686 		}
11687 	}
11688 	else
11689 	{
11690 		if (strcmp(prosrc, "-") != 0)
11691 		{
11692 			appendPQExpBufferStr(asPart, "AS ");
11693 			/* with no bin, dollar quote src unconditionally if allowed */
11694 			if (dopt->disable_dollar_quoting)
11695 				appendStringLiteralAH(asPart, prosrc, fout);
11696 			else
11697 				appendStringLiteralDQ(asPart, prosrc, NULL);
11698 		}
11699 	}
11700 
11701 	nallargs = finfo->nargs;	/* unless we learn different from allargs */
11702 
11703 	if (proallargtypes && *proallargtypes)
11704 	{
11705 		int			nitems = 0;
11706 
11707 		if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11708 			nitems < finfo->nargs)
11709 		{
11710 			write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
11711 			if (allargtypes)
11712 				free(allargtypes);
11713 			allargtypes = NULL;
11714 		}
11715 		else
11716 			nallargs = nitems;
11717 	}
11718 
11719 	if (proargmodes && *proargmodes)
11720 	{
11721 		int			nitems = 0;
11722 
11723 		if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11724 			nitems != nallargs)
11725 		{
11726 			write_msg(NULL, "WARNING: could not parse proargmodes array\n");
11727 			if (argmodes)
11728 				free(argmodes);
11729 			argmodes = NULL;
11730 		}
11731 	}
11732 
11733 	if (proargnames && *proargnames)
11734 	{
11735 		int			nitems = 0;
11736 
11737 		if (!parsePGArray(proargnames, &argnames, &nitems) ||
11738 			nitems != nallargs)
11739 		{
11740 			write_msg(NULL, "WARNING: could not parse proargnames array\n");
11741 			if (argnames)
11742 				free(argnames);
11743 			argnames = NULL;
11744 		}
11745 	}
11746 
11747 	if (proconfig && *proconfig)
11748 	{
11749 		if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11750 		{
11751 			write_msg(NULL, "WARNING: could not parse proconfig array\n");
11752 			if (configitems)
11753 				free(configitems);
11754 			configitems = NULL;
11755 			nconfigitems = 0;
11756 		}
11757 	}
11758 
11759 	if (funcargs)
11760 	{
11761 		/* 8.4 or later; we rely on server-side code for most of the work */
11762 		funcfullsig = format_function_arguments(finfo, funcargs, false);
11763 		funcsig = format_function_arguments(finfo, funciargs, false);
11764 	}
11765 	else
11766 		/* pre-8.4, do it ourselves */
11767 		funcsig = format_function_arguments_old(fout,
11768 												finfo, nallargs, allargtypes,
11769 												argmodes, argnames);
11770 
11771 	funcsig_tag = format_function_signature(fout, finfo, false);
11772 
11773 	appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
11774 					  fmtId(finfo->dobj.namespace->dobj.name),
11775 					  funcsig);
11776 
11777 	appendPQExpBuffer(q, "CREATE FUNCTION %s.%s ",
11778 					  fmtId(finfo->dobj.namespace->dobj.name),
11779 					  funcfullsig ? funcfullsig :
11780 					  funcsig);
11781 
11782 	if (funcresult)
11783 		appendPQExpBuffer(q, "RETURNS %s", funcresult);
11784 	else
11785 		appendPQExpBuffer(q, "RETURNS %s%s",
11786 						  (proretset[0] == 't') ? "SETOF " : "",
11787 						  getFormattedTypeName(fout, finfo->prorettype,
11788 											   zeroAsOpaque));
11789 
11790 	appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11791 
11792 	if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11793 	{
11794 		Oid		   *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11795 		int			i;
11796 
11797 		appendPQExpBufferStr(q, " TRANSFORM ");
11798 		parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11799 		for (i = 0; typeids[i]; i++)
11800 		{
11801 			if (i != 0)
11802 				appendPQExpBufferStr(q, ", ");
11803 			appendPQExpBuffer(q, "FOR TYPE %s",
11804 						 getFormattedTypeName(fout, typeids[i], zeroAsNone));
11805 		}
11806 	}
11807 
11808 	if (proiswindow[0] == 't')
11809 		appendPQExpBufferStr(q, " WINDOW");
11810 
11811 	if (provolatile[0] != PROVOLATILE_VOLATILE)
11812 	{
11813 		if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11814 			appendPQExpBufferStr(q, " IMMUTABLE");
11815 		else if (provolatile[0] == PROVOLATILE_STABLE)
11816 			appendPQExpBufferStr(q, " STABLE");
11817 		else if (provolatile[0] != PROVOLATILE_VOLATILE)
11818 			exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
11819 						  finfo->dobj.name);
11820 	}
11821 
11822 	if (proisstrict[0] == 't')
11823 		appendPQExpBufferStr(q, " STRICT");
11824 
11825 	if (prosecdef[0] == 't')
11826 		appendPQExpBufferStr(q, " SECURITY DEFINER");
11827 
11828 	if (proleakproof[0] == 't')
11829 		appendPQExpBufferStr(q, " LEAKPROOF");
11830 
11831 	/*
11832 	 * COST and ROWS are emitted only if present and not default, so as not to
11833 	 * break backwards-compatibility of the dump without need.  Keep this code
11834 	 * in sync with the defaults in functioncmds.c.
11835 	 */
11836 	if (strcmp(procost, "0") != 0)
11837 	{
11838 		if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
11839 		{
11840 			/* default cost is 1 */
11841 			if (strcmp(procost, "1") != 0)
11842 				appendPQExpBuffer(q, " COST %s", procost);
11843 		}
11844 		else
11845 		{
11846 			/* default cost is 100 */
11847 			if (strcmp(procost, "100") != 0)
11848 				appendPQExpBuffer(q, " COST %s", procost);
11849 		}
11850 	}
11851 	if (proretset[0] == 't' &&
11852 		strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
11853 		appendPQExpBuffer(q, " ROWS %s", prorows);
11854 
11855 	if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
11856 	{
11857 		if (proparallel[0] == PROPARALLEL_SAFE)
11858 			appendPQExpBufferStr(q, " PARALLEL SAFE");
11859 		else if (proparallel[0] == PROPARALLEL_RESTRICTED)
11860 			appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
11861 		else if (proparallel[0] != PROPARALLEL_UNSAFE)
11862 			exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
11863 						  finfo->dobj.name);
11864 	}
11865 
11866 	for (i = 0; i < nconfigitems; i++)
11867 	{
11868 		/* we feel free to scribble on configitems[] here */
11869 		char	   *configitem = configitems[i];
11870 		char	   *pos;
11871 
11872 		pos = strchr(configitem, '=');
11873 		if (pos == NULL)
11874 			continue;
11875 		*pos++ = '\0';
11876 		appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
11877 
11878 		/*
11879 		 * Variables that are marked GUC_LIST_QUOTE were already fully quoted
11880 		 * by flatten_set_variable_args() before they were put into the
11881 		 * proconfig array.  However, because the quoting rules used there
11882 		 * aren't exactly like SQL's, we have to break the list value apart
11883 		 * and then quote the elements as string literals.  (The elements may
11884 		 * be double-quoted as-is, but we can't just feed them to the SQL
11885 		 * parser; it would do the wrong thing with elements that are
11886 		 * zero-length or longer than NAMEDATALEN.)
11887 		 *
11888 		 * Variables that are not so marked should just be emitted as simple
11889 		 * string literals.  If the variable is not known to
11890 		 * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
11891 		 * to use GUC_LIST_QUOTE for extension variables.
11892 		 */
11893 		if (variable_is_guc_list_quote(configitem))
11894 		{
11895 			char	  **namelist;
11896 			char	  **nameptr;
11897 
11898 			/* Parse string into list of identifiers */
11899 			/* this shouldn't fail really */
11900 			if (SplitGUCList(pos, ',', &namelist))
11901 			{
11902 				for (nameptr = namelist; *nameptr; nameptr++)
11903 				{
11904 					if (nameptr != namelist)
11905 						appendPQExpBufferStr(q, ", ");
11906 					appendStringLiteralAH(q, *nameptr, fout);
11907 				}
11908 			}
11909 			pg_free(namelist);
11910 		}
11911 		else
11912 			appendStringLiteralAH(q, pos, fout);
11913 	}
11914 
11915 	appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
11916 
11917 	append_depends_on_extension(fout, q, &finfo->dobj,
11918 								"pg_catalog.pg_proc", "FUNCTION",
11919 								psprintf("%s.%s",
11920 										 fmtId(finfo->dobj.namespace->dobj.name),
11921 										 funcsig));
11922 
11923 	if (dopt->binary_upgrade)
11924 		binary_upgrade_extension_member(q, &finfo->dobj,
11925 										"FUNCTION", funcsig,
11926 										finfo->dobj.namespace->dobj.name);
11927 
11928 	if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11929 		ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
11930 					 funcsig_tag,
11931 					 finfo->dobj.namespace->dobj.name,
11932 					 NULL,
11933 					 finfo->rolname, false,
11934 					 "FUNCTION", SECTION_PRE_DATA,
11935 					 q->data, delqry->data, NULL,
11936 					 NULL, 0,
11937 					 NULL, NULL);
11938 
11939 	/* Dump Function Comments and Security Labels */
11940 	if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11941 		dumpComment(fout, "FUNCTION", funcsig,
11942 					finfo->dobj.namespace->dobj.name, finfo->rolname,
11943 					finfo->dobj.catId, 0, finfo->dobj.dumpId);
11944 
11945 	if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11946 		dumpSecLabel(fout, "FUNCTION", funcsig,
11947 					 finfo->dobj.namespace->dobj.name, finfo->rolname,
11948 					 finfo->dobj.catId, 0, finfo->dobj.dumpId);
11949 
11950 	if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
11951 		dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, "FUNCTION",
11952 				funcsig, NULL,
11953 				finfo->dobj.namespace->dobj.name,
11954 				finfo->rolname, finfo->proacl, finfo->rproacl,
11955 				finfo->initproacl, finfo->initrproacl);
11956 
11957 	PQclear(res);
11958 
11959 	destroyPQExpBuffer(query);
11960 	destroyPQExpBuffer(q);
11961 	destroyPQExpBuffer(delqry);
11962 	destroyPQExpBuffer(asPart);
11963 	free(funcsig);
11964 	if (funcfullsig)
11965 		free(funcfullsig);
11966 	free(funcsig_tag);
11967 	if (allargtypes)
11968 		free(allargtypes);
11969 	if (argmodes)
11970 		free(argmodes);
11971 	if (argnames)
11972 		free(argnames);
11973 	if (configitems)
11974 		free(configitems);
11975 }
11976 
11977 
11978 /*
11979  * Dump a user-defined cast
11980  */
11981 static void
dumpCast(Archive * fout,CastInfo * cast)11982 dumpCast(Archive *fout, CastInfo *cast)
11983 {
11984 	DumpOptions *dopt = fout->dopt;
11985 	PQExpBuffer defqry;
11986 	PQExpBuffer delqry;
11987 	PQExpBuffer labelq;
11988 	PQExpBuffer castargs;
11989 	FuncInfo   *funcInfo = NULL;
11990 	const char *sourceType;
11991 	const char *targetType;
11992 
11993 	/* Skip if not to be dumped */
11994 	if (!cast->dobj.dump || dopt->dataOnly)
11995 		return;
11996 
11997 	/* Cannot dump if we don't have the cast function's info */
11998 	if (OidIsValid(cast->castfunc))
11999 	{
12000 		funcInfo = findFuncByOid(cast->castfunc);
12001 		if (funcInfo == NULL)
12002 			exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12003 						  cast->castfunc);
12004 	}
12005 
12006 	defqry = createPQExpBuffer();
12007 	delqry = createPQExpBuffer();
12008 	labelq = createPQExpBuffer();
12009 	castargs = createPQExpBuffer();
12010 
12011 	sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12012 	targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12013 	appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12014 					  sourceType, targetType);
12015 
12016 	appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12017 					  sourceType, targetType);
12018 
12019 	switch (cast->castmethod)
12020 	{
12021 		case COERCION_METHOD_BINARY:
12022 			appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12023 			break;
12024 		case COERCION_METHOD_INOUT:
12025 			appendPQExpBufferStr(defqry, "WITH INOUT");
12026 			break;
12027 		case COERCION_METHOD_FUNCTION:
12028 			if (funcInfo)
12029 			{
12030 				char	   *fsig = format_function_signature(fout, funcInfo, true);
12031 
12032 				/*
12033 				 * Always qualify the function name (format_function_signature
12034 				 * won't qualify it).
12035 				 */
12036 				appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12037 						   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12038 				free(fsig);
12039 			}
12040 			else
12041 				write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
12042 			break;
12043 		default:
12044 			write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
12045 	}
12046 
12047 	if (cast->castcontext == 'a')
12048 		appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12049 	else if (cast->castcontext == 'i')
12050 		appendPQExpBufferStr(defqry, " AS IMPLICIT");
12051 	appendPQExpBufferStr(defqry, ";\n");
12052 
12053 	appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12054 					  sourceType, targetType);
12055 
12056 	appendPQExpBuffer(castargs, "(%s AS %s)",
12057 					  sourceType, targetType);
12058 
12059 	if (dopt->binary_upgrade)
12060 		binary_upgrade_extension_member(defqry, &cast->dobj,
12061 										"CAST", castargs->data, NULL);
12062 
12063 	if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12064 		ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12065 					 labelq->data,
12066 					 NULL, NULL, "",
12067 					 false, "CAST", SECTION_PRE_DATA,
12068 					 defqry->data, delqry->data, NULL,
12069 					 NULL, 0,
12070 					 NULL, NULL);
12071 
12072 	/* Dump Cast Comments */
12073 	if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12074 		dumpComment(fout, "CAST", castargs->data,
12075 					NULL, "",
12076 					cast->dobj.catId, 0, cast->dobj.dumpId);
12077 
12078 	destroyPQExpBuffer(defqry);
12079 	destroyPQExpBuffer(delqry);
12080 	destroyPQExpBuffer(labelq);
12081 	destroyPQExpBuffer(castargs);
12082 }
12083 
12084 /*
12085  * Dump a transform
12086  */
12087 static void
dumpTransform(Archive * fout,TransformInfo * transform)12088 dumpTransform(Archive *fout, TransformInfo *transform)
12089 {
12090 	DumpOptions *dopt = fout->dopt;
12091 	PQExpBuffer defqry;
12092 	PQExpBuffer delqry;
12093 	PQExpBuffer labelq;
12094 	PQExpBuffer transformargs;
12095 	FuncInfo   *fromsqlFuncInfo = NULL;
12096 	FuncInfo   *tosqlFuncInfo = NULL;
12097 	char	   *lanname;
12098 	const char *transformType;
12099 
12100 	/* Skip if not to be dumped */
12101 	if (!transform->dobj.dump || dopt->dataOnly)
12102 		return;
12103 
12104 	/* Cannot dump if we don't have the transform functions' info */
12105 	if (OidIsValid(transform->trffromsql))
12106 	{
12107 		fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12108 		if (fromsqlFuncInfo == NULL)
12109 			exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12110 						  transform->trffromsql);
12111 	}
12112 	if (OidIsValid(transform->trftosql))
12113 	{
12114 		tosqlFuncInfo = findFuncByOid(transform->trftosql);
12115 		if (tosqlFuncInfo == NULL)
12116 			exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12117 						  transform->trftosql);
12118 	}
12119 
12120 	defqry = createPQExpBuffer();
12121 	delqry = createPQExpBuffer();
12122 	labelq = createPQExpBuffer();
12123 	transformargs = createPQExpBuffer();
12124 
12125 	lanname = get_language_name(fout, transform->trflang);
12126 	transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12127 
12128 	appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12129 					  transformType, lanname);
12130 
12131 	appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12132 					  transformType, lanname);
12133 
12134 	if (!transform->trffromsql && !transform->trftosql)
12135 		write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
12136 
12137 	if (transform->trffromsql)
12138 	{
12139 		if (fromsqlFuncInfo)
12140 		{
12141 			char	   *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12142 
12143 			/*
12144 			 * Always qualify the function name (format_function_signature
12145 			 * won't qualify it).
12146 			 */
12147 			appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12148 					fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12149 			free(fsig);
12150 		}
12151 		else
12152 			write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
12153 	}
12154 
12155 	if (transform->trftosql)
12156 	{
12157 		if (transform->trffromsql)
12158 			appendPQExpBuffer(defqry, ", ");
12159 
12160 		if (tosqlFuncInfo)
12161 		{
12162 			char	   *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12163 
12164 			/*
12165 			 * Always qualify the function name (format_function_signature
12166 			 * won't qualify it).
12167 			 */
12168 			appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12169 					  fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12170 			free(fsig);
12171 		}
12172 		else
12173 			write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
12174 	}
12175 
12176 	appendPQExpBuffer(defqry, ");\n");
12177 
12178 	appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12179 					  transformType, lanname);
12180 
12181 	appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12182 					  transformType, lanname);
12183 
12184 	if (dopt->binary_upgrade)
12185 		binary_upgrade_extension_member(defqry, &transform->dobj,
12186 									 "TRANSFORM", transformargs->data, NULL);
12187 
12188 	if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12189 		ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12190 					 labelq->data,
12191 					 NULL, NULL, "",
12192 					 false, "TRANSFORM", SECTION_PRE_DATA,
12193 					 defqry->data, delqry->data, NULL,
12194 					 transform->dobj.dependencies, transform->dobj.nDeps,
12195 					 NULL, NULL);
12196 
12197 	/* Dump Transform Comments */
12198 	if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12199 		dumpComment(fout, "TRANSFORM", transformargs->data,
12200 					NULL, "",
12201 					transform->dobj.catId, 0, transform->dobj.dumpId);
12202 
12203 	free(lanname);
12204 	destroyPQExpBuffer(defqry);
12205 	destroyPQExpBuffer(delqry);
12206 	destroyPQExpBuffer(labelq);
12207 	destroyPQExpBuffer(transformargs);
12208 }
12209 
12210 
12211 /*
12212  * dumpOpr
12213  *	  write out a single operator definition
12214  */
12215 static void
dumpOpr(Archive * fout,OprInfo * oprinfo)12216 dumpOpr(Archive *fout, OprInfo *oprinfo)
12217 {
12218 	DumpOptions *dopt = fout->dopt;
12219 	PQExpBuffer query;
12220 	PQExpBuffer q;
12221 	PQExpBuffer delq;
12222 	PQExpBuffer oprid;
12223 	PQExpBuffer details;
12224 	const char *name;
12225 	PGresult   *res;
12226 	int			i_oprkind;
12227 	int			i_oprcode;
12228 	int			i_oprleft;
12229 	int			i_oprright;
12230 	int			i_oprcom;
12231 	int			i_oprnegate;
12232 	int			i_oprrest;
12233 	int			i_oprjoin;
12234 	int			i_oprcanmerge;
12235 	int			i_oprcanhash;
12236 	char	   *oprkind;
12237 	char	   *oprcode;
12238 	char	   *oprleft;
12239 	char	   *oprright;
12240 	char	   *oprcom;
12241 	char	   *oprnegate;
12242 	char	   *oprrest;
12243 	char	   *oprjoin;
12244 	char	   *oprcanmerge;
12245 	char	   *oprcanhash;
12246 	char	   *oprregproc;
12247 	char	   *oprref;
12248 
12249 	/* Skip if not to be dumped */
12250 	if (!oprinfo->dobj.dump || dopt->dataOnly)
12251 		return;
12252 
12253 	/*
12254 	 * some operators are invalid because they were the result of user
12255 	 * defining operators before commutators exist
12256 	 */
12257 	if (!OidIsValid(oprinfo->oprcode))
12258 		return;
12259 
12260 	query = createPQExpBuffer();
12261 	q = createPQExpBuffer();
12262 	delq = createPQExpBuffer();
12263 	oprid = createPQExpBuffer();
12264 	details = createPQExpBuffer();
12265 
12266 	if (fout->remoteVersion >= 80300)
12267 	{
12268 		appendPQExpBuffer(query, "SELECT oprkind, "
12269 						  "oprcode::pg_catalog.regprocedure, "
12270 						  "oprleft::pg_catalog.regtype, "
12271 						  "oprright::pg_catalog.regtype, "
12272 						  "oprcom, "
12273 						  "oprnegate, "
12274 						  "oprrest::pg_catalog.regprocedure, "
12275 						  "oprjoin::pg_catalog.regprocedure, "
12276 						  "oprcanmerge, oprcanhash "
12277 						  "FROM pg_catalog.pg_operator "
12278 						  "WHERE oid = '%u'::pg_catalog.oid",
12279 						  oprinfo->dobj.catId.oid);
12280 	}
12281 	else if (fout->remoteVersion >= 70300)
12282 	{
12283 		appendPQExpBuffer(query, "SELECT oprkind, "
12284 						  "oprcode::pg_catalog.regprocedure, "
12285 						  "oprleft::pg_catalog.regtype, "
12286 						  "oprright::pg_catalog.regtype, "
12287 						  "oprcom, "
12288 						  "oprnegate, "
12289 						  "oprrest::pg_catalog.regprocedure, "
12290 						  "oprjoin::pg_catalog.regprocedure, "
12291 						  "(oprlsortop != 0) AS oprcanmerge, "
12292 						  "oprcanhash "
12293 						  "FROM pg_catalog.pg_operator "
12294 						  "WHERE oid = '%u'::pg_catalog.oid",
12295 						  oprinfo->dobj.catId.oid);
12296 	}
12297 	else if (fout->remoteVersion >= 70100)
12298 	{
12299 		appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
12300 						  "CASE WHEN oprleft = 0 THEN '-' "
12301 						  "ELSE format_type(oprleft, NULL) END AS oprleft, "
12302 						  "CASE WHEN oprright = 0 THEN '-' "
12303 						  "ELSE format_type(oprright, NULL) END AS oprright, "
12304 						  "oprcom, oprnegate, oprrest, oprjoin, "
12305 						  "(oprlsortop != 0) AS oprcanmerge, "
12306 						  "oprcanhash "
12307 						  "FROM pg_operator "
12308 						  "WHERE oid = '%u'::oid",
12309 						  oprinfo->dobj.catId.oid);
12310 	}
12311 	else
12312 	{
12313 		appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
12314 						  "CASE WHEN oprleft = 0 THEN '-'::name "
12315 						  "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
12316 						  "CASE WHEN oprright = 0 THEN '-'::name "
12317 						  "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
12318 						  "oprcom, oprnegate, oprrest, oprjoin, "
12319 						  "(oprlsortop != 0) AS oprcanmerge, "
12320 						  "oprcanhash "
12321 						  "FROM pg_operator "
12322 						  "WHERE oid = '%u'::oid",
12323 						  oprinfo->dobj.catId.oid);
12324 	}
12325 
12326 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
12327 
12328 	i_oprkind = PQfnumber(res, "oprkind");
12329 	i_oprcode = PQfnumber(res, "oprcode");
12330 	i_oprleft = PQfnumber(res, "oprleft");
12331 	i_oprright = PQfnumber(res, "oprright");
12332 	i_oprcom = PQfnumber(res, "oprcom");
12333 	i_oprnegate = PQfnumber(res, "oprnegate");
12334 	i_oprrest = PQfnumber(res, "oprrest");
12335 	i_oprjoin = PQfnumber(res, "oprjoin");
12336 	i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12337 	i_oprcanhash = PQfnumber(res, "oprcanhash");
12338 
12339 	oprkind = PQgetvalue(res, 0, i_oprkind);
12340 	oprcode = PQgetvalue(res, 0, i_oprcode);
12341 	oprleft = PQgetvalue(res, 0, i_oprleft);
12342 	oprright = PQgetvalue(res, 0, i_oprright);
12343 	oprcom = PQgetvalue(res, 0, i_oprcom);
12344 	oprnegate = PQgetvalue(res, 0, i_oprnegate);
12345 	oprrest = PQgetvalue(res, 0, i_oprrest);
12346 	oprjoin = PQgetvalue(res, 0, i_oprjoin);
12347 	oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12348 	oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12349 
12350 	oprregproc = convertRegProcReference(fout, oprcode);
12351 	if (oprregproc)
12352 	{
12353 		appendPQExpBuffer(details, "    PROCEDURE = %s", oprregproc);
12354 		free(oprregproc);
12355 	}
12356 
12357 	appendPQExpBuffer(oprid, "%s (",
12358 					  oprinfo->dobj.name);
12359 
12360 	/*
12361 	 * right unary means there's a left arg and left unary means there's a
12362 	 * right arg
12363 	 */
12364 	if (strcmp(oprkind, "r") == 0 ||
12365 		strcmp(oprkind, "b") == 0)
12366 	{
12367 		if (fout->remoteVersion >= 70100)
12368 			name = oprleft;
12369 		else
12370 			name = fmtId(oprleft);
12371 		appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
12372 		appendPQExpBufferStr(oprid, name);
12373 	}
12374 	else
12375 		appendPQExpBufferStr(oprid, "NONE");
12376 
12377 	if (strcmp(oprkind, "l") == 0 ||
12378 		strcmp(oprkind, "b") == 0)
12379 	{
12380 		if (fout->remoteVersion >= 70100)
12381 			name = oprright;
12382 		else
12383 			name = fmtId(oprright);
12384 		appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
12385 		appendPQExpBuffer(oprid, ", %s)", name);
12386 	}
12387 	else
12388 		appendPQExpBufferStr(oprid, ", NONE)");
12389 
12390 	oprref = getFormattedOperatorName(fout, oprcom);
12391 	if (oprref)
12392 	{
12393 		appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12394 		free(oprref);
12395 	}
12396 
12397 	oprref = getFormattedOperatorName(fout, oprnegate);
12398 	if (oprref)
12399 	{
12400 		appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12401 		free(oprref);
12402 	}
12403 
12404 	if (strcmp(oprcanmerge, "t") == 0)
12405 		appendPQExpBufferStr(details, ",\n    MERGES");
12406 
12407 	if (strcmp(oprcanhash, "t") == 0)
12408 		appendPQExpBufferStr(details, ",\n    HASHES");
12409 
12410 	oprregproc = convertRegProcReference(fout, oprrest);
12411 	if (oprregproc)
12412 	{
12413 		appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12414 		free(oprregproc);
12415 	}
12416 
12417 	oprregproc = convertRegProcReference(fout, oprjoin);
12418 	if (oprregproc)
12419 	{
12420 		appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12421 		free(oprregproc);
12422 	}
12423 
12424 	appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12425 					  fmtId(oprinfo->dobj.namespace->dobj.name),
12426 					  oprid->data);
12427 
12428 	appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12429 					  fmtId(oprinfo->dobj.namespace->dobj.name),
12430 					  oprinfo->dobj.name, details->data);
12431 
12432 	if (dopt->binary_upgrade)
12433 		binary_upgrade_extension_member(q, &oprinfo->dobj,
12434 										"OPERATOR", oprid->data,
12435 										oprinfo->dobj.namespace->dobj.name);
12436 
12437 	if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12438 		ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12439 					 oprinfo->dobj.name,
12440 					 oprinfo->dobj.namespace->dobj.name,
12441 					 NULL,
12442 					 oprinfo->rolname,
12443 					 false, "OPERATOR", SECTION_PRE_DATA,
12444 					 q->data, delq->data, NULL,
12445 					 NULL, 0,
12446 					 NULL, NULL);
12447 
12448 	/* Dump Operator Comments */
12449 	if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12450 		dumpComment(fout, "OPERATOR", oprid->data,
12451 					oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12452 					oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12453 
12454 	PQclear(res);
12455 
12456 	destroyPQExpBuffer(query);
12457 	destroyPQExpBuffer(q);
12458 	destroyPQExpBuffer(delq);
12459 	destroyPQExpBuffer(oprid);
12460 	destroyPQExpBuffer(details);
12461 }
12462 
12463 /*
12464  * Convert a function reference obtained from pg_operator
12465  *
12466  * Returns allocated string of what to print, or NULL if function references
12467  * is InvalidOid. Returned string is expected to be free'd by the caller.
12468  *
12469  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
12470  * argument-types part.  In prior versions, the input is a REGPROC display.
12471  */
12472 static char *
convertRegProcReference(Archive * fout,const char * proc)12473 convertRegProcReference(Archive *fout, const char *proc)
12474 {
12475 	/* In all cases "-" means a null reference */
12476 	if (strcmp(proc, "-") == 0)
12477 		return NULL;
12478 
12479 	if (fout->remoteVersion >= 70300)
12480 	{
12481 		char	   *name;
12482 		char	   *paren;
12483 		bool		inquote;
12484 
12485 		name = pg_strdup(proc);
12486 		/* find non-double-quoted left paren */
12487 		inquote = false;
12488 		for (paren = name; *paren; paren++)
12489 		{
12490 			if (*paren == '(' && !inquote)
12491 			{
12492 				*paren = '\0';
12493 				break;
12494 			}
12495 			if (*paren == '"')
12496 				inquote = !inquote;
12497 		}
12498 		return name;
12499 	}
12500 
12501 	/* REGPROC before 7.3 does not quote its result */
12502 	return pg_strdup(fmtId(proc));
12503 }
12504 
12505 /*
12506  * getFormattedOperatorName - retrieve the operator name for the
12507  * given operator OID (presented in string form).
12508  *
12509  * Returns an allocated string, or NULL if the given OID is InvalidOid.
12510  * Caller is responsible for free'ing result string.
12511  *
12512  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12513  * useful in commands where the operator's argument types can be inferred from
12514  * context.  We always schema-qualify the name, though.  The predecessor to
12515  * this code tried to skip the schema qualification if possible, but that led
12516  * to wrong results in corner cases, such as if an operator and its negator
12517  * are in different schemas.
12518  */
12519 static char *
getFormattedOperatorName(Archive * fout,const char * oproid)12520 getFormattedOperatorName(Archive *fout, const char *oproid)
12521 {
12522 	OprInfo    *oprInfo;
12523 
12524 	/* In all cases "0" means a null reference */
12525 	if (strcmp(oproid, "0") == 0)
12526 		return NULL;
12527 
12528 	oprInfo = findOprByOid(atooid(oproid));
12529 	if (oprInfo == NULL)
12530 	{
12531 		write_msg(NULL, "WARNING: could not find operator with OID %s\n",
12532 				  oproid);
12533 		return NULL;
12534 	}
12535 
12536 	return psprintf("OPERATOR(%s.%s)",
12537 					fmtId(oprInfo->dobj.namespace->dobj.name),
12538 					oprInfo->dobj.name);
12539 }
12540 
12541 /*
12542  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12543  *
12544  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12545  * argument lists of these functions are predetermined.  Note that the
12546  * caller should ensure we are in the proper schema, because the results
12547  * are search path dependent!
12548  */
12549 static char *
convertTSFunction(Archive * fout,Oid funcOid)12550 convertTSFunction(Archive *fout, Oid funcOid)
12551 {
12552 	char	   *result;
12553 	char		query[128];
12554 	PGresult   *res;
12555 
12556 	snprintf(query, sizeof(query),
12557 			 "SELECT '%u'::pg_catalog.regproc", funcOid);
12558 	res = ExecuteSqlQueryForSingleRow(fout, query);
12559 
12560 	result = pg_strdup(PQgetvalue(res, 0, 0));
12561 
12562 	PQclear(res);
12563 
12564 	return result;
12565 }
12566 
12567 /*
12568  * dumpAccessMethod
12569  *	  write out a single access method definition
12570  */
12571 static void
dumpAccessMethod(Archive * fout,AccessMethodInfo * aminfo)12572 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12573 {
12574 	DumpOptions *dopt = fout->dopt;
12575 	PQExpBuffer q;
12576 	PQExpBuffer delq;
12577 	char	   *qamname;
12578 
12579 	/* Skip if not to be dumped */
12580 	if (!aminfo->dobj.dump || dopt->dataOnly)
12581 		return;
12582 
12583 	q = createPQExpBuffer();
12584 	delq = createPQExpBuffer();
12585 
12586 	qamname = pg_strdup(fmtId(aminfo->dobj.name));
12587 
12588 	appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12589 
12590 	switch (aminfo->amtype)
12591 	{
12592 		case AMTYPE_INDEX:
12593 			appendPQExpBuffer(q, "TYPE INDEX ");
12594 			break;
12595 		default:
12596 			write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
12597 					  aminfo->amtype, qamname);
12598 			destroyPQExpBuffer(q);
12599 			destroyPQExpBuffer(delq);
12600 			free(qamname);
12601 			return;
12602 	}
12603 
12604 	appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12605 
12606 	appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12607 					  qamname);
12608 
12609 	if (dopt->binary_upgrade)
12610 		binary_upgrade_extension_member(q, &aminfo->dobj,
12611 										"ACCESS METHOD", qamname, NULL);
12612 
12613 	if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12614 		ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12615 					 aminfo->dobj.name,
12616 					 NULL,
12617 					 NULL,
12618 					 "",
12619 					 false, "ACCESS METHOD", SECTION_PRE_DATA,
12620 					 q->data, delq->data, NULL,
12621 					 NULL, 0,
12622 					 NULL, NULL);
12623 
12624 	/* Dump Access Method Comments */
12625 	if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12626 		dumpComment(fout, "ACCESS METHOD", qamname,
12627 					NULL, "",
12628 					aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12629 
12630 	destroyPQExpBuffer(q);
12631 	destroyPQExpBuffer(delq);
12632 	free(qamname);
12633 }
12634 
12635 /*
12636  * dumpOpclass
12637  *	  write out a single operator class definition
12638  */
12639 static void
dumpOpclass(Archive * fout,OpclassInfo * opcinfo)12640 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12641 {
12642 	DumpOptions *dopt = fout->dopt;
12643 	PQExpBuffer query;
12644 	PQExpBuffer q;
12645 	PQExpBuffer delq;
12646 	PQExpBuffer nameusing;
12647 	PGresult   *res;
12648 	int			ntups;
12649 	int			i_opcintype;
12650 	int			i_opckeytype;
12651 	int			i_opcdefault;
12652 	int			i_opcfamily;
12653 	int			i_opcfamilyname;
12654 	int			i_opcfamilynsp;
12655 	int			i_amname;
12656 	int			i_amopstrategy;
12657 	int			i_amopreqcheck;
12658 	int			i_amopopr;
12659 	int			i_sortfamily;
12660 	int			i_sortfamilynsp;
12661 	int			i_amprocnum;
12662 	int			i_amproc;
12663 	int			i_amproclefttype;
12664 	int			i_amprocrighttype;
12665 	char	   *opcintype;
12666 	char	   *opckeytype;
12667 	char	   *opcdefault;
12668 	char	   *opcfamily;
12669 	char	   *opcfamilyname;
12670 	char	   *opcfamilynsp;
12671 	char	   *amname;
12672 	char	   *amopstrategy;
12673 	char	   *amopreqcheck;
12674 	char	   *amopopr;
12675 	char	   *sortfamily;
12676 	char	   *sortfamilynsp;
12677 	char	   *amprocnum;
12678 	char	   *amproc;
12679 	char	   *amproclefttype;
12680 	char	   *amprocrighttype;
12681 	bool		needComma;
12682 	int			i;
12683 
12684 	/* Skip if not to be dumped */
12685 	if (!opcinfo->dobj.dump || dopt->dataOnly)
12686 		return;
12687 
12688 	/*
12689 	 * XXX currently we do not implement dumping of operator classes from
12690 	 * pre-7.3 databases.  This could be done but it seems not worth the
12691 	 * trouble.
12692 	 */
12693 	if (fout->remoteVersion < 70300)
12694 		return;
12695 
12696 	query = createPQExpBuffer();
12697 	q = createPQExpBuffer();
12698 	delq = createPQExpBuffer();
12699 	nameusing = createPQExpBuffer();
12700 
12701 	/* Get additional fields from the pg_opclass row */
12702 	if (fout->remoteVersion >= 80300)
12703 	{
12704 		appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12705 						  "opckeytype::pg_catalog.regtype, "
12706 						  "opcdefault, opcfamily, "
12707 						  "opfname AS opcfamilyname, "
12708 						  "nspname AS opcfamilynsp, "
12709 						  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12710 						  "FROM pg_catalog.pg_opclass c "
12711 				   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12712 			   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12713 						  "WHERE c.oid = '%u'::pg_catalog.oid",
12714 						  opcinfo->dobj.catId.oid);
12715 	}
12716 	else
12717 	{
12718 		appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12719 						  "opckeytype::pg_catalog.regtype, "
12720 						  "opcdefault, NULL AS opcfamily, "
12721 						  "NULL AS opcfamilyname, "
12722 						  "NULL AS opcfamilynsp, "
12723 		"(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12724 						  "FROM pg_catalog.pg_opclass "
12725 						  "WHERE oid = '%u'::pg_catalog.oid",
12726 						  opcinfo->dobj.catId.oid);
12727 	}
12728 
12729 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
12730 
12731 	i_opcintype = PQfnumber(res, "opcintype");
12732 	i_opckeytype = PQfnumber(res, "opckeytype");
12733 	i_opcdefault = PQfnumber(res, "opcdefault");
12734 	i_opcfamily = PQfnumber(res, "opcfamily");
12735 	i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12736 	i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12737 	i_amname = PQfnumber(res, "amname");
12738 
12739 	/* opcintype may still be needed after we PQclear res */
12740 	opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12741 	opckeytype = PQgetvalue(res, 0, i_opckeytype);
12742 	opcdefault = PQgetvalue(res, 0, i_opcdefault);
12743 	/* opcfamily will still be needed after we PQclear res */
12744 	opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12745 	opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12746 	opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12747 	/* amname will still be needed after we PQclear res */
12748 	amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12749 
12750 	appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12751 					  fmtQualifiedDumpable(opcinfo));
12752 	appendPQExpBuffer(delq, " USING %s;\n",
12753 					  fmtId(amname));
12754 
12755 	/* Build the fixed portion of the CREATE command */
12756 	appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12757 					  fmtQualifiedDumpable(opcinfo));
12758 	if (strcmp(opcdefault, "t") == 0)
12759 		appendPQExpBufferStr(q, "DEFAULT ");
12760 	appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12761 					  opcintype,
12762 					  fmtId(amname));
12763 	if (strlen(opcfamilyname) > 0)
12764 	{
12765 		appendPQExpBufferStr(q, " FAMILY ");
12766 		appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12767 		appendPQExpBufferStr(q, fmtId(opcfamilyname));
12768 	}
12769 	appendPQExpBufferStr(q, " AS\n    ");
12770 
12771 	needComma = false;
12772 
12773 	if (strcmp(opckeytype, "-") != 0)
12774 	{
12775 		appendPQExpBuffer(q, "STORAGE %s",
12776 						  opckeytype);
12777 		needComma = true;
12778 	}
12779 
12780 	PQclear(res);
12781 
12782 	/*
12783 	 * Now fetch and print the OPERATOR entries (pg_amop rows).
12784 	 *
12785 	 * Print only those opfamily members that are tied to the opclass by
12786 	 * pg_depend entries.
12787 	 *
12788 	 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12789 	 * older server's opclass in which it is used.  This is to avoid
12790 	 * hard-to-detect breakage if a newer pg_dump is used to dump from an
12791 	 * older server and then reload into that old version.  This can go away
12792 	 * once 8.3 is so old as to not be of interest to anyone.
12793 	 */
12794 	resetPQExpBuffer(query);
12795 
12796 	if (fout->remoteVersion >= 90100)
12797 	{
12798 		appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12799 						  "amopopr::pg_catalog.regoperator, "
12800 						  "opfname AS sortfamily, "
12801 						  "nspname AS sortfamilynsp "
12802 				   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12803 						  "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12804 			  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12805 			   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12806 		   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12807 						  "AND refobjid = '%u'::pg_catalog.oid "
12808 						  "AND amopfamily = '%s'::pg_catalog.oid "
12809 						  "ORDER BY amopstrategy",
12810 						  opcinfo->dobj.catId.oid,
12811 						  opcfamily);
12812 	}
12813 	else if (fout->remoteVersion >= 80400)
12814 	{
12815 		appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12816 						  "amopopr::pg_catalog.regoperator, "
12817 						  "NULL AS sortfamily, "
12818 						  "NULL AS sortfamilynsp "
12819 						  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12820 		   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12821 						  "AND refobjid = '%u'::pg_catalog.oid "
12822 				   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12823 						  "AND objid = ao.oid "
12824 						  "ORDER BY amopstrategy",
12825 						  opcinfo->dobj.catId.oid);
12826 	}
12827 	else if (fout->remoteVersion >= 80300)
12828 	{
12829 		appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12830 						  "amopopr::pg_catalog.regoperator, "
12831 						  "NULL AS sortfamily, "
12832 						  "NULL AS sortfamilynsp "
12833 						  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12834 		   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12835 						  "AND refobjid = '%u'::pg_catalog.oid "
12836 				   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12837 						  "AND objid = ao.oid "
12838 						  "ORDER BY amopstrategy",
12839 						  opcinfo->dobj.catId.oid);
12840 	}
12841 	else
12842 	{
12843 		/*
12844 		 * Here, we print all entries since there are no opfamilies and hence
12845 		 * no loose operators to worry about.
12846 		 */
12847 		appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12848 						  "amopopr::pg_catalog.regoperator, "
12849 						  "NULL AS sortfamily, "
12850 						  "NULL AS sortfamilynsp "
12851 						  "FROM pg_catalog.pg_amop "
12852 						  "WHERE amopclaid = '%u'::pg_catalog.oid "
12853 						  "ORDER BY amopstrategy",
12854 						  opcinfo->dobj.catId.oid);
12855 	}
12856 
12857 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12858 
12859 	ntups = PQntuples(res);
12860 
12861 	i_amopstrategy = PQfnumber(res, "amopstrategy");
12862 	i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12863 	i_amopopr = PQfnumber(res, "amopopr");
12864 	i_sortfamily = PQfnumber(res, "sortfamily");
12865 	i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12866 
12867 	for (i = 0; i < ntups; i++)
12868 	{
12869 		amopstrategy = PQgetvalue(res, i, i_amopstrategy);
12870 		amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
12871 		amopopr = PQgetvalue(res, i, i_amopopr);
12872 		sortfamily = PQgetvalue(res, i, i_sortfamily);
12873 		sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
12874 
12875 		if (needComma)
12876 			appendPQExpBufferStr(q, " ,\n    ");
12877 
12878 		appendPQExpBuffer(q, "OPERATOR %s %s",
12879 						  amopstrategy, amopopr);
12880 
12881 		if (strlen(sortfamily) > 0)
12882 		{
12883 			appendPQExpBufferStr(q, " FOR ORDER BY ");
12884 			appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
12885 			appendPQExpBufferStr(q, fmtId(sortfamily));
12886 		}
12887 
12888 		if (strcmp(amopreqcheck, "t") == 0)
12889 			appendPQExpBufferStr(q, " RECHECK");
12890 
12891 		needComma = true;
12892 	}
12893 
12894 	PQclear(res);
12895 
12896 	/*
12897 	 * Now fetch and print the FUNCTION entries (pg_amproc rows).
12898 	 *
12899 	 * Print only those opfamily members that are tied to the opclass by
12900 	 * pg_depend entries.
12901 	 *
12902 	 * We print the amproclefttype/amprocrighttype even though in most cases
12903 	 * the backend could deduce the right values, because of the corner case
12904 	 * of a btree sort support function for a cross-type comparison.  That's
12905 	 * only allowed in 9.2 and later, but for simplicity print them in all
12906 	 * versions that have the columns.
12907 	 */
12908 	resetPQExpBuffer(query);
12909 
12910 	if (fout->remoteVersion >= 80300)
12911 	{
12912 		appendPQExpBuffer(query, "SELECT amprocnum, "
12913 						  "amproc::pg_catalog.regprocedure, "
12914 						  "amproclefttype::pg_catalog.regtype, "
12915 						  "amprocrighttype::pg_catalog.regtype "
12916 						"FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
12917 		   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12918 						  "AND refobjid = '%u'::pg_catalog.oid "
12919 				 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
12920 						  "AND objid = ap.oid "
12921 						  "ORDER BY amprocnum",
12922 						  opcinfo->dobj.catId.oid);
12923 	}
12924 	else
12925 	{
12926 		appendPQExpBuffer(query, "SELECT amprocnum, "
12927 						  "amproc::pg_catalog.regprocedure, "
12928 						  "'' AS amproclefttype, "
12929 						  "'' AS amprocrighttype "
12930 						  "FROM pg_catalog.pg_amproc "
12931 						  "WHERE amopclaid = '%u'::pg_catalog.oid "
12932 						  "ORDER BY amprocnum",
12933 						  opcinfo->dobj.catId.oid);
12934 	}
12935 
12936 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12937 
12938 	ntups = PQntuples(res);
12939 
12940 	i_amprocnum = PQfnumber(res, "amprocnum");
12941 	i_amproc = PQfnumber(res, "amproc");
12942 	i_amproclefttype = PQfnumber(res, "amproclefttype");
12943 	i_amprocrighttype = PQfnumber(res, "amprocrighttype");
12944 
12945 	for (i = 0; i < ntups; i++)
12946 	{
12947 		amprocnum = PQgetvalue(res, i, i_amprocnum);
12948 		amproc = PQgetvalue(res, i, i_amproc);
12949 		amproclefttype = PQgetvalue(res, i, i_amproclefttype);
12950 		amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
12951 
12952 		if (needComma)
12953 			appendPQExpBufferStr(q, " ,\n    ");
12954 
12955 		appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
12956 
12957 		if (*amproclefttype && *amprocrighttype)
12958 			appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
12959 
12960 		appendPQExpBuffer(q, " %s", amproc);
12961 
12962 		needComma = true;
12963 	}
12964 
12965 	PQclear(res);
12966 
12967 	/*
12968 	 * If needComma is still false it means we haven't added anything after
12969 	 * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
12970 	 * clause with the same datatype.  This isn't sanctioned by the
12971 	 * documentation, but actually DefineOpClass will treat it as a no-op.
12972 	 */
12973 	if (!needComma)
12974 		appendPQExpBuffer(q, "STORAGE %s", opcintype);
12975 
12976 	appendPQExpBufferStr(q, ";\n");
12977 
12978 	appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
12979 	appendPQExpBuffer(nameusing, " USING %s",
12980 					  fmtId(amname));
12981 
12982 	if (dopt->binary_upgrade)
12983 		binary_upgrade_extension_member(q, &opcinfo->dobj,
12984 										"OPERATOR CLASS", nameusing->data,
12985 										opcinfo->dobj.namespace->dobj.name);
12986 
12987 	if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12988 		ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
12989 					 opcinfo->dobj.name,
12990 					 opcinfo->dobj.namespace->dobj.name,
12991 					 NULL,
12992 					 opcinfo->rolname,
12993 					 false, "OPERATOR CLASS", SECTION_PRE_DATA,
12994 					 q->data, delq->data, NULL,
12995 					 NULL, 0,
12996 					 NULL, NULL);
12997 
12998 	/* Dump Operator Class Comments */
12999 	if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13000 		dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13001 					opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13002 					opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13003 
13004 	free(opcintype);
13005 	free(opcfamily);
13006 	free(amname);
13007 	destroyPQExpBuffer(query);
13008 	destroyPQExpBuffer(q);
13009 	destroyPQExpBuffer(delq);
13010 	destroyPQExpBuffer(nameusing);
13011 }
13012 
13013 /*
13014  * dumpOpfamily
13015  *	  write out a single operator family definition
13016  *
13017  * Note: this also dumps any "loose" operator members that aren't bound to a
13018  * specific opclass within the opfamily.
13019  */
13020 static void
dumpOpfamily(Archive * fout,OpfamilyInfo * opfinfo)13021 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
13022 {
13023 	DumpOptions *dopt = fout->dopt;
13024 	PQExpBuffer query;
13025 	PQExpBuffer q;
13026 	PQExpBuffer delq;
13027 	PQExpBuffer nameusing;
13028 	PGresult   *res;
13029 	PGresult   *res_ops;
13030 	PGresult   *res_procs;
13031 	int			ntups;
13032 	int			i_amname;
13033 	int			i_amopstrategy;
13034 	int			i_amopreqcheck;
13035 	int			i_amopopr;
13036 	int			i_sortfamily;
13037 	int			i_sortfamilynsp;
13038 	int			i_amprocnum;
13039 	int			i_amproc;
13040 	int			i_amproclefttype;
13041 	int			i_amprocrighttype;
13042 	char	   *amname;
13043 	char	   *amopstrategy;
13044 	char	   *amopreqcheck;
13045 	char	   *amopopr;
13046 	char	   *sortfamily;
13047 	char	   *sortfamilynsp;
13048 	char	   *amprocnum;
13049 	char	   *amproc;
13050 	char	   *amproclefttype;
13051 	char	   *amprocrighttype;
13052 	bool		needComma;
13053 	int			i;
13054 
13055 	/* Skip if not to be dumped */
13056 	if (!opfinfo->dobj.dump || dopt->dataOnly)
13057 		return;
13058 
13059 	query = createPQExpBuffer();
13060 	q = createPQExpBuffer();
13061 	delq = createPQExpBuffer();
13062 	nameusing = createPQExpBuffer();
13063 
13064 	/*
13065 	 * Fetch only those opfamily members that are tied directly to the
13066 	 * opfamily by pg_depend entries.
13067 	 *
13068 	 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13069 	 * older server's opclass in which it is used.  This is to avoid
13070 	 * hard-to-detect breakage if a newer pg_dump is used to dump from an
13071 	 * older server and then reload into that old version.  This can go away
13072 	 * once 8.3 is so old as to not be of interest to anyone.
13073 	 */
13074 	if (fout->remoteVersion >= 90100)
13075 	{
13076 		appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13077 						  "amopopr::pg_catalog.regoperator, "
13078 						  "opfname AS sortfamily, "
13079 						  "nspname AS sortfamilynsp "
13080 				   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13081 						  "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13082 			  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13083 			   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13084 		  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13085 						  "AND refobjid = '%u'::pg_catalog.oid "
13086 						  "AND amopfamily = '%u'::pg_catalog.oid "
13087 						  "ORDER BY amopstrategy",
13088 						  opfinfo->dobj.catId.oid,
13089 						  opfinfo->dobj.catId.oid);
13090 	}
13091 	else if (fout->remoteVersion >= 80400)
13092 	{
13093 		appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13094 						  "amopopr::pg_catalog.regoperator, "
13095 						  "NULL AS sortfamily, "
13096 						  "NULL AS sortfamilynsp "
13097 						  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13098 		  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13099 						  "AND refobjid = '%u'::pg_catalog.oid "
13100 				   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13101 						  "AND objid = ao.oid "
13102 						  "ORDER BY amopstrategy",
13103 						  opfinfo->dobj.catId.oid);
13104 	}
13105 	else
13106 	{
13107 		appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13108 						  "amopopr::pg_catalog.regoperator, "
13109 						  "NULL AS sortfamily, "
13110 						  "NULL AS sortfamilynsp "
13111 						  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13112 		  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13113 						  "AND refobjid = '%u'::pg_catalog.oid "
13114 				   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13115 						  "AND objid = ao.oid "
13116 						  "ORDER BY amopstrategy",
13117 						  opfinfo->dobj.catId.oid);
13118 	}
13119 
13120 	res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13121 
13122 	resetPQExpBuffer(query);
13123 
13124 	appendPQExpBuffer(query, "SELECT amprocnum, "
13125 					  "amproc::pg_catalog.regprocedure, "
13126 					  "amproclefttype::pg_catalog.regtype, "
13127 					  "amprocrighttype::pg_catalog.regtype "
13128 					  "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13129 		  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13130 					  "AND refobjid = '%u'::pg_catalog.oid "
13131 				 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13132 					  "AND objid = ap.oid "
13133 					  "ORDER BY amprocnum",
13134 					  opfinfo->dobj.catId.oid);
13135 
13136 	res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13137 
13138 	/* Get additional fields from the pg_opfamily row */
13139 	resetPQExpBuffer(query);
13140 
13141 	appendPQExpBuffer(query, "SELECT "
13142 	 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13143 					  "FROM pg_catalog.pg_opfamily "
13144 					  "WHERE oid = '%u'::pg_catalog.oid",
13145 					  opfinfo->dobj.catId.oid);
13146 
13147 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
13148 
13149 	i_amname = PQfnumber(res, "amname");
13150 
13151 	/* amname will still be needed after we PQclear res */
13152 	amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13153 
13154 	appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13155 					  fmtQualifiedDumpable(opfinfo));
13156 	appendPQExpBuffer(delq, " USING %s;\n",
13157 					  fmtId(amname));
13158 
13159 	/* Build the fixed portion of the CREATE command */
13160 	appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13161 					  fmtQualifiedDumpable(opfinfo));
13162 	appendPQExpBuffer(q, " USING %s;\n",
13163 					  fmtId(amname));
13164 
13165 	PQclear(res);
13166 
13167 	/* Do we need an ALTER to add loose members? */
13168 	if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13169 	{
13170 		appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13171 						  fmtQualifiedDumpable(opfinfo));
13172 		appendPQExpBuffer(q, " USING %s ADD\n    ",
13173 						  fmtId(amname));
13174 
13175 		needComma = false;
13176 
13177 		/*
13178 		 * Now fetch and print the OPERATOR entries (pg_amop rows).
13179 		 */
13180 		ntups = PQntuples(res_ops);
13181 
13182 		i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13183 		i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13184 		i_amopopr = PQfnumber(res_ops, "amopopr");
13185 		i_sortfamily = PQfnumber(res_ops, "sortfamily");
13186 		i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13187 
13188 		for (i = 0; i < ntups; i++)
13189 		{
13190 			amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13191 			amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13192 			amopopr = PQgetvalue(res_ops, i, i_amopopr);
13193 			sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13194 			sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13195 
13196 			if (needComma)
13197 				appendPQExpBufferStr(q, " ,\n    ");
13198 
13199 			appendPQExpBuffer(q, "OPERATOR %s %s",
13200 							  amopstrategy, amopopr);
13201 
13202 			if (strlen(sortfamily) > 0)
13203 			{
13204 				appendPQExpBufferStr(q, " FOR ORDER BY ");
13205 				appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13206 				appendPQExpBufferStr(q, fmtId(sortfamily));
13207 			}
13208 
13209 			if (strcmp(amopreqcheck, "t") == 0)
13210 				appendPQExpBufferStr(q, " RECHECK");
13211 
13212 			needComma = true;
13213 		}
13214 
13215 		/*
13216 		 * Now fetch and print the FUNCTION entries (pg_amproc rows).
13217 		 */
13218 		ntups = PQntuples(res_procs);
13219 
13220 		i_amprocnum = PQfnumber(res_procs, "amprocnum");
13221 		i_amproc = PQfnumber(res_procs, "amproc");
13222 		i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13223 		i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13224 
13225 		for (i = 0; i < ntups; i++)
13226 		{
13227 			amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13228 			amproc = PQgetvalue(res_procs, i, i_amproc);
13229 			amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13230 			amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13231 
13232 			if (needComma)
13233 				appendPQExpBufferStr(q, " ,\n    ");
13234 
13235 			appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13236 							  amprocnum, amproclefttype, amprocrighttype,
13237 							  amproc);
13238 
13239 			needComma = true;
13240 		}
13241 
13242 		appendPQExpBufferStr(q, ";\n");
13243 	}
13244 
13245 	appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13246 	appendPQExpBuffer(nameusing, " USING %s",
13247 					  fmtId(amname));
13248 
13249 	if (dopt->binary_upgrade)
13250 		binary_upgrade_extension_member(q, &opfinfo->dobj,
13251 										"OPERATOR FAMILY", nameusing->data,
13252 										opfinfo->dobj.namespace->dobj.name);
13253 
13254 	if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13255 		ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13256 					 opfinfo->dobj.name,
13257 					 opfinfo->dobj.namespace->dobj.name,
13258 					 NULL,
13259 					 opfinfo->rolname,
13260 					 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
13261 					 q->data, delq->data, NULL,
13262 					 NULL, 0,
13263 					 NULL, NULL);
13264 
13265 	/* Dump Operator Family Comments */
13266 	if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13267 		dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13268 					opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13269 					opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13270 
13271 	free(amname);
13272 	PQclear(res_ops);
13273 	PQclear(res_procs);
13274 	destroyPQExpBuffer(query);
13275 	destroyPQExpBuffer(q);
13276 	destroyPQExpBuffer(delq);
13277 	destroyPQExpBuffer(nameusing);
13278 }
13279 
13280 /*
13281  * dumpCollation
13282  *	  write out a single collation definition
13283  */
13284 static void
dumpCollation(Archive * fout,CollInfo * collinfo)13285 dumpCollation(Archive *fout, CollInfo *collinfo)
13286 {
13287 	DumpOptions *dopt = fout->dopt;
13288 	PQExpBuffer query;
13289 	PQExpBuffer q;
13290 	PQExpBuffer delq;
13291 	char	   *qcollname;
13292 	PGresult   *res;
13293 	int			i_collcollate;
13294 	int			i_collctype;
13295 	const char *collcollate;
13296 	const char *collctype;
13297 
13298 	/* Skip if not to be dumped */
13299 	if (!collinfo->dobj.dump || dopt->dataOnly)
13300 		return;
13301 
13302 	query = createPQExpBuffer();
13303 	q = createPQExpBuffer();
13304 	delq = createPQExpBuffer();
13305 
13306 	qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13307 
13308 	/* Get collation-specific details */
13309 	appendPQExpBuffer(query, "SELECT "
13310 					  "collcollate, "
13311 					  "collctype "
13312 					  "FROM pg_catalog.pg_collation c "
13313 					  "WHERE c.oid = '%u'::pg_catalog.oid",
13314 					  collinfo->dobj.catId.oid);
13315 
13316 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
13317 
13318 	i_collcollate = PQfnumber(res, "collcollate");
13319 	i_collctype = PQfnumber(res, "collctype");
13320 
13321 	collcollate = PQgetvalue(res, 0, i_collcollate);
13322 	collctype = PQgetvalue(res, 0, i_collctype);
13323 
13324 	appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13325 					  fmtQualifiedDumpable(collinfo));
13326 
13327 	appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
13328 					  fmtQualifiedDumpable(collinfo));
13329 	appendStringLiteralAH(q, collcollate, fout);
13330 	appendPQExpBufferStr(q, ", lc_ctype = ");
13331 	appendStringLiteralAH(q, collctype, fout);
13332 	appendPQExpBufferStr(q, ");\n");
13333 
13334 	if (dopt->binary_upgrade)
13335 		binary_upgrade_extension_member(q, &collinfo->dobj,
13336 										"COLLATION", qcollname,
13337 										collinfo->dobj.namespace->dobj.name);
13338 
13339 	if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13340 		ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13341 					 collinfo->dobj.name,
13342 					 collinfo->dobj.namespace->dobj.name,
13343 					 NULL,
13344 					 collinfo->rolname,
13345 					 false, "COLLATION", SECTION_PRE_DATA,
13346 					 q->data, delq->data, NULL,
13347 					 NULL, 0,
13348 					 NULL, NULL);
13349 
13350 	/* Dump Collation Comments */
13351 	if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13352 		dumpComment(fout, "COLLATION", qcollname,
13353 					collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13354 					collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13355 
13356 	PQclear(res);
13357 
13358 	destroyPQExpBuffer(query);
13359 	destroyPQExpBuffer(q);
13360 	destroyPQExpBuffer(delq);
13361 	free(qcollname);
13362 }
13363 
13364 /*
13365  * dumpConversion
13366  *	  write out a single conversion definition
13367  */
13368 static void
dumpConversion(Archive * fout,ConvInfo * convinfo)13369 dumpConversion(Archive *fout, ConvInfo *convinfo)
13370 {
13371 	DumpOptions *dopt = fout->dopt;
13372 	PQExpBuffer query;
13373 	PQExpBuffer q;
13374 	PQExpBuffer delq;
13375 	char	   *qconvname;
13376 	PGresult   *res;
13377 	int			i_conforencoding;
13378 	int			i_contoencoding;
13379 	int			i_conproc;
13380 	int			i_condefault;
13381 	const char *conforencoding;
13382 	const char *contoencoding;
13383 	const char *conproc;
13384 	bool		condefault;
13385 
13386 	/* Skip if not to be dumped */
13387 	if (!convinfo->dobj.dump || dopt->dataOnly)
13388 		return;
13389 
13390 	query = createPQExpBuffer();
13391 	q = createPQExpBuffer();
13392 	delq = createPQExpBuffer();
13393 
13394 	qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13395 
13396 	/* Get conversion-specific details */
13397 	appendPQExpBuffer(query, "SELECT "
13398 		 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13399 		   "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13400 					  "conproc, condefault "
13401 					  "FROM pg_catalog.pg_conversion c "
13402 					  "WHERE c.oid = '%u'::pg_catalog.oid",
13403 					  convinfo->dobj.catId.oid);
13404 
13405 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
13406 
13407 	i_conforencoding = PQfnumber(res, "conforencoding");
13408 	i_contoencoding = PQfnumber(res, "contoencoding");
13409 	i_conproc = PQfnumber(res, "conproc");
13410 	i_condefault = PQfnumber(res, "condefault");
13411 
13412 	conforencoding = PQgetvalue(res, 0, i_conforencoding);
13413 	contoencoding = PQgetvalue(res, 0, i_contoencoding);
13414 	conproc = PQgetvalue(res, 0, i_conproc);
13415 	condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13416 
13417 	appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13418 					  fmtQualifiedDumpable(convinfo));
13419 
13420 	appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13421 					  (condefault) ? "DEFAULT " : "",
13422 					  fmtQualifiedDumpable(convinfo));
13423 	appendStringLiteralAH(q, conforencoding, fout);
13424 	appendPQExpBufferStr(q, " TO ");
13425 	appendStringLiteralAH(q, contoencoding, fout);
13426 	/* regproc is automatically quoted in 7.3 and above */
13427 	appendPQExpBuffer(q, " FROM %s;\n", conproc);
13428 
13429 	if (dopt->binary_upgrade)
13430 		binary_upgrade_extension_member(q, &convinfo->dobj,
13431 										"CONVERSION", qconvname,
13432 										convinfo->dobj.namespace->dobj.name);
13433 
13434 	if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13435 		ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13436 					 convinfo->dobj.name,
13437 					 convinfo->dobj.namespace->dobj.name,
13438 					 NULL,
13439 					 convinfo->rolname,
13440 					 false, "CONVERSION", SECTION_PRE_DATA,
13441 					 q->data, delq->data, NULL,
13442 					 NULL, 0,
13443 					 NULL, NULL);
13444 
13445 	/* Dump Conversion Comments */
13446 	if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13447 		dumpComment(fout, "CONVERSION", qconvname,
13448 					convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13449 					convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13450 
13451 	PQclear(res);
13452 
13453 	destroyPQExpBuffer(query);
13454 	destroyPQExpBuffer(q);
13455 	destroyPQExpBuffer(delq);
13456 	free(qconvname);
13457 }
13458 
13459 /*
13460  * format_aggregate_signature: generate aggregate name and argument list
13461  *
13462  * The argument type names are qualified if needed.  The aggregate name
13463  * is never qualified.
13464  */
13465 static char *
format_aggregate_signature(AggInfo * agginfo,Archive * fout,bool honor_quotes)13466 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13467 {
13468 	PQExpBufferData buf;
13469 	int			j;
13470 
13471 	initPQExpBuffer(&buf);
13472 	if (honor_quotes)
13473 		appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13474 	else
13475 		appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13476 
13477 	if (agginfo->aggfn.nargs == 0)
13478 		appendPQExpBuffer(&buf, "(*)");
13479 	else
13480 	{
13481 		appendPQExpBufferChar(&buf, '(');
13482 		for (j = 0; j < agginfo->aggfn.nargs; j++)
13483 			appendPQExpBuffer(&buf, "%s%s",
13484 							  (j > 0) ? ", " : "",
13485 							  getFormattedTypeName(fout,
13486 												   agginfo->aggfn.argtypes[j],
13487 												   zeroAsOpaque));
13488 		appendPQExpBufferChar(&buf, ')');
13489 	}
13490 	return buf.data;
13491 }
13492 
13493 /*
13494  * dumpAgg
13495  *	  write out a single aggregate definition
13496  */
13497 static void
dumpAgg(Archive * fout,AggInfo * agginfo)13498 dumpAgg(Archive *fout, AggInfo *agginfo)
13499 {
13500 	DumpOptions *dopt = fout->dopt;
13501 	PQExpBuffer query;
13502 	PQExpBuffer q;
13503 	PQExpBuffer delq;
13504 	PQExpBuffer details;
13505 	char	   *aggsig;			/* identity signature */
13506 	char	   *aggfullsig = NULL;		/* full signature */
13507 	char	   *aggsig_tag;
13508 	PGresult   *res;
13509 	int			i_aggtransfn;
13510 	int			i_aggfinalfn;
13511 	int			i_aggcombinefn;
13512 	int			i_aggserialfn;
13513 	int			i_aggdeserialfn;
13514 	int			i_aggmtransfn;
13515 	int			i_aggminvtransfn;
13516 	int			i_aggmfinalfn;
13517 	int			i_aggfinalextra;
13518 	int			i_aggmfinalextra;
13519 	int			i_aggsortop;
13520 	int			i_hypothetical;
13521 	int			i_aggtranstype;
13522 	int			i_aggtransspace;
13523 	int			i_aggmtranstype;
13524 	int			i_aggmtransspace;
13525 	int			i_agginitval;
13526 	int			i_aggminitval;
13527 	int			i_convertok;
13528 	int			i_proparallel;
13529 	const char *aggtransfn;
13530 	const char *aggfinalfn;
13531 	const char *aggcombinefn;
13532 	const char *aggserialfn;
13533 	const char *aggdeserialfn;
13534 	const char *aggmtransfn;
13535 	const char *aggminvtransfn;
13536 	const char *aggmfinalfn;
13537 	bool		aggfinalextra;
13538 	bool		aggmfinalextra;
13539 	const char *aggsortop;
13540 	char	   *aggsortconvop;
13541 	bool		hypothetical;
13542 	const char *aggtranstype;
13543 	const char *aggtransspace;
13544 	const char *aggmtranstype;
13545 	const char *aggmtransspace;
13546 	const char *agginitval;
13547 	const char *aggminitval;
13548 	bool		convertok;
13549 	const char *proparallel;
13550 
13551 	/* Skip if not to be dumped */
13552 	if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13553 		return;
13554 
13555 	query = createPQExpBuffer();
13556 	q = createPQExpBuffer();
13557 	delq = createPQExpBuffer();
13558 	details = createPQExpBuffer();
13559 
13560 	/* Get aggregate-specific details */
13561 	if (fout->remoteVersion >= 90600)
13562 	{
13563 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13564 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13565 					"aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13566 		   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13567 						  "aggfinalextra, aggmfinalextra, "
13568 						  "aggsortop, "
13569 						  "(aggkind = 'h') AS hypothetical, "
13570 						  "aggtransspace, agginitval, "
13571 						  "aggmtransspace, aggminitval, "
13572 						  "true AS convertok, "
13573 				  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13574 		"pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13575 						  "p.proparallel "
13576 					  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13577 						  "WHERE a.aggfnoid = p.oid "
13578 						  "AND p.oid = '%u'::pg_catalog.oid",
13579 						  agginfo->aggfn.dobj.catId.oid);
13580 	}
13581 	else if (fout->remoteVersion >= 90400)
13582 	{
13583 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13584 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13585 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
13586 						"'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13587 						  "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13588 						  "aggfinalextra, aggmfinalextra, "
13589 						  "aggsortop, "
13590 						  "(aggkind = 'h') AS hypothetical, "
13591 						  "aggtransspace, agginitval, "
13592 						  "aggmtransspace, aggminitval, "
13593 						  "true AS convertok, "
13594 				  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13595 		 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13596 					  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13597 						  "WHERE a.aggfnoid = p.oid "
13598 						  "AND p.oid = '%u'::pg_catalog.oid",
13599 						  agginfo->aggfn.dobj.catId.oid);
13600 	}
13601 	else if (fout->remoteVersion >= 80400)
13602 	{
13603 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13604 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13605 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
13606 						  "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13607 						  "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13608 						  "0 AS aggmtranstype, false AS aggfinalextra, "
13609 						  "false AS aggmfinalextra, "
13610 						  "aggsortop, "
13611 						  "false AS hypothetical, "
13612 						  "0 AS aggtransspace, agginitval, "
13613 						  "0 AS aggmtransspace, NULL AS aggminitval, "
13614 						  "true AS convertok, "
13615 				  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13616 		 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13617 					  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13618 						  "WHERE a.aggfnoid = p.oid "
13619 						  "AND p.oid = '%u'::pg_catalog.oid",
13620 						  agginfo->aggfn.dobj.catId.oid);
13621 	}
13622 	else if (fout->remoteVersion >= 80100)
13623 	{
13624 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13625 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13626 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
13627 						  "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13628 						  "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13629 						  "0 AS aggmtranstype, false AS aggfinalextra, "
13630 						  "false AS aggmfinalextra, "
13631 						  "aggsortop, "
13632 						  "false AS hypothetical, "
13633 						  "0 AS aggtransspace, agginitval, "
13634 						  "0 AS aggmtransspace, NULL AS aggminitval, "
13635 						  "true AS convertok "
13636 					  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13637 						  "WHERE a.aggfnoid = p.oid "
13638 						  "AND p.oid = '%u'::pg_catalog.oid",
13639 						  agginfo->aggfn.dobj.catId.oid);
13640 	}
13641 	else if (fout->remoteVersion >= 70300)
13642 	{
13643 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13644 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13645 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
13646 						  "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13647 						  "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13648 						  "0 AS aggmtranstype, false AS aggfinalextra, "
13649 						  "false AS aggmfinalextra, 0 AS aggsortop, "
13650 						  "false AS hypothetical, "
13651 						  "0 AS aggtransspace, agginitval, "
13652 						  "0 AS aggmtransspace, NULL AS aggminitval, "
13653 						  "true AS convertok "
13654 					  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13655 						  "WHERE a.aggfnoid = p.oid "
13656 						  "AND p.oid = '%u'::pg_catalog.oid",
13657 						  agginfo->aggfn.dobj.catId.oid);
13658 	}
13659 	else if (fout->remoteVersion >= 70100)
13660 	{
13661 		appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
13662 						  "format_type(aggtranstype, NULL) AS aggtranstype, "
13663 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
13664 						  "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13665 						  "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13666 						  "0 AS aggmtranstype, false AS aggfinalextra, "
13667 						  "false AS aggmfinalextra, 0 AS aggsortop, "
13668 						  "false AS hypothetical, "
13669 						  "0 AS aggtransspace, agginitval, "
13670 						  "0 AS aggmtransspace, NULL AS aggminitval, "
13671 						  "true AS convertok "
13672 						  "FROM pg_aggregate "
13673 						  "WHERE oid = '%u'::oid",
13674 						  agginfo->aggfn.dobj.catId.oid);
13675 	}
13676 	else
13677 	{
13678 		appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
13679 						  "aggfinalfn, "
13680 						  "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
13681 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
13682 						  "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13683 						  "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13684 						  "0 AS aggmtranstype, false AS aggfinalextra, "
13685 						  "false AS aggmfinalextra, 0 AS aggsortop, "
13686 						  "false AS hypothetical, "
13687 						  "0 AS aggtransspace, agginitval1 AS agginitval, "
13688 						  "0 AS aggmtransspace, NULL AS aggminitval, "
13689 						  "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
13690 						  "FROM pg_aggregate "
13691 						  "WHERE oid = '%u'::oid",
13692 						  agginfo->aggfn.dobj.catId.oid);
13693 	}
13694 
13695 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
13696 
13697 	i_aggtransfn = PQfnumber(res, "aggtransfn");
13698 	i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13699 	i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13700 	i_aggserialfn = PQfnumber(res, "aggserialfn");
13701 	i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13702 	i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13703 	i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13704 	i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13705 	i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13706 	i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13707 	i_aggsortop = PQfnumber(res, "aggsortop");
13708 	i_hypothetical = PQfnumber(res, "hypothetical");
13709 	i_aggtranstype = PQfnumber(res, "aggtranstype");
13710 	i_aggtransspace = PQfnumber(res, "aggtransspace");
13711 	i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13712 	i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13713 	i_agginitval = PQfnumber(res, "agginitval");
13714 	i_aggminitval = PQfnumber(res, "aggminitval");
13715 	i_convertok = PQfnumber(res, "convertok");
13716 	i_proparallel = PQfnumber(res, "proparallel");
13717 
13718 	aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13719 	aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13720 	aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13721 	aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13722 	aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13723 	aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13724 	aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13725 	aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13726 	aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13727 	aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13728 	aggsortop = PQgetvalue(res, 0, i_aggsortop);
13729 	hypothetical = (PQgetvalue(res, 0, i_hypothetical)[0] == 't');
13730 	aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13731 	aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13732 	aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13733 	aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13734 	agginitval = PQgetvalue(res, 0, i_agginitval);
13735 	aggminitval = PQgetvalue(res, 0, i_aggminitval);
13736 	convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13737 
13738 	if (fout->remoteVersion >= 80400)
13739 	{
13740 		/* 8.4 or later; we rely on server-side code for most of the work */
13741 		char	   *funcargs;
13742 		char	   *funciargs;
13743 
13744 		funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13745 		funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13746 		aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13747 		aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13748 	}
13749 	else
13750 		/* pre-8.4, do it ourselves */
13751 		aggsig = format_aggregate_signature(agginfo, fout, true);
13752 
13753 	aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13754 
13755 	if (i_proparallel != -1)
13756 		proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13757 	else
13758 		proparallel = NULL;
13759 
13760 	if (!convertok)
13761 	{
13762 		write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
13763 				  aggsig);
13764 
13765 		if (aggfullsig)
13766 			free(aggfullsig);
13767 
13768 		free(aggsig);
13769 
13770 		return;
13771 	}
13772 
13773 	if (fout->remoteVersion >= 70300)
13774 	{
13775 		/* If using 7.3's regproc or regtype, data is already quoted */
13776 		appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13777 						  aggtransfn,
13778 						  aggtranstype);
13779 	}
13780 	else if (fout->remoteVersion >= 70100)
13781 	{
13782 		/* format_type quotes, regproc does not */
13783 		appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13784 						  fmtId(aggtransfn),
13785 						  aggtranstype);
13786 	}
13787 	else
13788 	{
13789 		/* need quotes all around */
13790 		appendPQExpBuffer(details, "    SFUNC = %s,\n",
13791 						  fmtId(aggtransfn));
13792 		appendPQExpBuffer(details, "    STYPE = %s",
13793 						  fmtId(aggtranstype));
13794 	}
13795 
13796 	if (strcmp(aggtransspace, "0") != 0)
13797 	{
13798 		appendPQExpBuffer(details, ",\n    SSPACE = %s",
13799 						  aggtransspace);
13800 	}
13801 
13802 	if (!PQgetisnull(res, 0, i_agginitval))
13803 	{
13804 		appendPQExpBufferStr(details, ",\n    INITCOND = ");
13805 		appendStringLiteralAH(details, agginitval, fout);
13806 	}
13807 
13808 	if (strcmp(aggfinalfn, "-") != 0)
13809 	{
13810 		appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
13811 						  aggfinalfn);
13812 		if (aggfinalextra)
13813 			appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
13814 	}
13815 
13816 	if (strcmp(aggcombinefn, "-") != 0)
13817 		appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
13818 
13819 	if (strcmp(aggserialfn, "-") != 0)
13820 		appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
13821 
13822 	if (strcmp(aggdeserialfn, "-") != 0)
13823 		appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
13824 
13825 	if (strcmp(aggmtransfn, "-") != 0)
13826 	{
13827 		appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
13828 						  aggmtransfn,
13829 						  aggminvtransfn,
13830 						  aggmtranstype);
13831 	}
13832 
13833 	if (strcmp(aggmtransspace, "0") != 0)
13834 	{
13835 		appendPQExpBuffer(details, ",\n    MSSPACE = %s",
13836 						  aggmtransspace);
13837 	}
13838 
13839 	if (!PQgetisnull(res, 0, i_aggminitval))
13840 	{
13841 		appendPQExpBufferStr(details, ",\n    MINITCOND = ");
13842 		appendStringLiteralAH(details, aggminitval, fout);
13843 	}
13844 
13845 	if (strcmp(aggmfinalfn, "-") != 0)
13846 	{
13847 		appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
13848 						  aggmfinalfn);
13849 		if (aggmfinalextra)
13850 			appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
13851 	}
13852 
13853 	aggsortconvop = getFormattedOperatorName(fout, aggsortop);
13854 	if (aggsortconvop)
13855 	{
13856 		appendPQExpBuffer(details, ",\n    SORTOP = %s",
13857 						  aggsortconvop);
13858 		free(aggsortconvop);
13859 	}
13860 
13861 	if (hypothetical)
13862 		appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
13863 
13864 	if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
13865 	{
13866 		if (proparallel[0] == PROPARALLEL_SAFE)
13867 			appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
13868 		else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13869 			appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
13870 		else if (proparallel[0] != PROPARALLEL_UNSAFE)
13871 			exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
13872 						  agginfo->aggfn.dobj.name);
13873 	}
13874 
13875 	appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
13876 					  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13877 					  aggsig);
13878 
13879 	appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
13880 					  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13881 					  aggfullsig ? aggfullsig : aggsig, details->data);
13882 
13883 	if (dopt->binary_upgrade)
13884 		binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
13885 										"AGGREGATE", aggsig,
13886 								   agginfo->aggfn.dobj.namespace->dobj.name);
13887 
13888 	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
13889 		ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
13890 					 agginfo->aggfn.dobj.dumpId,
13891 					 aggsig_tag,
13892 					 agginfo->aggfn.dobj.namespace->dobj.name,
13893 					 NULL,
13894 					 agginfo->aggfn.rolname,
13895 					 false, "AGGREGATE", SECTION_PRE_DATA,
13896 					 q->data, delq->data, NULL,
13897 					 NULL, 0,
13898 					 NULL, NULL);
13899 
13900 	/* Dump Aggregate Comments */
13901 	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
13902 		dumpComment(fout, "AGGREGATE", aggsig,
13903 					agginfo->aggfn.dobj.namespace->dobj.name,
13904 					agginfo->aggfn.rolname,
13905 					agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13906 
13907 	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
13908 		dumpSecLabel(fout, "AGGREGATE", aggsig,
13909 					 agginfo->aggfn.dobj.namespace->dobj.name,
13910 					 agginfo->aggfn.rolname,
13911 				   agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13912 
13913 	/*
13914 	 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
13915 	 * command look like a function's GRANT; in particular this affects the
13916 	 * syntax for zero-argument aggregates and ordered-set aggregates.
13917 	 */
13918 	free(aggsig);
13919 
13920 	aggsig = format_function_signature(fout, &agginfo->aggfn, true);
13921 
13922 	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
13923 		dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
13924 				"FUNCTION", aggsig, NULL,
13925 				agginfo->aggfn.dobj.namespace->dobj.name,
13926 				agginfo->aggfn.rolname, agginfo->aggfn.proacl,
13927 				agginfo->aggfn.rproacl,
13928 				agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
13929 
13930 	free(aggsig);
13931 	if (aggfullsig)
13932 		free(aggfullsig);
13933 	free(aggsig_tag);
13934 
13935 	PQclear(res);
13936 
13937 	destroyPQExpBuffer(query);
13938 	destroyPQExpBuffer(q);
13939 	destroyPQExpBuffer(delq);
13940 	destroyPQExpBuffer(details);
13941 }
13942 
13943 /*
13944  * dumpTSParser
13945  *	  write out a single text search parser
13946  */
13947 static void
dumpTSParser(Archive * fout,TSParserInfo * prsinfo)13948 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
13949 {
13950 	DumpOptions *dopt = fout->dopt;
13951 	PQExpBuffer q;
13952 	PQExpBuffer delq;
13953 	char	   *qprsname;
13954 
13955 	/* Skip if not to be dumped */
13956 	if (!prsinfo->dobj.dump || dopt->dataOnly)
13957 		return;
13958 
13959 	q = createPQExpBuffer();
13960 	delq = createPQExpBuffer();
13961 
13962 	qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
13963 
13964 	appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
13965 					  fmtQualifiedDumpable(prsinfo));
13966 
13967 	appendPQExpBuffer(q, "    START = %s,\n",
13968 					  convertTSFunction(fout, prsinfo->prsstart));
13969 	appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
13970 					  convertTSFunction(fout, prsinfo->prstoken));
13971 	appendPQExpBuffer(q, "    END = %s,\n",
13972 					  convertTSFunction(fout, prsinfo->prsend));
13973 	if (prsinfo->prsheadline != InvalidOid)
13974 		appendPQExpBuffer(q, "    HEADLINE = %s,\n",
13975 						  convertTSFunction(fout, prsinfo->prsheadline));
13976 	appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
13977 					  convertTSFunction(fout, prsinfo->prslextype));
13978 
13979 	appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
13980 					  fmtQualifiedDumpable(prsinfo));
13981 
13982 	if (dopt->binary_upgrade)
13983 		binary_upgrade_extension_member(q, &prsinfo->dobj,
13984 										"TEXT SEARCH PARSER", qprsname,
13985 										prsinfo->dobj.namespace->dobj.name);
13986 
13987 	if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13988 		ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
13989 					 prsinfo->dobj.name,
13990 					 prsinfo->dobj.namespace->dobj.name,
13991 					 NULL,
13992 					 "",
13993 					 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
13994 					 q->data, delq->data, NULL,
13995 					 NULL, 0,
13996 					 NULL, NULL);
13997 
13998 	/* Dump Parser Comments */
13999 	if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14000 		dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14001 					prsinfo->dobj.namespace->dobj.name, "",
14002 					prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14003 
14004 	destroyPQExpBuffer(q);
14005 	destroyPQExpBuffer(delq);
14006 	free(qprsname);
14007 }
14008 
14009 /*
14010  * dumpTSDictionary
14011  *	  write out a single text search dictionary
14012  */
14013 static void
dumpTSDictionary(Archive * fout,TSDictInfo * dictinfo)14014 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14015 {
14016 	DumpOptions *dopt = fout->dopt;
14017 	PQExpBuffer q;
14018 	PQExpBuffer delq;
14019 	PQExpBuffer query;
14020 	char	   *qdictname;
14021 	PGresult   *res;
14022 	char	   *nspname;
14023 	char	   *tmplname;
14024 
14025 	/* Skip if not to be dumped */
14026 	if (!dictinfo->dobj.dump || dopt->dataOnly)
14027 		return;
14028 
14029 	q = createPQExpBuffer();
14030 	delq = createPQExpBuffer();
14031 	query = createPQExpBuffer();
14032 
14033 	qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14034 
14035 	/* Fetch name and namespace of the dictionary's template */
14036 	appendPQExpBuffer(query, "SELECT nspname, tmplname "
14037 					  "FROM pg_ts_template p, pg_namespace n "
14038 					  "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14039 					  dictinfo->dicttemplate);
14040 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
14041 	nspname = PQgetvalue(res, 0, 0);
14042 	tmplname = PQgetvalue(res, 0, 1);
14043 
14044 	appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14045 					  fmtQualifiedDumpable(dictinfo));
14046 
14047 	appendPQExpBufferStr(q, "    TEMPLATE = ");
14048 	appendPQExpBuffer(q, "%s.", fmtId(nspname));
14049 	appendPQExpBufferStr(q, fmtId(tmplname));
14050 
14051 	PQclear(res);
14052 
14053 	/* the dictinitoption can be dumped straight into the command */
14054 	if (dictinfo->dictinitoption)
14055 		appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14056 
14057 	appendPQExpBufferStr(q, " );\n");
14058 
14059 	appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14060 					  fmtQualifiedDumpable(dictinfo));
14061 
14062 	if (dopt->binary_upgrade)
14063 		binary_upgrade_extension_member(q, &dictinfo->dobj,
14064 										"TEXT SEARCH DICTIONARY", qdictname,
14065 										dictinfo->dobj.namespace->dobj.name);
14066 
14067 	if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14068 		ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14069 					 dictinfo->dobj.name,
14070 					 dictinfo->dobj.namespace->dobj.name,
14071 					 NULL,
14072 					 dictinfo->rolname,
14073 					 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
14074 					 q->data, delq->data, NULL,
14075 					 NULL, 0,
14076 					 NULL, NULL);
14077 
14078 	/* Dump Dictionary Comments */
14079 	if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14080 		dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14081 					dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14082 					dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14083 
14084 	destroyPQExpBuffer(q);
14085 	destroyPQExpBuffer(delq);
14086 	destroyPQExpBuffer(query);
14087 	free(qdictname);
14088 }
14089 
14090 /*
14091  * dumpTSTemplate
14092  *	  write out a single text search template
14093  */
14094 static void
dumpTSTemplate(Archive * fout,TSTemplateInfo * tmplinfo)14095 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14096 {
14097 	DumpOptions *dopt = fout->dopt;
14098 	PQExpBuffer q;
14099 	PQExpBuffer delq;
14100 	char	   *qtmplname;
14101 
14102 	/* Skip if not to be dumped */
14103 	if (!tmplinfo->dobj.dump || dopt->dataOnly)
14104 		return;
14105 
14106 	q = createPQExpBuffer();
14107 	delq = createPQExpBuffer();
14108 
14109 	qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14110 
14111 	appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14112 					  fmtQualifiedDumpable(tmplinfo));
14113 
14114 	if (tmplinfo->tmplinit != InvalidOid)
14115 		appendPQExpBuffer(q, "    INIT = %s,\n",
14116 						  convertTSFunction(fout, tmplinfo->tmplinit));
14117 	appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14118 					  convertTSFunction(fout, tmplinfo->tmpllexize));
14119 
14120 	appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14121 					  fmtQualifiedDumpable(tmplinfo));
14122 
14123 	if (dopt->binary_upgrade)
14124 		binary_upgrade_extension_member(q, &tmplinfo->dobj,
14125 										"TEXT SEARCH TEMPLATE", qtmplname,
14126 										tmplinfo->dobj.namespace->dobj.name);
14127 
14128 	if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14129 		ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14130 					 tmplinfo->dobj.name,
14131 					 tmplinfo->dobj.namespace->dobj.name,
14132 					 NULL,
14133 					 "",
14134 					 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
14135 					 q->data, delq->data, NULL,
14136 					 NULL, 0,
14137 					 NULL, NULL);
14138 
14139 	/* Dump Template Comments */
14140 	if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14141 		dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14142 					tmplinfo->dobj.namespace->dobj.name, "",
14143 					tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14144 
14145 	destroyPQExpBuffer(q);
14146 	destroyPQExpBuffer(delq);
14147 	free(qtmplname);
14148 }
14149 
14150 /*
14151  * dumpTSConfig
14152  *	  write out a single text search configuration
14153  */
14154 static void
dumpTSConfig(Archive * fout,TSConfigInfo * cfginfo)14155 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14156 {
14157 	DumpOptions *dopt = fout->dopt;
14158 	PQExpBuffer q;
14159 	PQExpBuffer delq;
14160 	PQExpBuffer query;
14161 	char	   *qcfgname;
14162 	PGresult   *res;
14163 	char	   *nspname;
14164 	char	   *prsname;
14165 	int			ntups,
14166 				i;
14167 	int			i_tokenname;
14168 	int			i_dictname;
14169 
14170 	/* Skip if not to be dumped */
14171 	if (!cfginfo->dobj.dump || dopt->dataOnly)
14172 		return;
14173 
14174 	q = createPQExpBuffer();
14175 	delq = createPQExpBuffer();
14176 	query = createPQExpBuffer();
14177 
14178 	qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14179 
14180 	/* Fetch name and namespace of the config's parser */
14181 	appendPQExpBuffer(query, "SELECT nspname, prsname "
14182 					  "FROM pg_ts_parser p, pg_namespace n "
14183 					  "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14184 					  cfginfo->cfgparser);
14185 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
14186 	nspname = PQgetvalue(res, 0, 0);
14187 	prsname = PQgetvalue(res, 0, 1);
14188 
14189 	appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14190 					  fmtQualifiedDumpable(cfginfo));
14191 
14192 	appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14193 	appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14194 
14195 	PQclear(res);
14196 
14197 	resetPQExpBuffer(query);
14198 	appendPQExpBuffer(query,
14199 					  "SELECT \n"
14200 					  "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
14201 					  "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
14202 					  "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
14203 					  "FROM pg_catalog.pg_ts_config_map AS m \n"
14204 					  "WHERE m.mapcfg = '%u' \n"
14205 					  "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14206 					  cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14207 
14208 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14209 	ntups = PQntuples(res);
14210 
14211 	i_tokenname = PQfnumber(res, "tokenname");
14212 	i_dictname = PQfnumber(res, "dictname");
14213 
14214 	for (i = 0; i < ntups; i++)
14215 	{
14216 		char	   *tokenname = PQgetvalue(res, i, i_tokenname);
14217 		char	   *dictname = PQgetvalue(res, i, i_dictname);
14218 
14219 		if (i == 0 ||
14220 			strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14221 		{
14222 			/* starting a new token type, so start a new command */
14223 			if (i > 0)
14224 				appendPQExpBufferStr(q, ";\n");
14225 			appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14226 							  fmtQualifiedDumpable(cfginfo));
14227 			/* tokenname needs quoting, dictname does NOT */
14228 			appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14229 							  fmtId(tokenname), dictname);
14230 		}
14231 		else
14232 			appendPQExpBuffer(q, ", %s", dictname);
14233 	}
14234 
14235 	if (ntups > 0)
14236 		appendPQExpBufferStr(q, ";\n");
14237 
14238 	PQclear(res);
14239 
14240 	appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14241 					  fmtQualifiedDumpable(cfginfo));
14242 
14243 	if (dopt->binary_upgrade)
14244 		binary_upgrade_extension_member(q, &cfginfo->dobj,
14245 										"TEXT SEARCH CONFIGURATION", qcfgname,
14246 										cfginfo->dobj.namespace->dobj.name);
14247 
14248 	if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14249 		ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14250 					 cfginfo->dobj.name,
14251 					 cfginfo->dobj.namespace->dobj.name,
14252 					 NULL,
14253 					 cfginfo->rolname,
14254 					 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
14255 					 q->data, delq->data, NULL,
14256 					 NULL, 0,
14257 					 NULL, NULL);
14258 
14259 	/* Dump Configuration Comments */
14260 	if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14261 		dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14262 					cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14263 					cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14264 
14265 	destroyPQExpBuffer(q);
14266 	destroyPQExpBuffer(delq);
14267 	destroyPQExpBuffer(query);
14268 	free(qcfgname);
14269 }
14270 
14271 /*
14272  * dumpForeignDataWrapper
14273  *	  write out a single foreign-data wrapper definition
14274  */
14275 static void
dumpForeignDataWrapper(Archive * fout,FdwInfo * fdwinfo)14276 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14277 {
14278 	DumpOptions *dopt = fout->dopt;
14279 	PQExpBuffer q;
14280 	PQExpBuffer delq;
14281 	char	   *qfdwname;
14282 
14283 	/* Skip if not to be dumped */
14284 	if (!fdwinfo->dobj.dump || dopt->dataOnly)
14285 		return;
14286 
14287 	q = createPQExpBuffer();
14288 	delq = createPQExpBuffer();
14289 
14290 	qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14291 
14292 	appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14293 					  qfdwname);
14294 
14295 	if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14296 		appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14297 
14298 	if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14299 		appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14300 
14301 	if (strlen(fdwinfo->fdwoptions) > 0)
14302 		appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14303 
14304 	appendPQExpBufferStr(q, ";\n");
14305 
14306 	appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14307 					  qfdwname);
14308 
14309 	if (dopt->binary_upgrade)
14310 		binary_upgrade_extension_member(q, &fdwinfo->dobj,
14311 										"FOREIGN DATA WRAPPER", qfdwname,
14312 										NULL);
14313 
14314 	if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14315 		ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14316 					 fdwinfo->dobj.name,
14317 					 NULL,
14318 					 NULL,
14319 					 fdwinfo->rolname,
14320 					 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
14321 					 q->data, delq->data, NULL,
14322 					 NULL, 0,
14323 					 NULL, NULL);
14324 
14325 	/* Handle the ACL */
14326 	if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14327 		dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
14328 				"FOREIGN DATA WRAPPER", qfdwname, NULL,
14329 				NULL, fdwinfo->rolname,
14330 				fdwinfo->fdwacl, fdwinfo->rfdwacl,
14331 				fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14332 
14333 	/* Dump Foreign Data Wrapper Comments */
14334 	if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14335 		dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14336 					NULL, fdwinfo->rolname,
14337 					fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14338 
14339 	free(qfdwname);
14340 
14341 	destroyPQExpBuffer(q);
14342 	destroyPQExpBuffer(delq);
14343 }
14344 
14345 /*
14346  * dumpForeignServer
14347  *	  write out a foreign server definition
14348  */
14349 static void
dumpForeignServer(Archive * fout,ForeignServerInfo * srvinfo)14350 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14351 {
14352 	DumpOptions *dopt = fout->dopt;
14353 	PQExpBuffer q;
14354 	PQExpBuffer delq;
14355 	PQExpBuffer query;
14356 	PGresult   *res;
14357 	char	   *qsrvname;
14358 	char	   *fdwname;
14359 
14360 	/* Skip if not to be dumped */
14361 	if (!srvinfo->dobj.dump || dopt->dataOnly)
14362 		return;
14363 
14364 	q = createPQExpBuffer();
14365 	delq = createPQExpBuffer();
14366 	query = createPQExpBuffer();
14367 
14368 	qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14369 
14370 	/* look up the foreign-data wrapper */
14371 	appendPQExpBuffer(query, "SELECT fdwname "
14372 					  "FROM pg_foreign_data_wrapper w "
14373 					  "WHERE w.oid = '%u'",
14374 					  srvinfo->srvfdw);
14375 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
14376 	fdwname = PQgetvalue(res, 0, 0);
14377 
14378 	appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14379 	if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14380 	{
14381 		appendPQExpBufferStr(q, " TYPE ");
14382 		appendStringLiteralAH(q, srvinfo->srvtype, fout);
14383 	}
14384 	if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14385 	{
14386 		appendPQExpBufferStr(q, " VERSION ");
14387 		appendStringLiteralAH(q, srvinfo->srvversion, fout);
14388 	}
14389 
14390 	appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14391 	appendPQExpBufferStr(q, fmtId(fdwname));
14392 
14393 	if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14394 		appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14395 
14396 	appendPQExpBufferStr(q, ";\n");
14397 
14398 	appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14399 					  qsrvname);
14400 
14401 	if (dopt->binary_upgrade)
14402 		binary_upgrade_extension_member(q, &srvinfo->dobj,
14403 										"SERVER", qsrvname, NULL);
14404 
14405 	if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14406 		ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14407 					 srvinfo->dobj.name,
14408 					 NULL,
14409 					 NULL,
14410 					 srvinfo->rolname,
14411 					 false, "SERVER", SECTION_PRE_DATA,
14412 					 q->data, delq->data, NULL,
14413 					 NULL, 0,
14414 					 NULL, NULL);
14415 
14416 	/* Handle the ACL */
14417 	if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14418 		dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
14419 				"FOREIGN SERVER", qsrvname, NULL,
14420 				NULL, srvinfo->rolname,
14421 				srvinfo->srvacl, srvinfo->rsrvacl,
14422 				srvinfo->initsrvacl, srvinfo->initrsrvacl);
14423 
14424 	/* Dump user mappings */
14425 	if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14426 		dumpUserMappings(fout,
14427 						 srvinfo->dobj.name, NULL,
14428 						 srvinfo->rolname,
14429 						 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14430 
14431 	/* Dump Foreign Server Comments */
14432 	if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14433 		dumpComment(fout, "SERVER", qsrvname,
14434 					NULL, srvinfo->rolname,
14435 					srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14436 
14437 	free(qsrvname);
14438 
14439 	destroyPQExpBuffer(q);
14440 	destroyPQExpBuffer(delq);
14441 	destroyPQExpBuffer(query);
14442 }
14443 
14444 /*
14445  * dumpUserMappings
14446  *
14447  * This routine is used to dump any user mappings associated with the
14448  * server handed to this routine. Should be called after ArchiveEntry()
14449  * for the server.
14450  */
14451 static void
dumpUserMappings(Archive * fout,const char * servername,const char * namespace,const char * owner,CatalogId catalogId,DumpId dumpId)14452 dumpUserMappings(Archive *fout,
14453 				 const char *servername, const char *namespace,
14454 				 const char *owner,
14455 				 CatalogId catalogId, DumpId dumpId)
14456 {
14457 	PQExpBuffer q;
14458 	PQExpBuffer delq;
14459 	PQExpBuffer query;
14460 	PQExpBuffer tag;
14461 	PGresult   *res;
14462 	int			ntups;
14463 	int			i_usename;
14464 	int			i_umoptions;
14465 	int			i;
14466 
14467 	q = createPQExpBuffer();
14468 	tag = createPQExpBuffer();
14469 	delq = createPQExpBuffer();
14470 	query = createPQExpBuffer();
14471 
14472 	/*
14473 	 * We read from the publicly accessible view pg_user_mappings, so as not
14474 	 * to fail if run by a non-superuser.  Note that the view will show
14475 	 * umoptions as null if the user hasn't got privileges for the associated
14476 	 * server; this means that pg_dump will dump such a mapping, but with no
14477 	 * OPTIONS clause.  A possible alternative is to skip such mappings
14478 	 * altogether, but it's not clear that that's an improvement.
14479 	 */
14480 	appendPQExpBuffer(query,
14481 					  "SELECT usename, "
14482 					  "array_to_string(ARRAY("
14483 					  "SELECT quote_ident(option_name) || ' ' || "
14484 					  "quote_literal(option_value) "
14485 					  "FROM pg_options_to_table(umoptions) "
14486 					  "ORDER BY option_name"
14487 					  "), E',\n    ') AS umoptions "
14488 					  "FROM pg_user_mappings "
14489 					  "WHERE srvid = '%u' "
14490 					  "ORDER BY usename",
14491 					  catalogId.oid);
14492 
14493 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14494 
14495 	ntups = PQntuples(res);
14496 	i_usename = PQfnumber(res, "usename");
14497 	i_umoptions = PQfnumber(res, "umoptions");
14498 
14499 	for (i = 0; i < ntups; i++)
14500 	{
14501 		char	   *usename;
14502 		char	   *umoptions;
14503 
14504 		usename = PQgetvalue(res, i, i_usename);
14505 		umoptions = PQgetvalue(res, i, i_umoptions);
14506 
14507 		resetPQExpBuffer(q);
14508 		appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14509 		appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14510 
14511 		if (umoptions && strlen(umoptions) > 0)
14512 			appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14513 
14514 		appendPQExpBufferStr(q, ";\n");
14515 
14516 		resetPQExpBuffer(delq);
14517 		appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14518 		appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14519 
14520 		resetPQExpBuffer(tag);
14521 		appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14522 						  usename, servername);
14523 
14524 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
14525 					 tag->data,
14526 					 namespace,
14527 					 NULL,
14528 					 owner, false,
14529 					 "USER MAPPING", SECTION_PRE_DATA,
14530 					 q->data, delq->data, NULL,
14531 					 &dumpId, 1,
14532 					 NULL, NULL);
14533 	}
14534 
14535 	PQclear(res);
14536 
14537 	destroyPQExpBuffer(query);
14538 	destroyPQExpBuffer(delq);
14539 	destroyPQExpBuffer(tag);
14540 	destroyPQExpBuffer(q);
14541 }
14542 
14543 /*
14544  * Write out default privileges information
14545  */
14546 static void
dumpDefaultACL(Archive * fout,DefaultACLInfo * daclinfo)14547 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14548 {
14549 	DumpOptions *dopt = fout->dopt;
14550 	PQExpBuffer q;
14551 	PQExpBuffer tag;
14552 	const char *type;
14553 
14554 	/* Skip if not to be dumped */
14555 	if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14556 		return;
14557 
14558 	q = createPQExpBuffer();
14559 	tag = createPQExpBuffer();
14560 
14561 	switch (daclinfo->defaclobjtype)
14562 	{
14563 		case DEFACLOBJ_RELATION:
14564 			type = "TABLES";
14565 			break;
14566 		case DEFACLOBJ_SEQUENCE:
14567 			type = "SEQUENCES";
14568 			break;
14569 		case DEFACLOBJ_FUNCTION:
14570 			type = "FUNCTIONS";
14571 			break;
14572 		case DEFACLOBJ_TYPE:
14573 			type = "TYPES";
14574 			break;
14575 		default:
14576 			/* shouldn't get here */
14577 			exit_horribly(NULL,
14578 					  "unrecognized object type in default privileges: %d\n",
14579 						  (int) daclinfo->defaclobjtype);
14580 			type = "";			/* keep compiler quiet */
14581 	}
14582 
14583 	appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14584 
14585 	/* build the actual command(s) for this tuple */
14586 	if (!buildDefaultACLCommands(type,
14587 								 daclinfo->dobj.namespace != NULL ?
14588 								 daclinfo->dobj.namespace->dobj.name : NULL,
14589 								 daclinfo->defaclacl,
14590 								 daclinfo->rdefaclacl,
14591 								 daclinfo->initdefaclacl,
14592 								 daclinfo->initrdefaclacl,
14593 								 daclinfo->defaclrole,
14594 								 fout->remoteVersion,
14595 								 q))
14596 		exit_horribly(NULL, "could not parse default ACL list (%s)\n",
14597 					  daclinfo->defaclacl);
14598 
14599 	if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14600 		ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14601 					 tag->data,
14602 		daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
14603 					 NULL,
14604 					 daclinfo->defaclrole,
14605 					 false, "DEFAULT ACL", SECTION_POST_DATA,
14606 					 q->data, "", NULL,
14607 					 NULL, 0,
14608 					 NULL, NULL);
14609 
14610 	destroyPQExpBuffer(tag);
14611 	destroyPQExpBuffer(q);
14612 }
14613 
14614 /*----------
14615  * Write out grant/revoke information
14616  *
14617  * 'objDumpId' is the dump ID of the underlying object.
14618  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
14619  *		or InvalidDumpId if there is no need for a second dependency.
14620  * 'type' must be one of
14621  *		TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14622  *		FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14623  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14624  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14625  *		(Currently we assume that subname is only provided for table columns.)
14626  * 'nspname' is the namespace the object is in (NULL if none).
14627  * 'owner' is the owner, NULL if there is no owner (for languages).
14628  * 'acls' contains the ACL string of the object from the appropriate system
14629  *		catalog field; it will be passed to buildACLCommands for building the
14630  *		appropriate GRANT commands.
14631  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14632  *		object; it will be passed to buildACLCommands for building the
14633  *		appropriate REVOKE commands.
14634  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14635  *		privileges, to be recorded into pg_init_privs
14636  * 'initracls' In binary-upgrade mode, ACL string of the object's
14637  *		revoked-from-default privileges, to be recorded into pg_init_privs
14638  *
14639  * NB: initacls/initracls are needed because extensions can set privileges on
14640  * an object during the extension's script file and we record those into
14641  * pg_init_privs as that object's initial privileges.
14642  *
14643  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
14644  * no ACL entry was created.
14645  *----------
14646  */
14647 static DumpId
dumpACL(Archive * fout,DumpId objDumpId,DumpId altDumpId,const char * type,const char * name,const char * subname,const char * nspname,const char * owner,const char * acls,const char * racls,const char * initacls,const char * initracls)14648 dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
14649 		const char *type, const char *name, const char *subname,
14650 		const char *nspname, const char *owner,
14651 		const char *acls, const char *racls,
14652 		const char *initacls, const char *initracls)
14653 {
14654 	DumpId		aclDumpId = InvalidDumpId;
14655 	DumpOptions *dopt = fout->dopt;
14656 	PQExpBuffer sql;
14657 
14658 	/* Do nothing if ACL dump is not enabled */
14659 	if (dopt->aclsSkip)
14660 		return InvalidDumpId;
14661 
14662 	/* --data-only skips ACLs *except* BLOB ACLs */
14663 	if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14664 		return InvalidDumpId;
14665 
14666 	sql = createPQExpBuffer();
14667 
14668 	/*
14669 	 * Check to see if this object has had any initial ACLs included for it.
14670 	 * If so, we are in binary upgrade mode and these are the ACLs to turn
14671 	 * into GRANT and REVOKE statements to set and record the initial
14672 	 * privileges for an extension object.  Let the backend know that these
14673 	 * are to be recorded by calling binary_upgrade_set_record_init_privs()
14674 	 * before and after.
14675 	 */
14676 	if (strlen(initacls) != 0 || strlen(initracls) != 0)
14677 	{
14678 		appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14679 		if (!buildACLCommands(name, subname, nspname, type,
14680 							  initacls, initracls, owner,
14681 							  "", fout->remoteVersion, sql))
14682 			exit_horribly(NULL,
14683 						  "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14684 						  initacls, initracls, name, type);
14685 		appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14686 	}
14687 
14688 	if (!buildACLCommands(name, subname, nspname, type,
14689 						  acls, racls, owner,
14690 						  "", fout->remoteVersion, sql))
14691 		exit_horribly(NULL,
14692 					  "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14693 					  acls, racls, name, type);
14694 
14695 	if (sql->len > 0)
14696 	{
14697 		PQExpBuffer tag = createPQExpBuffer();
14698 		DumpId		aclDeps[2];
14699 		int			nDeps = 0;
14700 
14701 		if (subname)
14702 			appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14703 		else
14704 			appendPQExpBuffer(tag, "%s %s", type, name);
14705 
14706 		aclDeps[nDeps++] = objDumpId;
14707 		if (altDumpId != InvalidDumpId)
14708 			aclDeps[nDeps++] = altDumpId;
14709 
14710 		aclDumpId = createDumpId();
14711 
14712 		ArchiveEntry(fout, nilCatalogId, aclDumpId,
14713 					 tag->data, nspname,
14714 					 NULL,
14715 					 owner ? owner : "",
14716 					 false, "ACL", SECTION_NONE,
14717 					 sql->data, "", NULL,
14718 					 aclDeps, nDeps,
14719 					 NULL, NULL);
14720 
14721 		destroyPQExpBuffer(tag);
14722 	}
14723 
14724 	destroyPQExpBuffer(sql);
14725 
14726 	return aclDumpId;
14727 }
14728 
14729 /*
14730  * dumpSecLabel
14731  *
14732  * This routine is used to dump any security labels associated with the
14733  * object handed to this routine. The routine takes the object type
14734  * and object name (ready to print, except for schema decoration), plus
14735  * the namespace and owner of the object (for labeling the ArchiveEntry),
14736  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14737  * plus the dump ID for the object (for setting a dependency).
14738  * If a matching pg_seclabel entry is found, it is dumped.
14739  *
14740  * Note: although this routine takes a dumpId for dependency purposes,
14741  * that purpose is just to mark the dependency in the emitted dump file
14742  * for possible future use by pg_restore.  We do NOT use it for determining
14743  * ordering of the label in the dump file, because this routine is called
14744  * after dependency sorting occurs.  This routine should be called just after
14745  * calling ArchiveEntry() for the specified object.
14746  */
14747 static void
dumpSecLabel(Archive * fout,const char * type,const char * name,const char * namespace,const char * owner,CatalogId catalogId,int subid,DumpId dumpId)14748 dumpSecLabel(Archive *fout, const char *type, const char *name,
14749 			 const char *namespace, const char *owner,
14750 			 CatalogId catalogId, int subid, DumpId dumpId)
14751 {
14752 	DumpOptions *dopt = fout->dopt;
14753 	SecLabelItem *labels;
14754 	int			nlabels;
14755 	int			i;
14756 	PQExpBuffer query;
14757 
14758 	/* do nothing, if --no-security-labels is supplied */
14759 	if (dopt->no_security_labels)
14760 		return;
14761 
14762 	/* Security labels are schema not data ... except blob labels are data */
14763 	if (strcmp(type, "LARGE OBJECT") != 0)
14764 	{
14765 		if (dopt->dataOnly)
14766 			return;
14767 	}
14768 	else
14769 	{
14770 		/* We do dump blob security labels in binary-upgrade mode */
14771 		if (dopt->schemaOnly && !dopt->binary_upgrade)
14772 			return;
14773 	}
14774 
14775 	/* Search for security labels associated with catalogId, using table */
14776 	nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14777 
14778 	query = createPQExpBuffer();
14779 
14780 	for (i = 0; i < nlabels; i++)
14781 	{
14782 		/*
14783 		 * Ignore label entries for which the subid doesn't match.
14784 		 */
14785 		if (labels[i].objsubid != subid)
14786 			continue;
14787 
14788 		appendPQExpBuffer(query,
14789 						  "SECURITY LABEL FOR %s ON %s ",
14790 						  fmtId(labels[i].provider), type);
14791 		if (namespace && *namespace)
14792 			appendPQExpBuffer(query, "%s.", fmtId(namespace));
14793 		appendPQExpBuffer(query, "%s IS ", name);
14794 		appendStringLiteralAH(query, labels[i].label, fout);
14795 		appendPQExpBufferStr(query, ";\n");
14796 	}
14797 
14798 	if (query->len > 0)
14799 	{
14800 		PQExpBuffer tag = createPQExpBuffer();
14801 
14802 		appendPQExpBuffer(tag, "%s %s", type, name);
14803 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
14804 					 tag->data, namespace, NULL, owner,
14805 					 false, "SECURITY LABEL", SECTION_NONE,
14806 					 query->data, "", NULL,
14807 					 &(dumpId), 1,
14808 					 NULL, NULL);
14809 		destroyPQExpBuffer(tag);
14810 	}
14811 
14812 	destroyPQExpBuffer(query);
14813 }
14814 
14815 /*
14816  * dumpTableSecLabel
14817  *
14818  * As above, but dump security label for both the specified table (or view)
14819  * and its columns.
14820  */
14821 static void
dumpTableSecLabel(Archive * fout,TableInfo * tbinfo,const char * reltypename)14822 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
14823 {
14824 	DumpOptions *dopt = fout->dopt;
14825 	SecLabelItem *labels;
14826 	int			nlabels;
14827 	int			i;
14828 	PQExpBuffer query;
14829 	PQExpBuffer target;
14830 
14831 	/* do nothing, if --no-security-labels is supplied */
14832 	if (dopt->no_security_labels)
14833 		return;
14834 
14835 	/* SecLabel are SCHEMA not data */
14836 	if (dopt->dataOnly)
14837 		return;
14838 
14839 	/* Search for comments associated with relation, using table */
14840 	nlabels = findSecLabels(fout,
14841 							tbinfo->dobj.catId.tableoid,
14842 							tbinfo->dobj.catId.oid,
14843 							&labels);
14844 
14845 	/* If security labels exist, build SECURITY LABEL statements */
14846 	if (nlabels <= 0)
14847 		return;
14848 
14849 	query = createPQExpBuffer();
14850 	target = createPQExpBuffer();
14851 
14852 	for (i = 0; i < nlabels; i++)
14853 	{
14854 		const char *colname;
14855 		const char *provider = labels[i].provider;
14856 		const char *label = labels[i].label;
14857 		int			objsubid = labels[i].objsubid;
14858 
14859 		resetPQExpBuffer(target);
14860 		if (objsubid == 0)
14861 		{
14862 			appendPQExpBuffer(target, "%s %s", reltypename,
14863 							  fmtQualifiedDumpable(tbinfo));
14864 		}
14865 		else
14866 		{
14867 			colname = getAttrName(objsubid, tbinfo);
14868 			/* first fmtXXX result must be consumed before calling again */
14869 			appendPQExpBuffer(target, "COLUMN %s",
14870 							  fmtQualifiedDumpable(tbinfo));
14871 			appendPQExpBuffer(target, ".%s", fmtId(colname));
14872 		}
14873 		appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
14874 						  fmtId(provider), target->data);
14875 		appendStringLiteralAH(query, label, fout);
14876 		appendPQExpBufferStr(query, ";\n");
14877 	}
14878 	if (query->len > 0)
14879 	{
14880 		resetPQExpBuffer(target);
14881 		appendPQExpBuffer(target, "%s %s", reltypename,
14882 						  fmtId(tbinfo->dobj.name));
14883 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
14884 					 target->data,
14885 					 tbinfo->dobj.namespace->dobj.name,
14886 					 NULL, tbinfo->rolname,
14887 					 false, "SECURITY LABEL", SECTION_NONE,
14888 					 query->data, "", NULL,
14889 					 &(tbinfo->dobj.dumpId), 1,
14890 					 NULL, NULL);
14891 	}
14892 	destroyPQExpBuffer(query);
14893 	destroyPQExpBuffer(target);
14894 }
14895 
14896 /*
14897  * findSecLabels
14898  *
14899  * Find the security label(s), if any, associated with the given object.
14900  * All the objsubid values associated with the given classoid/objoid are
14901  * found with one search.
14902  */
14903 static int
findSecLabels(Archive * fout,Oid classoid,Oid objoid,SecLabelItem ** items)14904 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
14905 {
14906 	/* static storage for table of security labels */
14907 	static SecLabelItem *labels = NULL;
14908 	static int	nlabels = -1;
14909 
14910 	SecLabelItem *middle = NULL;
14911 	SecLabelItem *low;
14912 	SecLabelItem *high;
14913 	int			nmatch;
14914 
14915 	/* Get security labels if we didn't already */
14916 	if (nlabels < 0)
14917 		nlabels = collectSecLabels(fout, &labels);
14918 
14919 	if (nlabels <= 0)			/* no labels, so no match is possible */
14920 	{
14921 		*items = NULL;
14922 		return 0;
14923 	}
14924 
14925 	/*
14926 	 * Do binary search to find some item matching the object.
14927 	 */
14928 	low = &labels[0];
14929 	high = &labels[nlabels - 1];
14930 	while (low <= high)
14931 	{
14932 		middle = low + (high - low) / 2;
14933 
14934 		if (classoid < middle->classoid)
14935 			high = middle - 1;
14936 		else if (classoid > middle->classoid)
14937 			low = middle + 1;
14938 		else if (objoid < middle->objoid)
14939 			high = middle - 1;
14940 		else if (objoid > middle->objoid)
14941 			low = middle + 1;
14942 		else
14943 			break;				/* found a match */
14944 	}
14945 
14946 	if (low > high)				/* no matches */
14947 	{
14948 		*items = NULL;
14949 		return 0;
14950 	}
14951 
14952 	/*
14953 	 * Now determine how many items match the object.  The search loop
14954 	 * invariant still holds: only items between low and high inclusive could
14955 	 * match.
14956 	 */
14957 	nmatch = 1;
14958 	while (middle > low)
14959 	{
14960 		if (classoid != middle[-1].classoid ||
14961 			objoid != middle[-1].objoid)
14962 			break;
14963 		middle--;
14964 		nmatch++;
14965 	}
14966 
14967 	*items = middle;
14968 
14969 	middle += nmatch;
14970 	while (middle <= high)
14971 	{
14972 		if (classoid != middle->classoid ||
14973 			objoid != middle->objoid)
14974 			break;
14975 		middle++;
14976 		nmatch++;
14977 	}
14978 
14979 	return nmatch;
14980 }
14981 
14982 /*
14983  * collectSecLabels
14984  *
14985  * Construct a table of all security labels available for database objects.
14986  * It's much faster to pull them all at once.
14987  *
14988  * The table is sorted by classoid/objid/objsubid for speed in lookup.
14989  */
14990 static int
collectSecLabels(Archive * fout,SecLabelItem ** items)14991 collectSecLabels(Archive *fout, SecLabelItem **items)
14992 {
14993 	PGresult   *res;
14994 	PQExpBuffer query;
14995 	int			i_label;
14996 	int			i_provider;
14997 	int			i_classoid;
14998 	int			i_objoid;
14999 	int			i_objsubid;
15000 	int			ntups;
15001 	int			i;
15002 	SecLabelItem *labels;
15003 
15004 	query = createPQExpBuffer();
15005 
15006 	appendPQExpBufferStr(query,
15007 						 "SELECT label, provider, classoid, objoid, objsubid "
15008 						 "FROM pg_catalog.pg_seclabel "
15009 						 "ORDER BY classoid, objoid, objsubid");
15010 
15011 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15012 
15013 	/* Construct lookup table containing OIDs in numeric form */
15014 	i_label = PQfnumber(res, "label");
15015 	i_provider = PQfnumber(res, "provider");
15016 	i_classoid = PQfnumber(res, "classoid");
15017 	i_objoid = PQfnumber(res, "objoid");
15018 	i_objsubid = PQfnumber(res, "objsubid");
15019 
15020 	ntups = PQntuples(res);
15021 
15022 	labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15023 
15024 	for (i = 0; i < ntups; i++)
15025 	{
15026 		labels[i].label = PQgetvalue(res, i, i_label);
15027 		labels[i].provider = PQgetvalue(res, i, i_provider);
15028 		labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15029 		labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15030 		labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15031 	}
15032 
15033 	/* Do NOT free the PGresult since we are keeping pointers into it */
15034 	destroyPQExpBuffer(query);
15035 
15036 	*items = labels;
15037 	return ntups;
15038 }
15039 
15040 /*
15041  * dumpTable
15042  *	  write out to fout the declarations (not data) of a user-defined table
15043  */
15044 static void
dumpTable(Archive * fout,TableInfo * tbinfo)15045 dumpTable(Archive *fout, TableInfo *tbinfo)
15046 {
15047 	DumpOptions *dopt = fout->dopt;
15048 	DumpId		tableAclDumpId = InvalidDumpId;
15049 	char	   *namecopy;
15050 
15051 	/*
15052 	 * noop if we are not dumping anything about this table, or if we are
15053 	 * doing a data-only dump
15054 	 */
15055 	if (!tbinfo->dobj.dump || dopt->dataOnly)
15056 		return;
15057 
15058 	if (tbinfo->relkind == RELKIND_SEQUENCE)
15059 		dumpSequence(fout, tbinfo);
15060 	else
15061 		dumpTableSchema(fout, tbinfo);
15062 
15063 	/* Handle the ACL here */
15064 	namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15065 	if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15066 	{
15067 		const char *objtype =
15068 		(tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15069 
15070 		tableAclDumpId =
15071 			dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
15072 					objtype, namecopy, NULL,
15073 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15074 					tbinfo->relacl, tbinfo->rrelacl,
15075 					tbinfo->initrelacl, tbinfo->initrrelacl);
15076 	}
15077 
15078 	/*
15079 	 * Handle column ACLs, if any.  Note: we pull these with a separate query
15080 	 * rather than trying to fetch them during getTableAttrs, so that we won't
15081 	 * miss ACLs on system columns.
15082 	 */
15083 	if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15084 	{
15085 		PQExpBuffer query = createPQExpBuffer();
15086 		PGresult   *res;
15087 		int			i;
15088 
15089 		if (fout->remoteVersion >= 90600)
15090 		{
15091 			PQExpBuffer acl_subquery = createPQExpBuffer();
15092 			PQExpBuffer racl_subquery = createPQExpBuffer();
15093 			PQExpBuffer initacl_subquery = createPQExpBuffer();
15094 			PQExpBuffer initracl_subquery = createPQExpBuffer();
15095 
15096 			buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15097 						 initracl_subquery, "at.attacl", "c.relowner", "'c'",
15098 							dopt->binary_upgrade);
15099 
15100 			appendPQExpBuffer(query,
15101 							  "SELECT at.attname, "
15102 							  "%s AS attacl, "
15103 							  "%s AS rattacl, "
15104 							  "%s AS initattacl, "
15105 							  "%s AS initrattacl "
15106 							  "FROM pg_catalog.pg_attribute at "
15107 					   "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15108 							  "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15109 							  "(at.attrelid = pip.objoid "
15110 			 "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15111 							  "AND at.attnum = pip.objsubid) "
15112 							  "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15113 							  "NOT at.attisdropped "
15114 							  "AND ("
15115 							  "%s IS NOT NULL OR "
15116 							  "%s IS NOT NULL OR "
15117 							  "%s IS NOT NULL OR "
15118 							  "%s IS NOT NULL)"
15119 							  "ORDER BY at.attnum",
15120 							  acl_subquery->data,
15121 							  racl_subquery->data,
15122 							  initacl_subquery->data,
15123 							  initracl_subquery->data,
15124 							  tbinfo->dobj.catId.oid,
15125 							  acl_subquery->data,
15126 							  racl_subquery->data,
15127 							  initacl_subquery->data,
15128 							  initracl_subquery->data);
15129 
15130 			destroyPQExpBuffer(acl_subquery);
15131 			destroyPQExpBuffer(racl_subquery);
15132 			destroyPQExpBuffer(initacl_subquery);
15133 			destroyPQExpBuffer(initracl_subquery);
15134 		}
15135 		else
15136 		{
15137 			appendPQExpBuffer(query,
15138 							  "SELECT attname, attacl, NULL as rattacl, "
15139 							  "NULL AS initattacl, NULL AS initrattacl "
15140 							  "FROM pg_catalog.pg_attribute "
15141 				"WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15142 							  "AND attacl IS NOT NULL "
15143 							  "ORDER BY attnum",
15144 							  tbinfo->dobj.catId.oid);
15145 		}
15146 
15147 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15148 
15149 		for (i = 0; i < PQntuples(res); i++)
15150 		{
15151 			char	   *attname = PQgetvalue(res, i, 0);
15152 			char	   *attacl = PQgetvalue(res, i, 1);
15153 			char	   *rattacl = PQgetvalue(res, i, 2);
15154 			char	   *initattacl = PQgetvalue(res, i, 3);
15155 			char	   *initrattacl = PQgetvalue(res, i, 4);
15156 			char	   *attnamecopy;
15157 
15158 			attnamecopy = pg_strdup(fmtId(attname));
15159 
15160 			/*
15161 			 * Column's GRANT type is always TABLE.  Each column ACL depends
15162 			 * on the table-level ACL, since we can restore column ACLs in
15163 			 * parallel but the table-level ACL has to be done first.
15164 			 */
15165 			dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
15166 					"TABLE", namecopy, attnamecopy,
15167 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15168 					attacl, rattacl, initattacl, initrattacl);
15169 			free(attnamecopy);
15170 		}
15171 		PQclear(res);
15172 		destroyPQExpBuffer(query);
15173 	}
15174 
15175 	free(namecopy);
15176 
15177 	return;
15178 }
15179 
15180 /*
15181  * Create the AS clause for a view or materialized view. The semicolon is
15182  * stripped because a materialized view must add a WITH NO DATA clause.
15183  *
15184  * This returns a new buffer which must be freed by the caller.
15185  */
15186 static PQExpBuffer
createViewAsClause(Archive * fout,TableInfo * tbinfo)15187 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15188 {
15189 	PQExpBuffer query = createPQExpBuffer();
15190 	PQExpBuffer result = createPQExpBuffer();
15191 	PGresult   *res;
15192 	int			len;
15193 
15194 	/* Fetch the view definition */
15195 	if (fout->remoteVersion >= 70300)
15196 	{
15197 		/* Beginning in 7.3, viewname is not unique; rely on OID */
15198 		appendPQExpBuffer(query,
15199 		 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15200 						  tbinfo->dobj.catId.oid);
15201 	}
15202 	else
15203 	{
15204 		appendPQExpBufferStr(query, "SELECT definition AS viewdef "
15205 							 "FROM pg_views WHERE viewname = ");
15206 		appendStringLiteralAH(query, tbinfo->dobj.name, fout);
15207 	}
15208 
15209 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15210 
15211 	if (PQntuples(res) != 1)
15212 	{
15213 		if (PQntuples(res) < 1)
15214 			exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
15215 						  tbinfo->dobj.name);
15216 		else
15217 			exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
15218 						  tbinfo->dobj.name);
15219 	}
15220 
15221 	len = PQgetlength(res, 0, 0);
15222 
15223 	if (len == 0)
15224 		exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
15225 					  tbinfo->dobj.name);
15226 
15227 	/* Strip off the trailing semicolon so that other things may follow. */
15228 	Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15229 	appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15230 
15231 	PQclear(res);
15232 	destroyPQExpBuffer(query);
15233 
15234 	return result;
15235 }
15236 
15237 /*
15238  * Create a dummy AS clause for a view.  This is used when the real view
15239  * definition has to be postponed because of circular dependencies.
15240  * We must duplicate the view's external properties -- column names and types
15241  * (including collation) -- so that it works for subsequent references.
15242  *
15243  * This returns a new buffer which must be freed by the caller.
15244  */
15245 static PQExpBuffer
createDummyViewAsClause(Archive * fout,TableInfo * tbinfo)15246 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15247 {
15248 	PQExpBuffer result = createPQExpBuffer();
15249 	int			j;
15250 
15251 	appendPQExpBufferStr(result, "SELECT");
15252 
15253 	for (j = 0; j < tbinfo->numatts; j++)
15254 	{
15255 		if (j > 0)
15256 			appendPQExpBufferChar(result, ',');
15257 		appendPQExpBufferStr(result, "\n    ");
15258 
15259 		appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15260 
15261 		/*
15262 		 * Must add collation if not default for the type, because CREATE OR
15263 		 * REPLACE VIEW won't change it
15264 		 */
15265 		if (OidIsValid(tbinfo->attcollation[j]))
15266 		{
15267 			CollInfo   *coll;
15268 
15269 			coll = findCollationByOid(tbinfo->attcollation[j]);
15270 			if (coll)
15271 				appendPQExpBuffer(result, " COLLATE %s",
15272 								  fmtQualifiedDumpable(coll));
15273 		}
15274 
15275 		appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15276 	}
15277 
15278 	return result;
15279 }
15280 
15281 /*
15282  * dumpTableSchema
15283  *	  write the declaration (not data) of one user-defined table or view
15284  */
15285 static void
dumpTableSchema(Archive * fout,TableInfo * tbinfo)15286 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15287 {
15288 	DumpOptions *dopt = fout->dopt;
15289 	PQExpBuffer q = createPQExpBuffer();
15290 	PQExpBuffer delq = createPQExpBuffer();
15291 	char	   *qrelname;
15292 	char	   *qualrelname;
15293 	int			numParents;
15294 	TableInfo **parents;
15295 	int			actual_atts;	/* number of attrs in this CREATE statement */
15296 	const char *reltypename;
15297 	char	   *storage;
15298 	char	   *srvname;
15299 	char	   *ftoptions;
15300 	int			j,
15301 				k;
15302 
15303 	/* We had better have loaded per-column details about this table */
15304 	Assert(tbinfo->interesting);
15305 
15306 	qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15307 	qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15308 
15309 	if (dopt->binary_upgrade)
15310 		binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15311 												tbinfo->dobj.catId.oid);
15312 
15313 	/* Is it a table or a view? */
15314 	if (tbinfo->relkind == RELKIND_VIEW)
15315 	{
15316 		PQExpBuffer result;
15317 
15318 		/*
15319 		 * Note: keep this code in sync with the is_view case in dumpRule()
15320 		 */
15321 
15322 		reltypename = "VIEW";
15323 
15324 		appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15325 
15326 		if (dopt->binary_upgrade)
15327 			binary_upgrade_set_pg_class_oids(fout, q,
15328 											 tbinfo->dobj.catId.oid, false);
15329 
15330 		appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15331 
15332 		if (tbinfo->dummy_view)
15333 			result = createDummyViewAsClause(fout, tbinfo);
15334 		else
15335 		{
15336 			if (nonemptyReloptions(tbinfo->reloptions))
15337 			{
15338 				appendPQExpBufferStr(q, " WITH (");
15339 				appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15340 				appendPQExpBufferChar(q, ')');
15341 			}
15342 			result = createViewAsClause(fout, tbinfo);
15343 		}
15344 		appendPQExpBuffer(q, " AS\n%s", result->data);
15345 		destroyPQExpBuffer(result);
15346 
15347 		if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15348 			appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15349 		appendPQExpBufferStr(q, ";\n");
15350 	}
15351 	else
15352 	{
15353 		switch (tbinfo->relkind)
15354 		{
15355 			case (RELKIND_FOREIGN_TABLE):
15356 				{
15357 					PQExpBuffer query = createPQExpBuffer();
15358 					PGresult   *res;
15359 					int			i_srvname;
15360 					int			i_ftoptions;
15361 
15362 					reltypename = "FOREIGN TABLE";
15363 
15364 					/* retrieve name of foreign server and generic options */
15365 					appendPQExpBuffer(query,
15366 									  "SELECT fs.srvname, "
15367 									  "pg_catalog.array_to_string(ARRAY("
15368 							 "SELECT pg_catalog.quote_ident(option_name) || "
15369 							 "' ' || pg_catalog.quote_literal(option_value) "
15370 							"FROM pg_catalog.pg_options_to_table(ftoptions) "
15371 									  "ORDER BY option_name"
15372 									  "), E',\n    ') AS ftoptions "
15373 									  "FROM pg_catalog.pg_foreign_table ft "
15374 									  "JOIN pg_catalog.pg_foreign_server fs "
15375 									  "ON (fs.oid = ft.ftserver) "
15376 									  "WHERE ft.ftrelid = '%u'",
15377 									  tbinfo->dobj.catId.oid);
15378 					res = ExecuteSqlQueryForSingleRow(fout, query->data);
15379 					i_srvname = PQfnumber(res, "srvname");
15380 					i_ftoptions = PQfnumber(res, "ftoptions");
15381 					srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15382 					ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15383 					PQclear(res);
15384 					destroyPQExpBuffer(query);
15385 					break;
15386 				}
15387 			case (RELKIND_MATVIEW):
15388 				reltypename = "MATERIALIZED VIEW";
15389 				srvname = NULL;
15390 				ftoptions = NULL;
15391 				break;
15392 			default:
15393 				reltypename = "TABLE";
15394 				srvname = NULL;
15395 				ftoptions = NULL;
15396 		}
15397 
15398 		numParents = tbinfo->numParents;
15399 		parents = tbinfo->parents;
15400 
15401 		appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15402 
15403 		if (dopt->binary_upgrade)
15404 			binary_upgrade_set_pg_class_oids(fout, q,
15405 											 tbinfo->dobj.catId.oid, false);
15406 
15407 		appendPQExpBuffer(q, "CREATE %s%s %s",
15408 						  tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15409 						  "UNLOGGED " : "",
15410 						  reltypename,
15411 						  qualrelname);
15412 
15413 		/*
15414 		 * Attach to type, if reloftype; except in case of a binary upgrade,
15415 		 * we dump the table normally and attach it to the type afterward.
15416 		 */
15417 		if (tbinfo->reloftype && !dopt->binary_upgrade)
15418 			appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15419 
15420 		if (tbinfo->relkind != RELKIND_MATVIEW)
15421 		{
15422 			/* Dump the attributes */
15423 			actual_atts = 0;
15424 			for (j = 0; j < tbinfo->numatts; j++)
15425 			{
15426 				/*
15427 				 * Normally, dump if it's locally defined in this table, and
15428 				 * not dropped.  But for binary upgrade, we'll dump all the
15429 				 * columns, and then fix up the dropped and nonlocal cases
15430 				 * below.
15431 				 */
15432 				if (shouldPrintColumn(dopt, tbinfo, j))
15433 				{
15434 					/*
15435 					 * Default value --- suppress if to be printed separately.
15436 					 */
15437 					bool		has_default = (tbinfo->attrdefs[j] != NULL &&
15438 											 !tbinfo->attrdefs[j]->separate);
15439 
15440 					/*
15441 					 * Not Null constraint --- suppress if inherited, except
15442 					 * in binary-upgrade case where that won't work.
15443 					 */
15444 					bool		has_notnull = (tbinfo->notnull[j] &&
15445 											   (!tbinfo->inhNotNull[j] ||
15446 												dopt->binary_upgrade));
15447 
15448 					/* Skip column if fully defined by reloftype */
15449 					if (tbinfo->reloftype &&
15450 						!has_default && !has_notnull && !dopt->binary_upgrade)
15451 						continue;
15452 
15453 					/* Format properly if not first attr */
15454 					if (actual_atts == 0)
15455 						appendPQExpBufferStr(q, " (");
15456 					else
15457 						appendPQExpBufferChar(q, ',');
15458 					appendPQExpBufferStr(q, "\n    ");
15459 					actual_atts++;
15460 
15461 					/* Attribute name */
15462 					appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15463 
15464 					if (tbinfo->attisdropped[j])
15465 					{
15466 						/*
15467 						 * ALTER TABLE DROP COLUMN clears
15468 						 * pg_attribute.atttypid, so we will not have gotten a
15469 						 * valid type name; insert INTEGER as a stopgap. We'll
15470 						 * clean things up later.
15471 						 */
15472 						appendPQExpBufferStr(q, " INTEGER /* dummy */");
15473 						/* Skip all the rest, too */
15474 						continue;
15475 					}
15476 
15477 					/* Attribute type */
15478 					if (tbinfo->reloftype && !dopt->binary_upgrade)
15479 					{
15480 						appendPQExpBufferStr(q, " WITH OPTIONS");
15481 					}
15482 					else if (fout->remoteVersion >= 70100)
15483 					{
15484 						appendPQExpBuffer(q, " %s",
15485 										  tbinfo->atttypnames[j]);
15486 					}
15487 					else
15488 					{
15489 						/* If no format_type, fake it */
15490 						appendPQExpBuffer(q, " %s",
15491 										  myFormatType(tbinfo->atttypnames[j],
15492 													   tbinfo->atttypmod[j]));
15493 					}
15494 
15495 					/* Add collation if not default for the type */
15496 					if (OidIsValid(tbinfo->attcollation[j]))
15497 					{
15498 						CollInfo   *coll;
15499 
15500 						coll = findCollationByOid(tbinfo->attcollation[j]);
15501 						if (coll)
15502 							appendPQExpBuffer(q, " COLLATE %s",
15503 											  fmtQualifiedDumpable(coll));
15504 					}
15505 
15506 					if (has_default)
15507 						appendPQExpBuffer(q, " DEFAULT %s",
15508 										  tbinfo->attrdefs[j]->adef_expr);
15509 
15510 					if (has_notnull)
15511 						appendPQExpBufferStr(q, " NOT NULL");
15512 				}
15513 			}
15514 
15515 			/*
15516 			 * Add non-inherited CHECK constraints, if any.
15517 			 */
15518 			for (j = 0; j < tbinfo->ncheck; j++)
15519 			{
15520 				ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15521 
15522 				if (constr->separate || !constr->conislocal)
15523 					continue;
15524 
15525 				if (actual_atts == 0)
15526 					appendPQExpBufferStr(q, " (\n    ");
15527 				else
15528 					appendPQExpBufferStr(q, ",\n    ");
15529 
15530 				appendPQExpBuffer(q, "CONSTRAINT %s ",
15531 								  fmtId(constr->dobj.name));
15532 				appendPQExpBufferStr(q, constr->condef);
15533 
15534 				actual_atts++;
15535 			}
15536 
15537 			if (actual_atts)
15538 				appendPQExpBufferStr(q, "\n)");
15539 			else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
15540 			{
15541 				/*
15542 				 * We must have a parenthesized attribute list, even though
15543 				 * empty, when not using the OF TYPE syntax.
15544 				 */
15545 				appendPQExpBufferStr(q, " (\n)");
15546 			}
15547 
15548 			if (numParents > 0 && !dopt->binary_upgrade)
15549 			{
15550 				appendPQExpBufferStr(q, "\nINHERITS (");
15551 				for (k = 0; k < numParents; k++)
15552 				{
15553 					TableInfo  *parentRel = parents[k];
15554 
15555 					if (k > 0)
15556 						appendPQExpBufferStr(q, ", ");
15557 					appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15558 				}
15559 				appendPQExpBufferChar(q, ')');
15560 			}
15561 
15562 			if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15563 				appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15564 		}
15565 
15566 		if (nonemptyReloptions(tbinfo->reloptions) ||
15567 			nonemptyReloptions(tbinfo->toast_reloptions))
15568 		{
15569 			bool		addcomma = false;
15570 
15571 			appendPQExpBufferStr(q, "\nWITH (");
15572 			if (nonemptyReloptions(tbinfo->reloptions))
15573 			{
15574 				addcomma = true;
15575 				appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15576 			}
15577 			if (nonemptyReloptions(tbinfo->toast_reloptions))
15578 			{
15579 				if (addcomma)
15580 					appendPQExpBufferStr(q, ", ");
15581 				appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15582 										fout);
15583 			}
15584 			appendPQExpBufferChar(q, ')');
15585 		}
15586 
15587 		/* Dump generic options if any */
15588 		if (ftoptions && ftoptions[0])
15589 			appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15590 
15591 		/*
15592 		 * For materialized views, create the AS clause just like a view. At
15593 		 * this point, we always mark the view as not populated.
15594 		 */
15595 		if (tbinfo->relkind == RELKIND_MATVIEW)
15596 		{
15597 			PQExpBuffer result;
15598 
15599 			result = createViewAsClause(fout, tbinfo);
15600 			appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15601 							  result->data);
15602 			destroyPQExpBuffer(result);
15603 		}
15604 		else
15605 			appendPQExpBufferStr(q, ";\n");
15606 
15607 		/* Materialized views can depend on extensions */
15608 		if (tbinfo->relkind == RELKIND_MATVIEW)
15609 			append_depends_on_extension(fout, q, &tbinfo->dobj,
15610 										"pg_catalog.pg_class",
15611 										tbinfo->relkind == RELKIND_MATVIEW ?
15612 										"MATERIALIZED VIEW" : "INDEX",
15613 										qualrelname);
15614 
15615 		/*
15616 		 * To create binary-compatible heap files, we have to ensure the same
15617 		 * physical column order, including dropped columns, as in the
15618 		 * original.  Therefore, we create dropped columns above and drop them
15619 		 * here, also updating their attlen/attalign values so that the
15620 		 * dropped column can be skipped properly.  (We do not bother with
15621 		 * restoring the original attbyval setting.)  Also, inheritance
15622 		 * relationships are set up by doing ALTER TABLE INHERIT rather than
15623 		 * using an INHERITS clause --- the latter would possibly mess up the
15624 		 * column order.  That also means we have to take care about setting
15625 		 * attislocal correctly, plus fix up any inherited CHECK constraints.
15626 		 * Analogously, we set up typed tables using ALTER TABLE / OF here.
15627 		 *
15628 		 * We process foreign tables here, even though they lack heap storage,
15629 		 * because they can participate in inheritance relationships and we
15630 		 * want this stuff to be consistent across the inheritance tree.  We
15631 		 * exclude indexes, toast tables, sequences and matviews, even though
15632 		 * they have storage, because we don't support altering or dropping
15633 		 * columns in them, nor can they be part of inheritance trees.
15634 		 */
15635 		if (dopt->binary_upgrade &&
15636 			(tbinfo->relkind == RELKIND_RELATION ||
15637 			 tbinfo->relkind == RELKIND_FOREIGN_TABLE))
15638 		{
15639 			for (j = 0; j < tbinfo->numatts; j++)
15640 			{
15641 				if (tbinfo->attisdropped[j])
15642 				{
15643 					appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15644 					appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15645 									  "SET attlen = %d, "
15646 									  "attalign = '%c', attbyval = false\n"
15647 									  "WHERE attname = ",
15648 									  tbinfo->attlen[j],
15649 									  tbinfo->attalign[j]);
15650 					appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15651 					appendPQExpBufferStr(q, "\n  AND attrelid = ");
15652 					appendStringLiteralAH(q, qualrelname, fout);
15653 					appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15654 
15655 					if (tbinfo->relkind == RELKIND_RELATION)
15656 						appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15657 										  qualrelname);
15658 					else
15659 						appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15660 										  qualrelname);
15661 					appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15662 									  fmtId(tbinfo->attnames[j]));
15663 				}
15664 				else if (!tbinfo->attislocal[j])
15665 				{
15666 					appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15667 					appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15668 										 "SET attislocal = false\n"
15669 										 "WHERE attname = ");
15670 					appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15671 					appendPQExpBufferStr(q, "\n  AND attrelid = ");
15672 					appendStringLiteralAH(q, qualrelname, fout);
15673 					appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15674 				}
15675 			}
15676 
15677 			for (k = 0; k < tbinfo->ncheck; k++)
15678 			{
15679 				ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15680 
15681 				if (constr->separate || constr->conislocal)
15682 					continue;
15683 
15684 				appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15685 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15686 								  qualrelname);
15687 				appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15688 								  fmtId(constr->dobj.name));
15689 				appendPQExpBuffer(q, "%s;\n", constr->condef);
15690 				appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15691 									 "SET conislocal = false\n"
15692 									 "WHERE contype = 'c' AND conname = ");
15693 				appendStringLiteralAH(q, constr->dobj.name, fout);
15694 				appendPQExpBufferStr(q, "\n  AND conrelid = ");
15695 				appendStringLiteralAH(q, qualrelname, fout);
15696 				appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15697 			}
15698 
15699 			if (numParents > 0)
15700 			{
15701 				appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
15702 				for (k = 0; k < numParents; k++)
15703 				{
15704 					TableInfo  *parentRel = parents[k];
15705 
15706 					appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
15707 									  qualrelname);
15708 					appendPQExpBuffer(q, "%s;\n",
15709 									  fmtQualifiedDumpable(parentRel));
15710 				}
15711 			}
15712 
15713 			if (tbinfo->reloftype)
15714 			{
15715 				appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15716 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15717 								  qualrelname,
15718 								  tbinfo->reloftype);
15719 			}
15720 		}
15721 
15722 		/*
15723 		 * In binary_upgrade mode, arrange to restore the old relfrozenxid and
15724 		 * relminmxid of all vacuumable relations.  (While vacuum.c processes
15725 		 * TOAST tables semi-independently, here we see them only as children
15726 		 * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
15727 		 * child toast table is handled below.)
15728 		 */
15729 		if (dopt->binary_upgrade &&
15730 			(tbinfo->relkind == RELKIND_RELATION ||
15731 			 tbinfo->relkind == RELKIND_MATVIEW))
15732 		{
15733 			appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15734 			appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15735 							  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15736 							  "WHERE oid = ",
15737 							  tbinfo->frozenxid, tbinfo->minmxid);
15738 			appendStringLiteralAH(q, qualrelname, fout);
15739 			appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15740 
15741 			if (tbinfo->toast_oid)
15742 			{
15743 				/*
15744 				 * The toast table will have the same OID at restore, so we
15745 				 * can safely target it by OID.
15746 				 */
15747 				appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
15748 				appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15749 							   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15750 								  "WHERE oid = '%u';\n",
15751 								  tbinfo->toast_frozenxid,
15752 								  tbinfo->toast_minmxid, tbinfo->toast_oid);
15753 			}
15754 		}
15755 
15756 		/*
15757 		 * In binary_upgrade mode, restore matviews' populated status by
15758 		 * poking pg_class directly.  This is pretty ugly, but we can't use
15759 		 * REFRESH MATERIALIZED VIEW since it's possible that some underlying
15760 		 * matview is not populated even though this matview is; in any case,
15761 		 * we want to transfer the matview's heap storage, not run REFRESH.
15762 		 */
15763 		if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
15764 			tbinfo->relispopulated)
15765 		{
15766 			appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
15767 			appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
15768 								 "SET relispopulated = 't'\n"
15769 								 "WHERE oid = ");
15770 			appendStringLiteralAH(q, qualrelname, fout);
15771 			appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15772 		}
15773 
15774 		/*
15775 		 * Dump additional per-column properties that we can't handle in the
15776 		 * main CREATE TABLE command.
15777 		 */
15778 		for (j = 0; j < tbinfo->numatts; j++)
15779 		{
15780 			/* None of this applies to dropped columns */
15781 			if (tbinfo->attisdropped[j])
15782 				continue;
15783 
15784 			/*
15785 			 * If we didn't dump the column definition explicitly above, and
15786 			 * it is NOT NULL and did not inherit that property from a parent,
15787 			 * we have to mark it separately.
15788 			 */
15789 			if (!shouldPrintColumn(dopt, tbinfo, j) &&
15790 				tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
15791 			{
15792 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15793 								  qualrelname);
15794 				appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
15795 								  fmtId(tbinfo->attnames[j]));
15796 			}
15797 
15798 			/*
15799 			 * Dump per-column statistics information. We only issue an ALTER
15800 			 * TABLE statement if the attstattarget entry for this column is
15801 			 * non-negative (i.e. it's not the default value)
15802 			 */
15803 			if (tbinfo->attstattarget[j] >= 0)
15804 			{
15805 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15806 								  qualrelname);
15807 				appendPQExpBuffer(q, "ALTER COLUMN %s ",
15808 								  fmtId(tbinfo->attnames[j]));
15809 				appendPQExpBuffer(q, "SET STATISTICS %d;\n",
15810 								  tbinfo->attstattarget[j]);
15811 			}
15812 
15813 			/*
15814 			 * Dump per-column storage information.  The statement is only
15815 			 * dumped if the storage has been changed from the type's default.
15816 			 */
15817 			if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
15818 			{
15819 				switch (tbinfo->attstorage[j])
15820 				{
15821 					case 'p':
15822 						storage = "PLAIN";
15823 						break;
15824 					case 'e':
15825 						storage = "EXTERNAL";
15826 						break;
15827 					case 'm':
15828 						storage = "MAIN";
15829 						break;
15830 					case 'x':
15831 						storage = "EXTENDED";
15832 						break;
15833 					default:
15834 						storage = NULL;
15835 				}
15836 
15837 				/*
15838 				 * Only dump the statement if it's a storage type we recognize
15839 				 */
15840 				if (storage != NULL)
15841 				{
15842 					appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15843 									  qualrelname);
15844 					appendPQExpBuffer(q, "ALTER COLUMN %s ",
15845 									  fmtId(tbinfo->attnames[j]));
15846 					appendPQExpBuffer(q, "SET STORAGE %s;\n",
15847 									  storage);
15848 				}
15849 			}
15850 
15851 			/*
15852 			 * Dump per-column attributes.
15853 			 */
15854 			if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
15855 			{
15856 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15857 								  qualrelname);
15858 				appendPQExpBuffer(q, "ALTER COLUMN %s ",
15859 								  fmtId(tbinfo->attnames[j]));
15860 				appendPQExpBuffer(q, "SET (%s);\n",
15861 								  tbinfo->attoptions[j]);
15862 			}
15863 
15864 			/*
15865 			 * Dump per-column fdw options.
15866 			 */
15867 			if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
15868 				tbinfo->attfdwoptions[j] &&
15869 				tbinfo->attfdwoptions[j][0] != '\0')
15870 			{
15871 				appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
15872 								  qualrelname);
15873 				appendPQExpBuffer(q, "ALTER COLUMN %s ",
15874 								  fmtId(tbinfo->attnames[j]));
15875 				appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
15876 								  tbinfo->attfdwoptions[j]);
15877 			}
15878 		}
15879 	}
15880 
15881 	/*
15882 	 * dump properties we only have ALTER TABLE syntax for
15883 	 */
15884 	if ((tbinfo->relkind == RELKIND_RELATION ||
15885 		 tbinfo->relkind == RELKIND_MATVIEW) &&
15886 		tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
15887 	{
15888 		if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
15889 		{
15890 			/* nothing to do, will be set when the index is dumped */
15891 		}
15892 		else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
15893 		{
15894 			appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
15895 							  qualrelname);
15896 		}
15897 		else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
15898 		{
15899 			appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
15900 							  qualrelname);
15901 		}
15902 	}
15903 
15904 	if (tbinfo->relkind == RELKIND_FOREIGN_TABLE && tbinfo->hasoids)
15905 		appendPQExpBuffer(q, "\nALTER TABLE ONLY %s SET WITH OIDS;\n",
15906 						  qualrelname);
15907 
15908 	if (tbinfo->forcerowsec)
15909 		appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
15910 						  qualrelname);
15911 
15912 	if (dopt->binary_upgrade)
15913 		binary_upgrade_extension_member(q, &tbinfo->dobj,
15914 										reltypename, qrelname,
15915 										tbinfo->dobj.namespace->dobj.name);
15916 
15917 	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15918 		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15919 					 tbinfo->dobj.name,
15920 					 tbinfo->dobj.namespace->dobj.name,
15921 			(tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
15922 					 tbinfo->rolname,
15923 			   (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
15924 					 reltypename,
15925 					 tbinfo->postponed_def ?
15926 					 SECTION_POST_DATA : SECTION_PRE_DATA,
15927 					 q->data, delq->data, NULL,
15928 					 NULL, 0,
15929 					 NULL, NULL);
15930 
15931 
15932 	/* Dump Table Comments */
15933 	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15934 		dumpTableComment(fout, tbinfo, reltypename);
15935 
15936 	/* Dump Table Security Labels */
15937 	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
15938 		dumpTableSecLabel(fout, tbinfo, reltypename);
15939 
15940 	/* Dump comments on inlined table constraints */
15941 	for (j = 0; j < tbinfo->ncheck; j++)
15942 	{
15943 		ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15944 
15945 		if (constr->separate || !constr->conislocal)
15946 			continue;
15947 
15948 		if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15949 			dumpTableConstraintComment(fout, constr);
15950 	}
15951 
15952 	destroyPQExpBuffer(q);
15953 	destroyPQExpBuffer(delq);
15954 	free(qrelname);
15955 	free(qualrelname);
15956 }
15957 
15958 /*
15959  * dumpAttrDef --- dump an attribute's default-value declaration
15960  */
15961 static void
dumpAttrDef(Archive * fout,AttrDefInfo * adinfo)15962 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
15963 {
15964 	DumpOptions *dopt = fout->dopt;
15965 	TableInfo  *tbinfo = adinfo->adtable;
15966 	int			adnum = adinfo->adnum;
15967 	PQExpBuffer q;
15968 	PQExpBuffer delq;
15969 	char	   *qualrelname;
15970 	char	   *tag;
15971 
15972 	/* Skip if table definition not to be dumped */
15973 	if (!tbinfo->dobj.dump || dopt->dataOnly)
15974 		return;
15975 
15976 	/* Skip if not "separate"; it was dumped in the table's definition */
15977 	if (!adinfo->separate)
15978 		return;
15979 
15980 	q = createPQExpBuffer();
15981 	delq = createPQExpBuffer();
15982 
15983 	qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15984 
15985 	appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15986 					  qualrelname);
15987 	appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
15988 					  fmtId(tbinfo->attnames[adnum - 1]),
15989 					  adinfo->adef_expr);
15990 
15991 	appendPQExpBuffer(delq, "ALTER TABLE %s ",
15992 					  qualrelname);
15993 	appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
15994 					  fmtId(tbinfo->attnames[adnum - 1]));
15995 
15996 	tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
15997 
15998 	if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15999 		ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16000 					 tag,
16001 					 tbinfo->dobj.namespace->dobj.name,
16002 					 NULL,
16003 					 tbinfo->rolname,
16004 					 false, "DEFAULT", SECTION_PRE_DATA,
16005 					 q->data, delq->data, NULL,
16006 					 NULL, 0,
16007 					 NULL, NULL);
16008 
16009 	free(tag);
16010 	destroyPQExpBuffer(q);
16011 	destroyPQExpBuffer(delq);
16012 	free(qualrelname);
16013 }
16014 
16015 /*
16016  * getAttrName: extract the correct name for an attribute
16017  *
16018  * The array tblInfo->attnames[] only provides names of user attributes;
16019  * if a system attribute number is supplied, we have to fake it.
16020  * We also do a little bit of bounds checking for safety's sake.
16021  */
16022 static const char *
getAttrName(int attrnum,TableInfo * tblInfo)16023 getAttrName(int attrnum, TableInfo *tblInfo)
16024 {
16025 	if (attrnum > 0 && attrnum <= tblInfo->numatts)
16026 		return tblInfo->attnames[attrnum - 1];
16027 	switch (attrnum)
16028 	{
16029 		case SelfItemPointerAttributeNumber:
16030 			return "ctid";
16031 		case ObjectIdAttributeNumber:
16032 			return "oid";
16033 		case MinTransactionIdAttributeNumber:
16034 			return "xmin";
16035 		case MinCommandIdAttributeNumber:
16036 			return "cmin";
16037 		case MaxTransactionIdAttributeNumber:
16038 			return "xmax";
16039 		case MaxCommandIdAttributeNumber:
16040 			return "cmax";
16041 		case TableOidAttributeNumber:
16042 			return "tableoid";
16043 	}
16044 	exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
16045 				  attrnum, tblInfo->dobj.name);
16046 	return NULL;				/* keep compiler quiet */
16047 }
16048 
16049 /*
16050  * dumpIndex
16051  *	  write out to fout a user-defined index
16052  */
16053 static void
dumpIndex(Archive * fout,IndxInfo * indxinfo)16054 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16055 {
16056 	DumpOptions *dopt = fout->dopt;
16057 	TableInfo  *tbinfo = indxinfo->indextable;
16058 	bool		is_constraint = (indxinfo->indexconstraint != 0);
16059 	PQExpBuffer q;
16060 	PQExpBuffer delq;
16061 	char	   *qindxname;
16062 	char	   *qqindxname;
16063 
16064 	if (dopt->dataOnly)
16065 		return;
16066 
16067 	q = createPQExpBuffer();
16068 	delq = createPQExpBuffer();
16069 
16070 	qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16071 	qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
16072 
16073 	/*
16074 	 * If there's an associated constraint, don't dump the index per se, but
16075 	 * do dump any comment for it.  (This is safe because dependency ordering
16076 	 * will have ensured the constraint is emitted first.)	Note that the
16077 	 * emitted comment has to be shown as depending on the constraint, not the
16078 	 * index, in such cases.
16079 	 */
16080 	if (!is_constraint)
16081 	{
16082 		if (dopt->binary_upgrade)
16083 			binary_upgrade_set_pg_class_oids(fout, q,
16084 											 indxinfo->dobj.catId.oid, true);
16085 
16086 		/* Plain secondary index */
16087 		appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16088 
16089 		/*
16090 		 * Append ALTER TABLE commands as needed to set properties that we
16091 		 * only have ALTER TABLE syntax for.  Keep this in sync with the
16092 		 * similar code in dumpConstraint!
16093 		 */
16094 
16095 		/* If the index is clustered, we need to record that. */
16096 		if (indxinfo->indisclustered)
16097 		{
16098 			appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16099 							  fmtQualifiedDumpable(tbinfo));
16100 			/* index name is not qualified in this syntax */
16101 			appendPQExpBuffer(q, " ON %s;\n",
16102 							  qindxname);
16103 		}
16104 
16105 		/* Indexes can depend on extensions */
16106 		append_depends_on_extension(fout, q, &indxinfo->dobj,
16107 									"pg_catalog.pg_class",
16108 									"INDEX", qqindxname);
16109 
16110 		/* If the index defines identity, we need to record that. */
16111 		if (indxinfo->indisreplident)
16112 		{
16113 			appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16114 							  fmtQualifiedDumpable(tbinfo));
16115 			/* index name is not qualified in this syntax */
16116 			appendPQExpBuffer(q, " INDEX %s;\n",
16117 							  qindxname);
16118 		}
16119 
16120 		appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
16121 
16122 		if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16123 			ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16124 						 indxinfo->dobj.name,
16125 						 tbinfo->dobj.namespace->dobj.name,
16126 						 indxinfo->tablespace,
16127 						 tbinfo->rolname, false,
16128 						 "INDEX", SECTION_POST_DATA,
16129 						 q->data, delq->data, NULL,
16130 						 NULL, 0,
16131 						 NULL, NULL);
16132 	}
16133 
16134 	/* Dump Index Comments */
16135 	if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16136 		dumpComment(fout, "INDEX", qindxname,
16137 					tbinfo->dobj.namespace->dobj.name,
16138 					tbinfo->rolname,
16139 					indxinfo->dobj.catId, 0,
16140 					is_constraint ? indxinfo->indexconstraint :
16141 					indxinfo->dobj.dumpId);
16142 
16143 	destroyPQExpBuffer(q);
16144 	destroyPQExpBuffer(delq);
16145 	free(qindxname);
16146 	free(qqindxname);
16147 }
16148 
16149 /*
16150  * dumpConstraint
16151  *	  write out to fout a user-defined constraint
16152  */
16153 static void
dumpConstraint(Archive * fout,ConstraintInfo * coninfo)16154 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16155 {
16156 	DumpOptions *dopt = fout->dopt;
16157 	TableInfo  *tbinfo = coninfo->contable;
16158 	PQExpBuffer q;
16159 	PQExpBuffer delq;
16160 	char	   *tag = NULL;
16161 
16162 	/* Skip if not to be dumped */
16163 	if (!coninfo->dobj.dump || dopt->dataOnly)
16164 		return;
16165 
16166 	q = createPQExpBuffer();
16167 	delq = createPQExpBuffer();
16168 
16169 	if (coninfo->contype == 'p' ||
16170 		coninfo->contype == 'u' ||
16171 		coninfo->contype == 'x')
16172 	{
16173 		/* Index-related constraint */
16174 		IndxInfo   *indxinfo;
16175 		int			k;
16176 
16177 		indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16178 
16179 		if (indxinfo == NULL)
16180 			exit_horribly(NULL, "missing index for constraint \"%s\"\n",
16181 						  coninfo->dobj.name);
16182 
16183 		if (dopt->binary_upgrade)
16184 			binary_upgrade_set_pg_class_oids(fout, q,
16185 											 indxinfo->dobj.catId.oid, true);
16186 
16187 		appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16188 						  fmtQualifiedDumpable(tbinfo));
16189 		appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16190 						  fmtId(coninfo->dobj.name));
16191 
16192 		if (coninfo->condef)
16193 		{
16194 			/* pg_get_constraintdef should have provided everything */
16195 			appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16196 		}
16197 		else
16198 		{
16199 			appendPQExpBuffer(q, "%s (",
16200 						 coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16201 			for (k = 0; k < indxinfo->indnkeys; k++)
16202 			{
16203 				int			indkey = (int) indxinfo->indkeys[k];
16204 				const char *attname;
16205 
16206 				if (indkey == InvalidAttrNumber)
16207 					break;
16208 				attname = getAttrName(indkey, tbinfo);
16209 
16210 				appendPQExpBuffer(q, "%s%s",
16211 								  (k == 0) ? "" : ", ",
16212 								  fmtId(attname));
16213 			}
16214 
16215 			appendPQExpBufferChar(q, ')');
16216 
16217 			if (nonemptyReloptions(indxinfo->indreloptions))
16218 			{
16219 				appendPQExpBufferStr(q, " WITH (");
16220 				appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16221 				appendPQExpBufferChar(q, ')');
16222 			}
16223 
16224 			if (coninfo->condeferrable)
16225 			{
16226 				appendPQExpBufferStr(q, " DEFERRABLE");
16227 				if (coninfo->condeferred)
16228 					appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16229 			}
16230 
16231 			appendPQExpBufferStr(q, ";\n");
16232 		}
16233 
16234 		/*
16235 		 * Append ALTER TABLE commands as needed to set properties that we
16236 		 * only have ALTER TABLE syntax for.  Keep this in sync with the
16237 		 * similar code in dumpIndex!
16238 		 */
16239 
16240 		/* If the index is clustered, we need to record that. */
16241 		if (indxinfo->indisclustered)
16242 		{
16243 			appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16244 							  fmtQualifiedDumpable(tbinfo));
16245 			/* index name is not qualified in this syntax */
16246 			appendPQExpBuffer(q, " ON %s;\n",
16247 							  fmtId(indxinfo->dobj.name));
16248 		}
16249 
16250 		/* If the index defines identity, we need to record that. */
16251 		if (indxinfo->indisreplident)
16252 		{
16253 			appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16254 							  fmtQualifiedDumpable(tbinfo));
16255 			/* index name is not qualified in this syntax */
16256 			appendPQExpBuffer(q, " INDEX %s;\n",
16257 							  fmtId(indxinfo->dobj.name));
16258 		}
16259 
16260 		/* Indexes can depend on extensions */
16261 		append_depends_on_extension(fout, q, &indxinfo->dobj,
16262 									"pg_catalog.pg_class", "INDEX",
16263 									fmtQualifiedDumpable(indxinfo));
16264 
16265 		appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16266 						  fmtQualifiedDumpable(tbinfo));
16267 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16268 						  fmtId(coninfo->dobj.name));
16269 
16270 		tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16271 
16272 		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16273 			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16274 						 tag,
16275 						 tbinfo->dobj.namespace->dobj.name,
16276 						 indxinfo->tablespace,
16277 						 tbinfo->rolname, false,
16278 						 "CONSTRAINT", SECTION_POST_DATA,
16279 						 q->data, delq->data, NULL,
16280 						 NULL, 0,
16281 						 NULL, NULL);
16282 	}
16283 	else if (coninfo->contype == 'f')
16284 	{
16285 		/*
16286 		 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16287 		 * current table data is not processed
16288 		 */
16289 		appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16290 						  fmtQualifiedDumpable(tbinfo));
16291 		appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16292 						  fmtId(coninfo->dobj.name),
16293 						  coninfo->condef);
16294 
16295 		appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16296 						  fmtQualifiedDumpable(tbinfo));
16297 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16298 						  fmtId(coninfo->dobj.name));
16299 
16300 		tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16301 
16302 		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16303 			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16304 						 tag,
16305 						 tbinfo->dobj.namespace->dobj.name,
16306 						 NULL,
16307 						 tbinfo->rolname, false,
16308 						 "FK CONSTRAINT", SECTION_POST_DATA,
16309 						 q->data, delq->data, NULL,
16310 						 NULL, 0,
16311 						 NULL, NULL);
16312 	}
16313 	else if (coninfo->contype == 'c' && tbinfo)
16314 	{
16315 		/* CHECK constraint on a table */
16316 
16317 		/* Ignore if not to be dumped separately, or if it was inherited */
16318 		if (coninfo->separate && coninfo->conislocal)
16319 		{
16320 			/* not ONLY since we want it to propagate to children */
16321 			appendPQExpBuffer(q, "ALTER TABLE %s\n",
16322 							  fmtQualifiedDumpable(tbinfo));
16323 			appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16324 							  fmtId(coninfo->dobj.name),
16325 							  coninfo->condef);
16326 
16327 			appendPQExpBuffer(delq, "ALTER TABLE %s ",
16328 							  fmtQualifiedDumpable(tbinfo));
16329 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16330 							  fmtId(coninfo->dobj.name));
16331 
16332 			tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16333 
16334 			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16335 				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16336 							 tag,
16337 							 tbinfo->dobj.namespace->dobj.name,
16338 							 NULL,
16339 							 tbinfo->rolname, false,
16340 							 "CHECK CONSTRAINT", SECTION_POST_DATA,
16341 							 q->data, delq->data, NULL,
16342 							 NULL, 0,
16343 							 NULL, NULL);
16344 		}
16345 	}
16346 	else if (coninfo->contype == 'c' && tbinfo == NULL)
16347 	{
16348 		/* CHECK constraint on a domain */
16349 		TypeInfo   *tyinfo = coninfo->condomain;
16350 
16351 		/* Ignore if not to be dumped separately */
16352 		if (coninfo->separate)
16353 		{
16354 			appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16355 							  fmtQualifiedDumpable(tyinfo));
16356 			appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16357 							  fmtId(coninfo->dobj.name),
16358 							  coninfo->condef);
16359 
16360 			appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16361 							  fmtQualifiedDumpable(tyinfo));
16362 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16363 							  fmtId(coninfo->dobj.name));
16364 
16365 			tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16366 
16367 			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16368 				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16369 							 tag,
16370 							 tyinfo->dobj.namespace->dobj.name,
16371 							 NULL,
16372 							 tyinfo->rolname, false,
16373 							 "CHECK CONSTRAINT", SECTION_POST_DATA,
16374 							 q->data, delq->data, NULL,
16375 							 NULL, 0,
16376 							 NULL, NULL);
16377 		}
16378 	}
16379 	else
16380 	{
16381 		exit_horribly(NULL, "unrecognized constraint type: %c\n",
16382 					  coninfo->contype);
16383 	}
16384 
16385 	/* Dump Constraint Comments --- only works for table constraints */
16386 	if (tbinfo && coninfo->separate &&
16387 		coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16388 		dumpTableConstraintComment(fout, coninfo);
16389 
16390 	free(tag);
16391 	destroyPQExpBuffer(q);
16392 	destroyPQExpBuffer(delq);
16393 }
16394 
16395 /*
16396  * dumpTableConstraintComment --- dump a constraint's comment if any
16397  *
16398  * This is split out because we need the function in two different places
16399  * depending on whether the constraint is dumped as part of CREATE TABLE
16400  * or as a separate ALTER command.
16401  */
16402 static void
dumpTableConstraintComment(Archive * fout,ConstraintInfo * coninfo)16403 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16404 {
16405 	TableInfo  *tbinfo = coninfo->contable;
16406 	PQExpBuffer conprefix = createPQExpBuffer();
16407 	char	   *qtabname;
16408 
16409 	qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16410 
16411 	appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16412 					  fmtId(coninfo->dobj.name));
16413 
16414 	if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16415 		dumpComment(fout, conprefix->data, qtabname,
16416 					tbinfo->dobj.namespace->dobj.name,
16417 					tbinfo->rolname,
16418 					coninfo->dobj.catId, 0,
16419 			 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16420 
16421 	destroyPQExpBuffer(conprefix);
16422 	free(qtabname);
16423 }
16424 
16425 /*
16426  * findLastBuiltinOid -
16427  * find the last built in oid
16428  *
16429  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16430  * pg_database entry for the current database
16431  */
16432 static Oid
findLastBuiltinOid_V71(Archive * fout,const char * dbname)16433 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
16434 {
16435 	PGresult   *res;
16436 	Oid			last_oid;
16437 	PQExpBuffer query = createPQExpBuffer();
16438 
16439 	resetPQExpBuffer(query);
16440 	appendPQExpBufferStr(query, "SELECT datlastsysoid from pg_database where datname = ");
16441 	appendStringLiteralAH(query, dbname, fout);
16442 
16443 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
16444 	last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16445 	PQclear(res);
16446 	destroyPQExpBuffer(query);
16447 	return last_oid;
16448 }
16449 
16450 /*
16451  * findLastBuiltinOid -
16452  * find the last built in oid
16453  *
16454  * For 7.0, we do this by assuming that the last thing that initdb does is to
16455  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
16456  * initdb won't be changing anymore, it'll do.
16457  */
16458 static Oid
findLastBuiltinOid_V70(Archive * fout)16459 findLastBuiltinOid_V70(Archive *fout)
16460 {
16461 	PGresult   *res;
16462 	int			last_oid;
16463 
16464 	res = ExecuteSqlQueryForSingleRow(fout,
16465 					"SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
16466 	last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
16467 	PQclear(res);
16468 	return last_oid;
16469 }
16470 
16471 /*
16472  * dumpSequence
16473  *	  write the declaration (not data) of one user-defined sequence
16474  */
16475 static void
dumpSequence(Archive * fout,TableInfo * tbinfo)16476 dumpSequence(Archive *fout, TableInfo *tbinfo)
16477 {
16478 	DumpOptions *dopt = fout->dopt;
16479 	PGresult   *res;
16480 	char	   *startv,
16481 			   *incby,
16482 			   *maxv = NULL,
16483 			   *minv = NULL,
16484 			   *cache;
16485 	char		bufm[100],
16486 				bufx[100];
16487 	bool		cycled;
16488 	PQExpBuffer query = createPQExpBuffer();
16489 	PQExpBuffer delqry = createPQExpBuffer();
16490 	char	   *qseqname;
16491 
16492 	qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16493 
16494 	snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
16495 	snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
16496 
16497 	if (fout->remoteVersion >= 80400)
16498 	{
16499 		appendPQExpBuffer(query,
16500 						  "SELECT sequence_name, "
16501 						  "start_value, increment_by, "
16502 				   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
16503 				   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
16504 						  "     ELSE max_value "
16505 						  "END AS max_value, "
16506 					"CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
16507 				   "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
16508 						  "     ELSE min_value "
16509 						  "END AS min_value, "
16510 						  "cache_value, is_cycled FROM %s",
16511 						  bufx, bufm,
16512 						  fmtQualifiedDumpable(tbinfo));
16513 	}
16514 	else
16515 	{
16516 		appendPQExpBuffer(query,
16517 						  "SELECT sequence_name, "
16518 						  "0 AS start_value, increment_by, "
16519 				   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
16520 				   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
16521 						  "     ELSE max_value "
16522 						  "END AS max_value, "
16523 					"CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
16524 				   "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
16525 						  "     ELSE min_value "
16526 						  "END AS min_value, "
16527 						  "cache_value, is_cycled FROM %s",
16528 						  bufx, bufm,
16529 						  fmtQualifiedDumpable(tbinfo));
16530 	}
16531 
16532 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16533 
16534 	if (PQntuples(res) != 1)
16535 	{
16536 		write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16537 								 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16538 								 PQntuples(res)),
16539 				  tbinfo->dobj.name, PQntuples(res));
16540 		exit_nicely(1);
16541 	}
16542 
16543 	/* Disable this check: it fails if sequence has been renamed */
16544 #ifdef NOT_USED
16545 	if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
16546 	{
16547 		write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
16548 				  tbinfo->dobj.name, PQgetvalue(res, 0, 0));
16549 		exit_nicely(1);
16550 	}
16551 #endif
16552 
16553 	startv = PQgetvalue(res, 0, 1);
16554 	incby = PQgetvalue(res, 0, 2);
16555 	if (!PQgetisnull(res, 0, 3))
16556 		maxv = PQgetvalue(res, 0, 3);
16557 	if (!PQgetisnull(res, 0, 4))
16558 		minv = PQgetvalue(res, 0, 4);
16559 	cache = PQgetvalue(res, 0, 5);
16560 	cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16561 
16562 	appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
16563 					  fmtQualifiedDumpable(tbinfo));
16564 
16565 	resetPQExpBuffer(query);
16566 
16567 	if (dopt->binary_upgrade)
16568 	{
16569 		binary_upgrade_set_pg_class_oids(fout, query,
16570 										 tbinfo->dobj.catId.oid, false);
16571 		binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16572 												tbinfo->dobj.catId.oid);
16573 	}
16574 
16575 	appendPQExpBuffer(query,
16576 					  "CREATE SEQUENCE %s\n",
16577 					  fmtQualifiedDumpable(tbinfo));
16578 
16579 	if (fout->remoteVersion >= 80400)
16580 		appendPQExpBuffer(query, "    START WITH %s\n", startv);
16581 
16582 	appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
16583 
16584 	if (minv)
16585 		appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
16586 	else
16587 		appendPQExpBufferStr(query, "    NO MINVALUE\n");
16588 
16589 	if (maxv)
16590 		appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
16591 	else
16592 		appendPQExpBufferStr(query, "    NO MAXVALUE\n");
16593 
16594 	appendPQExpBuffer(query,
16595 					  "    CACHE %s%s",
16596 					  cache, (cycled ? "\n    CYCLE" : ""));
16597 
16598 	appendPQExpBufferStr(query, ";\n");
16599 
16600 	/* binary_upgrade:	no need to clear TOAST table oid */
16601 
16602 	if (dopt->binary_upgrade)
16603 		binary_upgrade_extension_member(query, &tbinfo->dobj,
16604 										"SEQUENCE", qseqname,
16605 										tbinfo->dobj.namespace->dobj.name);
16606 
16607 	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16608 		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16609 					 tbinfo->dobj.name,
16610 					 tbinfo->dobj.namespace->dobj.name,
16611 					 NULL,
16612 					 tbinfo->rolname,
16613 					 false, "SEQUENCE", SECTION_PRE_DATA,
16614 					 query->data, delqry->data, NULL,
16615 					 NULL, 0,
16616 					 NULL, NULL);
16617 
16618 	/*
16619 	 * If the sequence is owned by a table column, emit the ALTER for it as a
16620 	 * separate TOC entry immediately following the sequence's own entry. It's
16621 	 * OK to do this rather than using full sorting logic, because the
16622 	 * dependency that tells us it's owned will have forced the table to be
16623 	 * created first.  We can't just include the ALTER in the TOC entry
16624 	 * because it will fail if we haven't reassigned the sequence owner to
16625 	 * match the table's owner.
16626 	 *
16627 	 * We need not schema-qualify the table reference because both sequence
16628 	 * and table must be in the same schema.
16629 	 */
16630 	if (OidIsValid(tbinfo->owning_tab))
16631 	{
16632 		TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16633 
16634 		if (owning_tab == NULL)
16635 			exit_horribly(NULL, "failed sanity check, parent table OID %u of sequence OID %u not found\n",
16636 						  tbinfo->owning_tab, tbinfo->dobj.catId.oid);
16637 
16638 		if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
16639 		{
16640 			resetPQExpBuffer(query);
16641 			appendPQExpBuffer(query, "ALTER SEQUENCE %s",
16642 							  fmtQualifiedDumpable(tbinfo));
16643 			appendPQExpBuffer(query, " OWNED BY %s",
16644 							  fmtQualifiedDumpable(owning_tab));
16645 			appendPQExpBuffer(query, ".%s;\n",
16646 						fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16647 
16648 			if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16649 				ArchiveEntry(fout, nilCatalogId, createDumpId(),
16650 							 tbinfo->dobj.name,
16651 							 tbinfo->dobj.namespace->dobj.name,
16652 							 NULL,
16653 							 tbinfo->rolname,
16654 							 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
16655 							 query->data, "", NULL,
16656 							 &(tbinfo->dobj.dumpId), 1,
16657 							 NULL, NULL);
16658 		}
16659 	}
16660 
16661 	/* Dump Sequence Comments and Security Labels */
16662 	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16663 		dumpComment(fout, "SEQUENCE", qseqname,
16664 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16665 					tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16666 
16667 	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16668 		dumpSecLabel(fout, "SEQUENCE", qseqname,
16669 					 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16670 					 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16671 
16672 	PQclear(res);
16673 
16674 	destroyPQExpBuffer(query);
16675 	destroyPQExpBuffer(delqry);
16676 	free(qseqname);
16677 }
16678 
16679 /*
16680  * dumpSequenceData
16681  *	  write the data of one user-defined sequence
16682  */
16683 static void
dumpSequenceData(Archive * fout,TableDataInfo * tdinfo)16684 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
16685 {
16686 	TableInfo  *tbinfo = tdinfo->tdtable;
16687 	PGresult   *res;
16688 	char	   *last;
16689 	bool		called;
16690 	PQExpBuffer query = createPQExpBuffer();
16691 
16692 	appendPQExpBuffer(query,
16693 					  "SELECT last_value, is_called FROM %s",
16694 					  fmtQualifiedDumpable(tbinfo));
16695 
16696 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16697 
16698 	if (PQntuples(res) != 1)
16699 	{
16700 		write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16701 								 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16702 								 PQntuples(res)),
16703 				  tbinfo->dobj.name, PQntuples(res));
16704 		exit_nicely(1);
16705 	}
16706 
16707 	last = PQgetvalue(res, 0, 0);
16708 	called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
16709 
16710 	resetPQExpBuffer(query);
16711 	appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
16712 	appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
16713 	appendPQExpBuffer(query, ", %s, %s);\n",
16714 					  last, (called ? "true" : "false"));
16715 
16716 	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
16717 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
16718 					 tbinfo->dobj.name,
16719 					 tbinfo->dobj.namespace->dobj.name,
16720 					 NULL,
16721 					 tbinfo->rolname,
16722 					 false, "SEQUENCE SET", SECTION_DATA,
16723 					 query->data, "", NULL,
16724 					 &(tbinfo->dobj.dumpId), 1,
16725 					 NULL, NULL);
16726 
16727 	PQclear(res);
16728 
16729 	destroyPQExpBuffer(query);
16730 }
16731 
16732 /*
16733  * dumpTrigger
16734  *	  write the declaration of one user-defined table trigger
16735  */
16736 static void
dumpTrigger(Archive * fout,TriggerInfo * tginfo)16737 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
16738 {
16739 	DumpOptions *dopt = fout->dopt;
16740 	TableInfo  *tbinfo = tginfo->tgtable;
16741 	PQExpBuffer query;
16742 	PQExpBuffer delqry;
16743 	PQExpBuffer trigprefix;
16744 	PQExpBuffer trigidentity;
16745 	char	   *qtabname;
16746 	char	   *tgargs;
16747 	size_t		lentgargs;
16748 	const char *p;
16749 	int			findx;
16750 	char	   *tag;
16751 
16752 	/*
16753 	 * we needn't check dobj.dump because TriggerInfo wouldn't have been
16754 	 * created in the first place for non-dumpable triggers
16755 	 */
16756 	if (dopt->dataOnly)
16757 		return;
16758 
16759 	query = createPQExpBuffer();
16760 	delqry = createPQExpBuffer();
16761 	trigprefix = createPQExpBuffer();
16762 	trigidentity = createPQExpBuffer();
16763 
16764 	qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16765 
16766 	appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
16767 	appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
16768 
16769 	appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
16770 
16771 	if (tginfo->tgdef)
16772 	{
16773 		appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
16774 	}
16775 	else
16776 	{
16777 		if (tginfo->tgisconstraint)
16778 		{
16779 			appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
16780 			appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
16781 		}
16782 		else
16783 		{
16784 			appendPQExpBufferStr(query, "CREATE TRIGGER ");
16785 			appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
16786 		}
16787 		appendPQExpBufferStr(query, "\n    ");
16788 
16789 		/* Trigger type */
16790 		if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
16791 			appendPQExpBufferStr(query, "BEFORE");
16792 		else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
16793 			appendPQExpBufferStr(query, "AFTER");
16794 		else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
16795 			appendPQExpBufferStr(query, "INSTEAD OF");
16796 		else
16797 		{
16798 			write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
16799 			exit_nicely(1);
16800 		}
16801 
16802 		findx = 0;
16803 		if (TRIGGER_FOR_INSERT(tginfo->tgtype))
16804 		{
16805 			appendPQExpBufferStr(query, " INSERT");
16806 			findx++;
16807 		}
16808 		if (TRIGGER_FOR_DELETE(tginfo->tgtype))
16809 		{
16810 			if (findx > 0)
16811 				appendPQExpBufferStr(query, " OR DELETE");
16812 			else
16813 				appendPQExpBufferStr(query, " DELETE");
16814 			findx++;
16815 		}
16816 		if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
16817 		{
16818 			if (findx > 0)
16819 				appendPQExpBufferStr(query, " OR UPDATE");
16820 			else
16821 				appendPQExpBufferStr(query, " UPDATE");
16822 			findx++;
16823 		}
16824 		if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
16825 		{
16826 			if (findx > 0)
16827 				appendPQExpBufferStr(query, " OR TRUNCATE");
16828 			else
16829 				appendPQExpBufferStr(query, " TRUNCATE");
16830 			findx++;
16831 		}
16832 		appendPQExpBuffer(query, " ON %s\n",
16833 						  fmtQualifiedDumpable(tbinfo));
16834 
16835 		if (tginfo->tgisconstraint)
16836 		{
16837 			if (OidIsValid(tginfo->tgconstrrelid))
16838 			{
16839 				/* If we are using regclass, name is already quoted */
16840 				if (fout->remoteVersion >= 70300)
16841 					appendPQExpBuffer(query, "    FROM %s\n    ",
16842 									  tginfo->tgconstrrelname);
16843 				else
16844 					appendPQExpBuffer(query, "    FROM %s\n    ",
16845 									  fmtId(tginfo->tgconstrrelname));
16846 			}
16847 			if (!tginfo->tgdeferrable)
16848 				appendPQExpBufferStr(query, "NOT ");
16849 			appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
16850 			if (tginfo->tginitdeferred)
16851 				appendPQExpBufferStr(query, "DEFERRED\n");
16852 			else
16853 				appendPQExpBufferStr(query, "IMMEDIATE\n");
16854 		}
16855 
16856 		if (TRIGGER_FOR_ROW(tginfo->tgtype))
16857 			appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
16858 		else
16859 			appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
16860 
16861 		/* In 7.3, result of regproc is already quoted */
16862 		if (fout->remoteVersion >= 70300)
16863 			appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
16864 							  tginfo->tgfname);
16865 		else
16866 			appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
16867 							  fmtId(tginfo->tgfname));
16868 
16869 		tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
16870 										  &lentgargs);
16871 		p = tgargs;
16872 		for (findx = 0; findx < tginfo->tgnargs; findx++)
16873 		{
16874 			/* find the embedded null that terminates this trigger argument */
16875 			size_t		tlen = strlen(p);
16876 
16877 			if (p + tlen >= tgargs + lentgargs)
16878 			{
16879 				/* hm, not found before end of bytea value... */
16880 				write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
16881 						  tginfo->tgargs,
16882 						  tginfo->dobj.name,
16883 						  tbinfo->dobj.name);
16884 				exit_nicely(1);
16885 			}
16886 
16887 			if (findx > 0)
16888 				appendPQExpBufferStr(query, ", ");
16889 			appendStringLiteralAH(query, p, fout);
16890 			p += tlen + 1;
16891 		}
16892 		free(tgargs);
16893 		appendPQExpBufferStr(query, ");\n");
16894 	}
16895 
16896 	/* Triggers can depend on extensions */
16897 	append_depends_on_extension(fout, query, &tginfo->dobj,
16898 								"pg_catalog.pg_trigger", "TRIGGER",
16899 								trigidentity->data);
16900 
16901 	if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
16902 	{
16903 		appendPQExpBuffer(query, "\nALTER TABLE %s ",
16904 						  fmtQualifiedDumpable(tbinfo));
16905 		switch (tginfo->tgenabled)
16906 		{
16907 			case 'D':
16908 			case 'f':
16909 				appendPQExpBufferStr(query, "DISABLE");
16910 				break;
16911 			case 'A':
16912 				appendPQExpBufferStr(query, "ENABLE ALWAYS");
16913 				break;
16914 			case 'R':
16915 				appendPQExpBufferStr(query, "ENABLE REPLICA");
16916 				break;
16917 			default:
16918 				appendPQExpBufferStr(query, "ENABLE");
16919 				break;
16920 		}
16921 		appendPQExpBuffer(query, " TRIGGER %s;\n",
16922 						  fmtId(tginfo->dobj.name));
16923 	}
16924 
16925 	appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
16926 					  fmtId(tginfo->dobj.name));
16927 
16928 	tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
16929 
16930 	if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16931 		ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
16932 					 tag,
16933 					 tbinfo->dobj.namespace->dobj.name,
16934 					 NULL,
16935 					 tbinfo->rolname, false,
16936 					 "TRIGGER", SECTION_POST_DATA,
16937 					 query->data, delqry->data, NULL,
16938 					 NULL, 0,
16939 					 NULL, NULL);
16940 
16941 	if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16942 		dumpComment(fout, trigprefix->data, qtabname,
16943 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16944 					tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
16945 
16946 	free(tag);
16947 	destroyPQExpBuffer(query);
16948 	destroyPQExpBuffer(delqry);
16949 	destroyPQExpBuffer(trigprefix);
16950 	destroyPQExpBuffer(trigidentity);
16951 	free(qtabname);
16952 }
16953 
16954 /*
16955  * dumpEventTrigger
16956  *	  write the declaration of one user-defined event trigger
16957  */
16958 static void
dumpEventTrigger(Archive * fout,EventTriggerInfo * evtinfo)16959 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
16960 {
16961 	DumpOptions *dopt = fout->dopt;
16962 	PQExpBuffer query;
16963 	PQExpBuffer delqry;
16964 	char	   *qevtname;
16965 
16966 	/* Skip if not to be dumped */
16967 	if (!evtinfo->dobj.dump || dopt->dataOnly)
16968 		return;
16969 
16970 	query = createPQExpBuffer();
16971 	delqry = createPQExpBuffer();
16972 
16973 	qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
16974 
16975 	appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
16976 	appendPQExpBufferStr(query, qevtname);
16977 	appendPQExpBufferStr(query, " ON ");
16978 	appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
16979 
16980 	if (strcmp("", evtinfo->evttags) != 0)
16981 	{
16982 		appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
16983 		appendPQExpBufferStr(query, evtinfo->evttags);
16984 		appendPQExpBufferChar(query, ')');
16985 	}
16986 
16987 	appendPQExpBufferStr(query, "\n   EXECUTE PROCEDURE ");
16988 	appendPQExpBufferStr(query, evtinfo->evtfname);
16989 	appendPQExpBufferStr(query, "();\n");
16990 
16991 	if (evtinfo->evtenabled != 'O')
16992 	{
16993 		appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
16994 						  qevtname);
16995 		switch (evtinfo->evtenabled)
16996 		{
16997 			case 'D':
16998 				appendPQExpBufferStr(query, "DISABLE");
16999 				break;
17000 			case 'A':
17001 				appendPQExpBufferStr(query, "ENABLE ALWAYS");
17002 				break;
17003 			case 'R':
17004 				appendPQExpBufferStr(query, "ENABLE REPLICA");
17005 				break;
17006 			default:
17007 				appendPQExpBufferStr(query, "ENABLE");
17008 				break;
17009 		}
17010 		appendPQExpBufferStr(query, ";\n");
17011 	}
17012 
17013 	appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17014 					  qevtname);
17015 
17016 	if (dopt->binary_upgrade)
17017 		binary_upgrade_extension_member(query, &evtinfo->dobj,
17018 										"EVENT TRIGGER", qevtname, NULL);
17019 
17020 	if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17021 		ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17022 					 evtinfo->dobj.name, NULL, NULL,
17023 					 evtinfo->evtowner, false,
17024 					 "EVENT TRIGGER", SECTION_POST_DATA,
17025 					 query->data, delqry->data, NULL,
17026 					 NULL, 0,
17027 					 NULL, NULL);
17028 
17029 	if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17030 		dumpComment(fout, "EVENT TRIGGER", qevtname,
17031 					NULL, evtinfo->evtowner,
17032 					evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17033 
17034 	destroyPQExpBuffer(query);
17035 	destroyPQExpBuffer(delqry);
17036 	free(qevtname);
17037 }
17038 
17039 /*
17040  * dumpRule
17041  *		Dump a rule
17042  */
17043 static void
dumpRule(Archive * fout,RuleInfo * rinfo)17044 dumpRule(Archive *fout, RuleInfo *rinfo)
17045 {
17046 	DumpOptions *dopt = fout->dopt;
17047 	TableInfo  *tbinfo = rinfo->ruletable;
17048 	bool		is_view;
17049 	PQExpBuffer query;
17050 	PQExpBuffer cmd;
17051 	PQExpBuffer delcmd;
17052 	PQExpBuffer ruleprefix;
17053 	char	   *qtabname;
17054 	PGresult   *res;
17055 	char	   *tag;
17056 
17057 	/* Skip if not to be dumped */
17058 	if (!rinfo->dobj.dump || dopt->dataOnly)
17059 		return;
17060 
17061 	/*
17062 	 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17063 	 * we do not want to dump it as a separate object.
17064 	 */
17065 	if (!rinfo->separate)
17066 		return;
17067 
17068 	/*
17069 	 * If it's an ON SELECT rule, we want to print it as a view definition,
17070 	 * instead of a rule.
17071 	 */
17072 	is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17073 
17074 	query = createPQExpBuffer();
17075 	cmd = createPQExpBuffer();
17076 	delcmd = createPQExpBuffer();
17077 	ruleprefix = createPQExpBuffer();
17078 
17079 	qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17080 
17081 	if (is_view)
17082 	{
17083 		PQExpBuffer result;
17084 
17085 		/*
17086 		 * We need OR REPLACE here because we'll be replacing a dummy view.
17087 		 * Otherwise this should look largely like the regular view dump code.
17088 		 */
17089 		appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17090 						  fmtQualifiedDumpable(tbinfo));
17091 		if (nonemptyReloptions(tbinfo->reloptions))
17092 		{
17093 			appendPQExpBufferStr(cmd, " WITH (");
17094 			appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17095 			appendPQExpBufferChar(cmd, ')');
17096 		}
17097 		result = createViewAsClause(fout, tbinfo);
17098 		appendPQExpBuffer(cmd, " AS\n%s", result->data);
17099 		destroyPQExpBuffer(result);
17100 		if (tbinfo->checkoption != NULL)
17101 			appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17102 							  tbinfo->checkoption);
17103 		appendPQExpBufferStr(cmd, ";\n");
17104 	}
17105 	else
17106 	{
17107 		/* In the rule case, just print pg_get_ruledef's result verbatim */
17108 		if (fout->remoteVersion >= 70300)
17109 		{
17110 			appendPQExpBuffer(query,
17111 							  "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
17112 							  rinfo->dobj.catId.oid);
17113 		}
17114 		else
17115 		{
17116 			/* Rule name was unique before 7.3 ... */
17117 			appendPQExpBuffer(query,
17118 							  "SELECT pg_get_ruledef('%s') AS definition",
17119 							  rinfo->dobj.name);
17120 		}
17121 
17122 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17123 
17124 		if (PQntuples(res) != 1)
17125 		{
17126 			write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
17127 					  rinfo->dobj.name, tbinfo->dobj.name);
17128 			exit_nicely(1);
17129 		}
17130 
17131 		printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17132 
17133 		PQclear(res);
17134 	}
17135 
17136 	/*
17137 	 * Add the command to alter the rules replication firing semantics if it
17138 	 * differs from the default.
17139 	 */
17140 	if (rinfo->ev_enabled != 'O')
17141 	{
17142 		appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17143 		switch (rinfo->ev_enabled)
17144 		{
17145 			case 'A':
17146 				appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17147 								  fmtId(rinfo->dobj.name));
17148 				break;
17149 			case 'R':
17150 				appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17151 								  fmtId(rinfo->dobj.name));
17152 				break;
17153 			case 'D':
17154 				appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17155 								  fmtId(rinfo->dobj.name));
17156 				break;
17157 		}
17158 	}
17159 
17160 	if (is_view)
17161 	{
17162 		/*
17163 		 * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17164 		 * REPLACE VIEW to replace the rule with something with minimal
17165 		 * dependencies.
17166 		 */
17167 		PQExpBuffer result;
17168 
17169 		appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17170 						  fmtQualifiedDumpable(tbinfo));
17171 		result = createDummyViewAsClause(fout, tbinfo);
17172 		appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17173 		destroyPQExpBuffer(result);
17174 	}
17175 	else
17176 	{
17177 		appendPQExpBuffer(delcmd, "DROP RULE %s ",
17178 						  fmtId(rinfo->dobj.name));
17179 		appendPQExpBuffer(delcmd, "ON %s;\n",
17180 						  fmtQualifiedDumpable(tbinfo));
17181 	}
17182 
17183 	appendPQExpBuffer(ruleprefix, "RULE %s ON",
17184 					  fmtId(rinfo->dobj.name));
17185 
17186 	tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17187 
17188 	if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17189 		ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17190 					 tag,
17191 					 tbinfo->dobj.namespace->dobj.name,
17192 					 NULL,
17193 					 tbinfo->rolname, false,
17194 					 "RULE", SECTION_POST_DATA,
17195 					 cmd->data, delcmd->data, NULL,
17196 					 NULL, 0,
17197 					 NULL, NULL);
17198 
17199 	/* Dump rule comments */
17200 	if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17201 		dumpComment(fout, ruleprefix->data, qtabname,
17202 					tbinfo->dobj.namespace->dobj.name,
17203 					tbinfo->rolname,
17204 					rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17205 
17206 	free(tag);
17207 	destroyPQExpBuffer(query);
17208 	destroyPQExpBuffer(cmd);
17209 	destroyPQExpBuffer(delcmd);
17210 	destroyPQExpBuffer(ruleprefix);
17211 	free(qtabname);
17212 }
17213 
17214 /*
17215  * getExtensionMembership --- obtain extension membership data
17216  *
17217  * We need to identify objects that are extension members as soon as they're
17218  * loaded, so that we can correctly determine whether they need to be dumped.
17219  * Generally speaking, extension member objects will get marked as *not* to
17220  * be dumped, as they will be recreated by the single CREATE EXTENSION
17221  * command.  However, in binary upgrade mode we still need to dump the members
17222  * individually.
17223  */
17224 void
getExtensionMembership(Archive * fout,ExtensionInfo extinfo[],int numExtensions)17225 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17226 					   int numExtensions)
17227 {
17228 	PQExpBuffer query;
17229 	PGresult   *res;
17230 	int			ntups,
17231 				nextmembers,
17232 				i;
17233 	int			i_classid,
17234 				i_objid,
17235 				i_refobjid;
17236 	ExtensionMemberId *extmembers;
17237 	ExtensionInfo *ext;
17238 
17239 	/* Nothing to do if no extensions */
17240 	if (numExtensions == 0)
17241 		return;
17242 
17243 	query = createPQExpBuffer();
17244 
17245 	/* refclassid constraint is redundant but may speed the search */
17246 	appendPQExpBufferStr(query, "SELECT "
17247 						 "classid, objid, refobjid "
17248 						 "FROM pg_depend "
17249 						 "WHERE refclassid = 'pg_extension'::regclass "
17250 						 "AND deptype = 'e' "
17251 						 "ORDER BY 3");
17252 
17253 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17254 
17255 	ntups = PQntuples(res);
17256 
17257 	i_classid = PQfnumber(res, "classid");
17258 	i_objid = PQfnumber(res, "objid");
17259 	i_refobjid = PQfnumber(res, "refobjid");
17260 
17261 	extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17262 	nextmembers = 0;
17263 
17264 	/*
17265 	 * Accumulate data into extmembers[].
17266 	 *
17267 	 * Since we ordered the SELECT by referenced ID, we can expect that
17268 	 * multiple entries for the same extension will appear together; this
17269 	 * saves on searches.
17270 	 */
17271 	ext = NULL;
17272 
17273 	for (i = 0; i < ntups; i++)
17274 	{
17275 		CatalogId	objId;
17276 		Oid			extId;
17277 
17278 		objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17279 		objId.oid = atooid(PQgetvalue(res, i, i_objid));
17280 		extId = atooid(PQgetvalue(res, i, i_refobjid));
17281 
17282 		if (ext == NULL ||
17283 			ext->dobj.catId.oid != extId)
17284 			ext = findExtensionByOid(extId);
17285 
17286 		if (ext == NULL)
17287 		{
17288 			/* shouldn't happen */
17289 			fprintf(stderr, "could not find referenced extension %u\n", extId);
17290 			continue;
17291 		}
17292 
17293 		extmembers[nextmembers].catId = objId;
17294 		extmembers[nextmembers].ext = ext;
17295 		nextmembers++;
17296 	}
17297 
17298 	PQclear(res);
17299 
17300 	/* Remember the data for use later */
17301 	setExtensionMembership(extmembers, nextmembers);
17302 
17303 	destroyPQExpBuffer(query);
17304 }
17305 
17306 /*
17307  * processExtensionTables --- deal with extension configuration tables
17308  *
17309  * There are two parts to this process:
17310  *
17311  * 1. Identify and create dump records for extension configuration tables.
17312  *
17313  *	  Extensions can mark tables as "configuration", which means that the user
17314  *	  is able and expected to modify those tables after the extension has been
17315  *	  loaded.  For these tables, we dump out only the data- the structure is
17316  *	  expected to be handled at CREATE EXTENSION time, including any indexes or
17317  *	  foreign keys, which brings us to-
17318  *
17319  * 2. Record FK dependencies between configuration tables.
17320  *
17321  *	  Due to the FKs being created at CREATE EXTENSION time and therefore before
17322  *	  the data is loaded, we have to work out what the best order for reloading
17323  *	  the data is, to avoid FK violations when the tables are restored.  This is
17324  *	  not perfect- we can't handle circular dependencies and if any exist they
17325  *	  will cause an invalid dump to be produced (though at least all of the data
17326  *	  is included for a user to manually restore).  This is currently documented
17327  *	  but perhaps we can provide a better solution in the future.
17328  */
17329 void
processExtensionTables(Archive * fout,ExtensionInfo extinfo[],int numExtensions)17330 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17331 					   int numExtensions)
17332 {
17333 	DumpOptions *dopt = fout->dopt;
17334 	PQExpBuffer query;
17335 	PGresult   *res;
17336 	int			ntups,
17337 				i;
17338 	int			i_conrelid,
17339 				i_confrelid;
17340 
17341 	/* Nothing to do if no extensions */
17342 	if (numExtensions == 0)
17343 		return;
17344 
17345 	/*
17346 	 * Identify extension configuration tables and create TableDataInfo
17347 	 * objects for them, ensuring their data will be dumped even though the
17348 	 * tables themselves won't be.
17349 	 *
17350 	 * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17351 	 * user data in a configuration table is treated like schema data. This
17352 	 * seems appropriate since system data in a config table would get
17353 	 * reloaded by CREATE EXTENSION.
17354 	 */
17355 	for (i = 0; i < numExtensions; i++)
17356 	{
17357 		ExtensionInfo *curext = &(extinfo[i]);
17358 		char	   *extconfig = curext->extconfig;
17359 		char	   *extcondition = curext->extcondition;
17360 		char	  **extconfigarray = NULL;
17361 		char	  **extconditionarray = NULL;
17362 		int			nconfigitems;
17363 		int			nconditionitems;
17364 
17365 		if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17366 		  parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17367 			nconfigitems == nconditionitems)
17368 		{
17369 			int			j;
17370 
17371 			for (j = 0; j < nconfigitems; j++)
17372 			{
17373 				TableInfo  *configtbl;
17374 				Oid			configtbloid = atooid(extconfigarray[j]);
17375 				bool		dumpobj =
17376 				curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17377 
17378 				configtbl = findTableByOid(configtbloid);
17379 				if (configtbl == NULL)
17380 					continue;
17381 
17382 				/*
17383 				 * Tables of not-to-be-dumped extensions shouldn't be dumped
17384 				 * unless the table or its schema is explicitly included
17385 				 */
17386 				if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17387 				{
17388 					/* check table explicitly requested */
17389 					if (table_include_oids.head != NULL &&
17390 						simple_oid_list_member(&table_include_oids,
17391 											   configtbloid))
17392 						dumpobj = true;
17393 
17394 					/* check table's schema explicitly requested */
17395 					if (configtbl->dobj.namespace->dobj.dump &
17396 						DUMP_COMPONENT_DATA)
17397 						dumpobj = true;
17398 				}
17399 
17400 				/* check table excluded by an exclusion switch */
17401 				if (table_exclude_oids.head != NULL &&
17402 					simple_oid_list_member(&table_exclude_oids,
17403 										   configtbloid))
17404 					dumpobj = false;
17405 
17406 				/* check schema excluded by an exclusion switch */
17407 				if (simple_oid_list_member(&schema_exclude_oids,
17408 								  configtbl->dobj.namespace->dobj.catId.oid))
17409 					dumpobj = false;
17410 
17411 				if (dumpobj)
17412 				{
17413 					/*
17414 					 * Note: config tables are dumped without OIDs regardless
17415 					 * of the --oids setting.  This is because row filtering
17416 					 * conditions aren't compatible with dumping OIDs.
17417 					 */
17418 					makeTableDataInfo(dopt, configtbl, false);
17419 					if (configtbl->dataObj != NULL)
17420 					{
17421 						if (strlen(extconditionarray[j]) > 0)
17422 							configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17423 					}
17424 				}
17425 			}
17426 		}
17427 		if (extconfigarray)
17428 			free(extconfigarray);
17429 		if (extconditionarray)
17430 			free(extconditionarray);
17431 	}
17432 
17433 	/*
17434 	 * Now that all the TableInfoData objects have been created for all the
17435 	 * extensions, check their FK dependencies and register them to try and
17436 	 * dump the data out in an order that they can be restored in.
17437 	 *
17438 	 * Note that this is not a problem for user tables as their FKs are
17439 	 * recreated after the data has been loaded.
17440 	 */
17441 
17442 	query = createPQExpBuffer();
17443 
17444 	printfPQExpBuffer(query,
17445 					  "SELECT conrelid, confrelid "
17446 					  "FROM pg_constraint "
17447 					  "JOIN pg_depend ON (objid = confrelid) "
17448 					  "WHERE contype = 'f' "
17449 					  "AND refclassid = 'pg_extension'::regclass "
17450 					  "AND classid = 'pg_class'::regclass;");
17451 
17452 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17453 	ntups = PQntuples(res);
17454 
17455 	i_conrelid = PQfnumber(res, "conrelid");
17456 	i_confrelid = PQfnumber(res, "confrelid");
17457 
17458 	/* Now get the dependencies and register them */
17459 	for (i = 0; i < ntups; i++)
17460 	{
17461 		Oid			conrelid,
17462 					confrelid;
17463 		TableInfo  *reftable,
17464 				   *contable;
17465 
17466 		conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17467 		confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17468 		contable = findTableByOid(conrelid);
17469 		reftable = findTableByOid(confrelid);
17470 
17471 		if (reftable == NULL ||
17472 			reftable->dataObj == NULL ||
17473 			contable == NULL ||
17474 			contable->dataObj == NULL)
17475 			continue;
17476 
17477 		/*
17478 		 * Make referencing TABLE_DATA object depend on the referenced table's
17479 		 * TABLE_DATA object.
17480 		 */
17481 		addObjectDependency(&contable->dataObj->dobj,
17482 							reftable->dataObj->dobj.dumpId);
17483 	}
17484 	PQclear(res);
17485 	destroyPQExpBuffer(query);
17486 }
17487 
17488 /*
17489  * getDependencies --- obtain available dependency data
17490  */
17491 static void
getDependencies(Archive * fout)17492 getDependencies(Archive *fout)
17493 {
17494 	PQExpBuffer query;
17495 	PGresult   *res;
17496 	int			ntups,
17497 				i;
17498 	int			i_classid,
17499 				i_objid,
17500 				i_refclassid,
17501 				i_refobjid,
17502 				i_deptype;
17503 	DumpableObject *dobj,
17504 			   *refdobj;
17505 
17506 	/* No dependency info available before 7.3 */
17507 	if (fout->remoteVersion < 70300)
17508 		return;
17509 
17510 	if (g_verbose)
17511 		write_msg(NULL, "reading dependency data\n");
17512 
17513 	query = createPQExpBuffer();
17514 
17515 	/*
17516 	 * Messy query to collect the dependency data we need.  Note that we
17517 	 * ignore the sub-object column, so that dependencies of or on a column
17518 	 * look the same as dependencies of or on a whole table.
17519 	 *
17520 	 * PIN dependencies aren't interesting, and EXTENSION dependencies were
17521 	 * already processed by getExtensionMembership.
17522 	 */
17523 	appendPQExpBufferStr(query, "SELECT "
17524 						 "classid, objid, refclassid, refobjid, deptype "
17525 						 "FROM pg_depend "
17526 						 "WHERE deptype != 'p' AND deptype != 'e'\n");
17527 
17528 	/*
17529 	 * Since we don't treat pg_amop entries as separate DumpableObjects, we
17530 	 * have to translate their dependencies into dependencies of their parent
17531 	 * opfamily.  Ignore internal dependencies though, as those will point to
17532 	 * their parent opclass, which we needn't consider here (and if we did,
17533 	 * it'd just result in circular dependencies).  Also, "loose" opfamily
17534 	 * entries will have dependencies on their parent opfamily, which we
17535 	 * should drop since they'd likewise become useless self-dependencies.
17536 	 * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
17537 	 *
17538 	 * Skip this for pre-8.3 source servers: pg_opfamily doesn't exist there,
17539 	 * and the (known) cases where it would matter to have these dependencies
17540 	 * can't arise anyway.
17541 	 */
17542 	if (fout->remoteVersion >= 80300)
17543 	{
17544 		appendPQExpBufferStr(query, "UNION ALL\n"
17545 							 "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
17546 							 "FROM pg_depend d, pg_amop o "
17547 							 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
17548 							 "classid = 'pg_amop'::regclass AND objid = o.oid "
17549 							 "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
17550 
17551 		/* Likewise for pg_amproc entries */
17552 		appendPQExpBufferStr(query, "UNION ALL\n"
17553 							 "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
17554 							 "FROM pg_depend d, pg_amproc p "
17555 							 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
17556 							 "classid = 'pg_amproc'::regclass AND objid = p.oid "
17557 							 "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
17558 	}
17559 
17560 	/* Sort the output for efficiency below */
17561 	appendPQExpBufferStr(query, "ORDER BY 1,2");
17562 
17563 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17564 
17565 	ntups = PQntuples(res);
17566 
17567 	i_classid = PQfnumber(res, "classid");
17568 	i_objid = PQfnumber(res, "objid");
17569 	i_refclassid = PQfnumber(res, "refclassid");
17570 	i_refobjid = PQfnumber(res, "refobjid");
17571 	i_deptype = PQfnumber(res, "deptype");
17572 
17573 	/*
17574 	 * Since we ordered the SELECT by referencing ID, we can expect that
17575 	 * multiple entries for the same object will appear together; this saves
17576 	 * on searches.
17577 	 */
17578 	dobj = NULL;
17579 
17580 	for (i = 0; i < ntups; i++)
17581 	{
17582 		CatalogId	objId;
17583 		CatalogId	refobjId;
17584 		char		deptype;
17585 
17586 		objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17587 		objId.oid = atooid(PQgetvalue(res, i, i_objid));
17588 		refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17589 		refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17590 		deptype = *(PQgetvalue(res, i, i_deptype));
17591 
17592 		if (dobj == NULL ||
17593 			dobj->catId.tableoid != objId.tableoid ||
17594 			dobj->catId.oid != objId.oid)
17595 			dobj = findObjectByCatalogId(objId);
17596 
17597 		/*
17598 		 * Failure to find objects mentioned in pg_depend is not unexpected,
17599 		 * since for example we don't collect info about TOAST tables.
17600 		 */
17601 		if (dobj == NULL)
17602 		{
17603 #ifdef NOT_USED
17604 			fprintf(stderr, "no referencing object %u %u\n",
17605 					objId.tableoid, objId.oid);
17606 #endif
17607 			continue;
17608 		}
17609 
17610 		refdobj = findObjectByCatalogId(refobjId);
17611 
17612 		if (refdobj == NULL)
17613 		{
17614 #ifdef NOT_USED
17615 			fprintf(stderr, "no referenced object %u %u\n",
17616 					refobjId.tableoid, refobjId.oid);
17617 #endif
17618 			continue;
17619 		}
17620 
17621 		/*
17622 		 * For 'x' dependencies, mark the object for later; we still add the
17623 		 * normal dependency, for possible ordering purposes.  Currently
17624 		 * pg_dump_sort.c knows to put extensions ahead of all object types
17625 		 * that could possibly depend on them, but this is safer.
17626 		 */
17627 		if (deptype == 'x')
17628 			dobj->depends_on_ext = true;
17629 
17630 		/*
17631 		 * Ordinarily, table rowtypes have implicit dependencies on their
17632 		 * tables.  However, for a composite type the implicit dependency goes
17633 		 * the other way in pg_depend; which is the right thing for DROP but
17634 		 * it doesn't produce the dependency ordering we need. So in that one
17635 		 * case, we reverse the direction of the dependency.
17636 		 */
17637 		if (deptype == 'i' &&
17638 			dobj->objType == DO_TABLE &&
17639 			refdobj->objType == DO_TYPE)
17640 			addObjectDependency(refdobj, dobj->dumpId);
17641 		else
17642 			/* normal case */
17643 			addObjectDependency(dobj, refdobj->dumpId);
17644 	}
17645 
17646 	PQclear(res);
17647 
17648 	destroyPQExpBuffer(query);
17649 }
17650 
17651 
17652 /*
17653  * createBoundaryObjects - create dummy DumpableObjects to represent
17654  * dump section boundaries.
17655  */
17656 static DumpableObject *
createBoundaryObjects(void)17657 createBoundaryObjects(void)
17658 {
17659 	DumpableObject *dobjs;
17660 
17661 	dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
17662 
17663 	dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
17664 	dobjs[0].catId = nilCatalogId;
17665 	AssignDumpId(dobjs + 0);
17666 	dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
17667 
17668 	dobjs[1].objType = DO_POST_DATA_BOUNDARY;
17669 	dobjs[1].catId = nilCatalogId;
17670 	AssignDumpId(dobjs + 1);
17671 	dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
17672 
17673 	return dobjs;
17674 }
17675 
17676 /*
17677  * addBoundaryDependencies - add dependencies as needed to enforce the dump
17678  * section boundaries.
17679  */
17680 static void
addBoundaryDependencies(DumpableObject ** dobjs,int numObjs,DumpableObject * boundaryObjs)17681 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
17682 						DumpableObject *boundaryObjs)
17683 {
17684 	DumpableObject *preDataBound = boundaryObjs + 0;
17685 	DumpableObject *postDataBound = boundaryObjs + 1;
17686 	int			i;
17687 
17688 	for (i = 0; i < numObjs; i++)
17689 	{
17690 		DumpableObject *dobj = dobjs[i];
17691 
17692 		/*
17693 		 * The classification of object types here must match the SECTION_xxx
17694 		 * values assigned during subsequent ArchiveEntry calls!
17695 		 */
17696 		switch (dobj->objType)
17697 		{
17698 			case DO_NAMESPACE:
17699 			case DO_EXTENSION:
17700 			case DO_TYPE:
17701 			case DO_SHELL_TYPE:
17702 			case DO_FUNC:
17703 			case DO_AGG:
17704 			case DO_OPERATOR:
17705 			case DO_ACCESS_METHOD:
17706 			case DO_OPCLASS:
17707 			case DO_OPFAMILY:
17708 			case DO_COLLATION:
17709 			case DO_CONVERSION:
17710 			case DO_TABLE:
17711 			case DO_ATTRDEF:
17712 			case DO_PROCLANG:
17713 			case DO_CAST:
17714 			case DO_DUMMY_TYPE:
17715 			case DO_TSPARSER:
17716 			case DO_TSDICT:
17717 			case DO_TSTEMPLATE:
17718 			case DO_TSCONFIG:
17719 			case DO_FDW:
17720 			case DO_FOREIGN_SERVER:
17721 			case DO_TRANSFORM:
17722 			case DO_BLOB:
17723 				/* Pre-data objects: must come before the pre-data boundary */
17724 				addObjectDependency(preDataBound, dobj->dumpId);
17725 				break;
17726 			case DO_TABLE_DATA:
17727 			case DO_BLOB_DATA:
17728 				/* Data objects: must come between the boundaries */
17729 				addObjectDependency(dobj, preDataBound->dumpId);
17730 				addObjectDependency(postDataBound, dobj->dumpId);
17731 				break;
17732 			case DO_INDEX:
17733 			case DO_REFRESH_MATVIEW:
17734 			case DO_TRIGGER:
17735 			case DO_EVENT_TRIGGER:
17736 			case DO_DEFAULT_ACL:
17737 			case DO_POLICY:
17738 				/* Post-data objects: must come after the post-data boundary */
17739 				addObjectDependency(dobj, postDataBound->dumpId);
17740 				break;
17741 			case DO_RULE:
17742 				/* Rules are post-data, but only if dumped separately */
17743 				if (((RuleInfo *) dobj)->separate)
17744 					addObjectDependency(dobj, postDataBound->dumpId);
17745 				break;
17746 			case DO_CONSTRAINT:
17747 			case DO_FK_CONSTRAINT:
17748 				/* Constraints are post-data, but only if dumped separately */
17749 				if (((ConstraintInfo *) dobj)->separate)
17750 					addObjectDependency(dobj, postDataBound->dumpId);
17751 				break;
17752 			case DO_PRE_DATA_BOUNDARY:
17753 				/* nothing to do */
17754 				break;
17755 			case DO_POST_DATA_BOUNDARY:
17756 				/* must come after the pre-data boundary */
17757 				addObjectDependency(dobj, preDataBound->dumpId);
17758 				break;
17759 		}
17760 	}
17761 }
17762 
17763 
17764 /*
17765  * BuildArchiveDependencies - create dependency data for archive TOC entries
17766  *
17767  * The raw dependency data obtained by getDependencies() is not terribly
17768  * useful in an archive dump, because in many cases there are dependency
17769  * chains linking through objects that don't appear explicitly in the dump.
17770  * For example, a view will depend on its _RETURN rule while the _RETURN rule
17771  * will depend on other objects --- but the rule will not appear as a separate
17772  * object in the dump.  We need to adjust the view's dependencies to include
17773  * whatever the rule depends on that is included in the dump.
17774  *
17775  * Just to make things more complicated, there are also "special" dependencies
17776  * such as the dependency of a TABLE DATA item on its TABLE, which we must
17777  * not rearrange because pg_restore knows that TABLE DATA only depends on
17778  * its table.  In these cases we must leave the dependencies strictly as-is
17779  * even if they refer to not-to-be-dumped objects.
17780  *
17781  * To handle this, the convention is that "special" dependencies are created
17782  * during ArchiveEntry calls, and an archive TOC item that has any such
17783  * entries will not be touched here.  Otherwise, we recursively search the
17784  * DumpableObject data structures to build the correct dependencies for each
17785  * archive TOC item.
17786  */
17787 static void
BuildArchiveDependencies(Archive * fout)17788 BuildArchiveDependencies(Archive *fout)
17789 {
17790 	ArchiveHandle *AH = (ArchiveHandle *) fout;
17791 	TocEntry   *te;
17792 
17793 	/* Scan all TOC entries in the archive */
17794 	for (te = AH->toc->next; te != AH->toc; te = te->next)
17795 	{
17796 		DumpableObject *dobj;
17797 		DumpId	   *dependencies;
17798 		int			nDeps;
17799 		int			allocDeps;
17800 
17801 		/* No need to process entries that will not be dumped */
17802 		if (te->reqs == 0)
17803 			continue;
17804 		/* Ignore entries that already have "special" dependencies */
17805 		if (te->nDeps > 0)
17806 			continue;
17807 		/* Otherwise, look up the item's original DumpableObject, if any */
17808 		dobj = findObjectByDumpId(te->dumpId);
17809 		if (dobj == NULL)
17810 			continue;
17811 		/* No work if it has no dependencies */
17812 		if (dobj->nDeps <= 0)
17813 			continue;
17814 		/* Set up work array */
17815 		allocDeps = 64;
17816 		dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
17817 		nDeps = 0;
17818 		/* Recursively find all dumpable dependencies */
17819 		findDumpableDependencies(AH, dobj,
17820 								 &dependencies, &nDeps, &allocDeps);
17821 		/* And save 'em ... */
17822 		if (nDeps > 0)
17823 		{
17824 			dependencies = (DumpId *) pg_realloc(dependencies,
17825 												 nDeps * sizeof(DumpId));
17826 			te->dependencies = dependencies;
17827 			te->nDeps = nDeps;
17828 		}
17829 		else
17830 			free(dependencies);
17831 	}
17832 }
17833 
17834 /* Recursive search subroutine for BuildArchiveDependencies */
17835 static void
findDumpableDependencies(ArchiveHandle * AH,DumpableObject * dobj,DumpId ** dependencies,int * nDeps,int * allocDeps)17836 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
17837 						 DumpId **dependencies, int *nDeps, int *allocDeps)
17838 {
17839 	int			i;
17840 
17841 	/*
17842 	 * Ignore section boundary objects: if we search through them, we'll
17843 	 * report lots of bogus dependencies.
17844 	 */
17845 	if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
17846 		dobj->objType == DO_POST_DATA_BOUNDARY)
17847 		return;
17848 
17849 	for (i = 0; i < dobj->nDeps; i++)
17850 	{
17851 		DumpId		depid = dobj->dependencies[i];
17852 
17853 		if (TocIDRequired(AH, depid) != 0)
17854 		{
17855 			/* Object will be dumped, so just reference it as a dependency */
17856 			if (*nDeps >= *allocDeps)
17857 			{
17858 				*allocDeps *= 2;
17859 				*dependencies = (DumpId *) pg_realloc(*dependencies,
17860 												*allocDeps * sizeof(DumpId));
17861 			}
17862 			(*dependencies)[*nDeps] = depid;
17863 			(*nDeps)++;
17864 		}
17865 		else
17866 		{
17867 			/*
17868 			 * Object will not be dumped, so recursively consider its deps. We
17869 			 * rely on the assumption that sortDumpableObjects already broke
17870 			 * any dependency loops, else we might recurse infinitely.
17871 			 */
17872 			DumpableObject *otherdobj = findObjectByDumpId(depid);
17873 
17874 			if (otherdobj)
17875 				findDumpableDependencies(AH, otherdobj,
17876 										 dependencies, nDeps, allocDeps);
17877 		}
17878 	}
17879 }
17880 
17881 
17882 /*
17883  * getFormattedTypeName - retrieve a nicely-formatted type name for the
17884  * given type OID.
17885  *
17886  * This does not guarantee to schema-qualify the output, so it should not
17887  * be used to create the target object name for CREATE or ALTER commands.
17888  *
17889  * Note that the result is cached and must not be freed by the caller.
17890  */
17891 static const char *
getFormattedTypeName(Archive * fout,Oid oid,OidOptions opts)17892 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
17893 {
17894 	TypeInfo   *typeInfo;
17895 	char	   *result;
17896 	PQExpBuffer query;
17897 	PGresult   *res;
17898 
17899 	if (oid == 0)
17900 	{
17901 		if ((opts & zeroAsOpaque) != 0)
17902 			return g_opaque_type;
17903 		else if ((opts & zeroAsAny) != 0)
17904 			return "'any'";
17905 		else if ((opts & zeroAsStar) != 0)
17906 			return "*";
17907 		else if ((opts & zeroAsNone) != 0)
17908 			return "NONE";
17909 	}
17910 
17911 	/* see if we have the result cached in the type's TypeInfo record */
17912 	typeInfo = findTypeByOid(oid);
17913 	if (typeInfo && typeInfo->ftypname)
17914 		return typeInfo->ftypname;
17915 
17916 	query = createPQExpBuffer();
17917 	if (fout->remoteVersion >= 70300)
17918 	{
17919 		appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
17920 						  oid);
17921 	}
17922 	else if (fout->remoteVersion >= 70100)
17923 	{
17924 		appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
17925 						  oid);
17926 	}
17927 	else
17928 	{
17929 		appendPQExpBuffer(query, "SELECT typname "
17930 						  "FROM pg_type "
17931 						  "WHERE oid = '%u'::oid",
17932 						  oid);
17933 	}
17934 
17935 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
17936 
17937 	if (fout->remoteVersion >= 70100)
17938 	{
17939 		/* already quoted */
17940 		result = pg_strdup(PQgetvalue(res, 0, 0));
17941 	}
17942 	else
17943 	{
17944 		/* may need to quote it */
17945 		result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
17946 	}
17947 
17948 	PQclear(res);
17949 	destroyPQExpBuffer(query);
17950 
17951 	/*
17952 	 * Cache the result for re-use in later requests, if possible.  If we
17953 	 * don't have a TypeInfo for the type, the string will be leaked once the
17954 	 * caller is done with it ... but that case really should not happen, so
17955 	 * leaking if it does seems acceptable.
17956 	 */
17957 	if (typeInfo)
17958 		typeInfo->ftypname = result;
17959 
17960 	return result;
17961 }
17962 
17963 /*
17964  * myFormatType --- local implementation of format_type for use with 7.0.
17965  */
17966 static char *
myFormatType(const char * typname,int32 typmod)17967 myFormatType(const char *typname, int32 typmod)
17968 {
17969 	char	   *result;
17970 	bool		isarray = false;
17971 	PQExpBuffer buf = createPQExpBuffer();
17972 
17973 	/* Handle array types */
17974 	if (typname[0] == '_')
17975 	{
17976 		isarray = true;
17977 		typname++;
17978 	}
17979 
17980 	/* Show lengths on bpchar and varchar */
17981 	if (strcmp(typname, "bpchar") == 0)
17982 	{
17983 		int			len = (typmod - VARHDRSZ);
17984 
17985 		appendPQExpBufferStr(buf, "character");
17986 		if (len > 1)
17987 			appendPQExpBuffer(buf, "(%d)",
17988 							  typmod - VARHDRSZ);
17989 	}
17990 	else if (strcmp(typname, "varchar") == 0)
17991 	{
17992 		appendPQExpBufferStr(buf, "character varying");
17993 		if (typmod != -1)
17994 			appendPQExpBuffer(buf, "(%d)",
17995 							  typmod - VARHDRSZ);
17996 	}
17997 	else if (strcmp(typname, "numeric") == 0)
17998 	{
17999 		appendPQExpBufferStr(buf, "numeric");
18000 		if (typmod != -1)
18001 		{
18002 			int32		tmp_typmod;
18003 			int			precision;
18004 			int			scale;
18005 
18006 			tmp_typmod = typmod - VARHDRSZ;
18007 			precision = (tmp_typmod >> 16) & 0xffff;
18008 			scale = tmp_typmod & 0xffff;
18009 			appendPQExpBuffer(buf, "(%d,%d)",
18010 							  precision, scale);
18011 		}
18012 	}
18013 
18014 	/*
18015 	 * char is an internal single-byte data type; Let's make sure we force it
18016 	 * through with quotes. - thomas 1998-12-13
18017 	 */
18018 	else if (strcmp(typname, "char") == 0)
18019 		appendPQExpBufferStr(buf, "\"char\"");
18020 	else
18021 		appendPQExpBufferStr(buf, fmtId(typname));
18022 
18023 	/* Append array qualifier for array types */
18024 	if (isarray)
18025 		appendPQExpBufferStr(buf, "[]");
18026 
18027 	result = pg_strdup(buf->data);
18028 	destroyPQExpBuffer(buf);
18029 
18030 	return result;
18031 }
18032 
18033 /*
18034  * Return a column list clause for the given relation.
18035  *
18036  * Special case: if there are no undropped columns in the relation, return
18037  * "", not an invalid "()" column list.
18038  */
18039 static const char *
fmtCopyColumnList(const TableInfo * ti,PQExpBuffer buffer)18040 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18041 {
18042 	int			numatts = ti->numatts;
18043 	char	  **attnames = ti->attnames;
18044 	bool	   *attisdropped = ti->attisdropped;
18045 	bool		needComma;
18046 	int			i;
18047 
18048 	appendPQExpBufferChar(buffer, '(');
18049 	needComma = false;
18050 	for (i = 0; i < numatts; i++)
18051 	{
18052 		if (attisdropped[i])
18053 			continue;
18054 		if (needComma)
18055 			appendPQExpBufferStr(buffer, ", ");
18056 		appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18057 		needComma = true;
18058 	}
18059 
18060 	if (!needComma)
18061 		return "";				/* no undropped columns */
18062 
18063 	appendPQExpBufferChar(buffer, ')');
18064 	return buffer->data;
18065 }
18066 
18067 /*
18068  * Check if a reloptions array is nonempty.
18069  */
18070 static bool
nonemptyReloptions(const char * reloptions)18071 nonemptyReloptions(const char *reloptions)
18072 {
18073 	/* Don't want to print it if it's just "{}" */
18074 	return (reloptions != NULL && strlen(reloptions) > 2);
18075 }
18076 
18077 /*
18078  * Format a reloptions array and append it to the given buffer.
18079  *
18080  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18081  */
18082 static void
appendReloptionsArrayAH(PQExpBuffer buffer,const char * reloptions,const char * prefix,Archive * fout)18083 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18084 						const char *prefix, Archive *fout)
18085 {
18086 	bool		res;
18087 
18088 	res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18089 								fout->std_strings);
18090 	if (!res)
18091 		write_msg(NULL, "WARNING: could not parse reloptions array\n");
18092 }
18093